Open stakemura opened 5 years ago
Hey @stakemura, thanks for your interest!
-serialize-spirv
and -deserialize-spirv
in mlir-translate is for serializing a spv.module
of the SPIR-V dialect into its binary format and deserializing a SPIR-V binary into is spv.module
equivalent, respectively. The API entry points are here. Tests can serve as an example for how to use the command-line tool. (Please ignore the outer function wrapping around the spv.module
in those tests; they are mandated by mlir-translate infra and should be removed later. We just haven't gotten back to it.)
If you are talking about conversion between the SPIR-V dialect and other dialects, then that's still under development right now and we expect to have more on it in the coming weeks.
I guess I'm not quite clear about your use case. Could you share more about what you intend to do with the SPIR-V dialect? That will also help me to answer your questions better. :)
@antiagainst I truly appreciate your quick reply.
One of my motivations is to run compute shader based inference like Stadia’s Style Transfer ML.
Currently I'm using TVM to generate SPIR-V assembler as the following code shows.
import sys
import tvm
import tvm.relay as relay
import numpy as np
in_n, in_c, in_h, in_w = tvm.var("n"), 3, 256, 256
x = relay.var("x", relay.ty.TensorType((in_n, in_c, in_h, in_w), "float32"))
w = relay.var("w")
y = relay.nn.conv2d(x, w,
kernel_size=(3, 3),
padding=(1, 1),
channels=2)
mod = relay.Function([x, w], y)
x_data = np.random.rand(1, in_c, in_h, in_w).astype('float32')
params = {"x": tvm.nd.array(x_data)}
target = "vulkan"
with relay.build_config(opt_level=3):
graph, lib, params = relay.build(mod, target, params=params)
spv = lib.imported_modules[0].get_source()
with open("conv2d.ll", mode='w') as f:
f.write(spv)
The SPIR-V assembler "conv2d.ll" is generated as follows.
; SPIR-V
; Version: 1.1
; Generator: Khronos; 0
; Bound: 330
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %15 "fused_nn_conv2d_kernel0" %gl_WorkGroupID %gl_LocalInvocationID
OpExecutionMode %15 LocalSize 32 1 2
OpDecorate %_runtimearr_float ArrayStride 4
OpMemberDecorate %_struct_10 0 Offset 0
OpDecorate %_struct_10 BufferBlock
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
OpDecorate %13 DescriptorSet 0
OpDecorate %13 Binding 1
OpDecorate %14 DescriptorSet 0
OpDecorate %14 Binding 2
OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
OpDecorate %_arr_float_uint_4 ArrayStride 4
OpMemberDecorate %_struct_26 0 Offset 0
OpDecorate %_arr_float_uint_204 ArrayStride 4
OpMemberDecorate %_struct_31 0 Offset 0
OpDecorate %_arr_float_uint_18 ArrayStride 4
OpMemberDecorate %_struct_36 0 Offset 0
OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%bool = OpTypeBool
%float = OpTypeFloat 32
%int_0 = OpConstant %int 0
%void = OpTypeVoid
%8 = OpTypeFunction %void
%_runtimearr_float = OpTypeRuntimeArray %float
%_struct_10 = OpTypeStruct %_runtimearr_float
%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
%12 = OpVariable %_ptr_Uniform__struct_10 Uniform
%13 = OpVariable %_ptr_Uniform__struct_10 Uniform
%14 = OpVariable %_ptr_Uniform__struct_10 Uniform
%v3int = OpTypeVector %int 3
%_ptr_Input_v3int = OpTypePointer Input %v3int
%gl_WorkGroupID = OpVariable %_ptr_Input_v3int Input
%_ptr_Input_int = OpTypePointer Input %int
%int_2 = OpConstant %int 2
%uint_4 = OpConstant %uint 4
%_arr_float_uint_4 = OpTypeArray %float %uint_4
%_struct_26 = OpTypeStruct %_arr_float_uint_4
%_ptr_Function__struct_26 = OpTypePointer Function %_struct_26
%uint_204 = OpConstant %uint 204
%_arr_float_uint_204 = OpTypeArray %float %uint_204
%_struct_31 = OpTypeStruct %_arr_float_uint_204
%_ptr_Workgroup__struct_31 = OpTypePointer Workgroup %_struct_31
%33 = OpVariable %_ptr_Workgroup__struct_31 Workgroup
%uint_18 = OpConstant %uint 18
%_arr_float_uint_18 = OpTypeArray %float %uint_18
%_struct_36 = OpTypeStruct %_arr_float_uint_18
%_ptr_Workgroup__struct_36 = OpTypePointer Workgroup %_struct_36
%38 = OpVariable %_ptr_Workgroup__struct_36 Workgroup
%int_1 = OpConstant %int 1
%gl_LocalInvocationID = OpVariable %_ptr_Input_v3int Input
%float_0 = OpConstant %float 0
%_ptr_Function_float = OpTypePointer Function %float
%int_3 = OpConstant %int 3
%int_272 = OpConstant %int 272
%int_4 = OpConstant %int 4
%int_6 = OpConstant %int 6
%int_34 = OpConstant %int 34
%int_204 = OpConstant %int 204
%int_102 = OpConstant %int 102
%int_257 = OpConstant %int 257
%int_32 = OpConstant %int 32
%_ptr_Uniform_float = OpTypePointer Uniform %float
%int_256 = OpConstant %int 256
%int_1024 = OpConstant %int 1024
%int_65536 = OpConstant %int 65536
%_ptr_Workgroup_float = OpTypePointer Workgroup %float
%int_9 = OpConstant %int 9
%int_18 = OpConstant %int 18
%int_27 = OpConstant %int 27
%int_68 = OpConstant %int 68
%int_512 = OpConstant %int 512
%int_768 = OpConstant %int 768
%15 = OpFunction %void None %8
%16 = OpLabel
%22 = OpAccessChain %_ptr_Input_int %gl_WorkGroupID %int_2
%23 = OpLoad %int %22
%28 = OpVariable %_ptr_Function__struct_26 Function
%40 = OpAccessChain %_ptr_Input_int %gl_WorkGroupID %int_1
%41 = OpLoad %int %40
%42 = OpAccessChain %_ptr_Input_int %gl_WorkGroupID %int_0
%43 = OpLoad %int %42
%45 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_2
%46 = OpLoad %int %45
%47 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_1
%48 = OpLoad %int %47
%49 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_0
%50 = OpLoad %int %49
%53 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_0
OpStore %53 %float_0 None
%54 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_1
OpStore %54 %float_0 None
%55 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_2
OpStore %55 %float_0 None
%57 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_3
OpStore %57 %float_0 None
OpBranch %58
%58 = OpLabel
%62 = OpPhi %int %int_0 %16 %288 %60
%63 = OpSLessThan %bool %62 %int_3
OpLoopMerge %61 %60 Unroll
OpBranchConditional %63 %59 %61 128 1
%59 = OpLabel
%64 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_2
%65 = OpLoad %int %64
%66 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_1
%67 = OpLoad %int %66
%68 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_0
%69 = OpLoad %int %68
OpControlBarrier %int_2 %int_2 %int_272
OpBranch %72
%72 = OpLabel
%76 = OpPhi %int %int_0 %59 %168 %74
%77 = OpSLessThan %bool %76 %int_4
OpLoopMerge %75 %74 Unroll
OpBranchConditional %77 %73 %75 128 1
%73 = OpLabel
%80 = OpIMul %int %69 %int_4
%81 = OpIAdd %int %80 %76
%82 = OpSDiv %int %81 %int_34
%83 = OpIMul %int %65 %int_3
%84 = OpIAdd %int %83 %82
%85 = OpSLessThan %bool %84 %int_6
OpSelectionMerge %87 None
OpBranchConditional %85 %86 %87 128 1
%86 = OpLabel
%89 = OpIMul %int %69 %int_4
%91 = OpIMul %int %65 %int_102
%92 = OpIAdd %int %91 %89
%93 = OpIAdd %int %92 %76
%94 = OpSLessThan %bool %93 %int_204
OpSelectionMerge %96 None
OpBranchConditional %94 %95 %96 128 1
%95 = OpLabel
%97 = OpIMul %int %69 %int_4
%98 = OpIAdd %int %97 %76
%99 = OpSLessThan %bool %98 %int_102
OpSelectionMerge %101 None
OpBranchConditional %99 %100 %101 128 1
%100 = OpLabel
%102 = OpIMul %int %69 %int_4
%103 = OpIAdd %int %102 %76
%104 = OpSDiv %int %103 %int_34
%105 = OpIMul %int %65 %int_3
%106 = OpIAdd %int %105 %104
%107 = OpIMul %int %41 %int_4
%108 = OpIAdd %int %107 %106
%109 = OpSLessThanEqual %bool %int_1 %108
%111 = OpIMul %int %69 %int_4
%112 = OpIAdd %int %111 %76
%113 = OpSDiv %int %112 %int_34
%114 = OpIMul %int %65 %int_3
%115 = OpIAdd %int %114 %113
%116 = OpIMul %int %41 %int_4
%117 = OpIAdd %int %116 %115
%118 = OpSLessThan %bool %117 %int_257
%119 = OpLogicalAnd %bool %109 %118
%120 = OpIMul %int %69 %int_4
%121 = OpIAdd %int %120 %76
%122 = OpSRem %int %121 %int_34
%124 = OpIMul %int %43 %int_32
%125 = OpIAdd %int %124 %122
%126 = OpSLessThanEqual %bool %int_1 %125
%127 = OpLogicalAnd %bool %119 %126
%128 = OpIMul %int %69 %int_4
%129 = OpIAdd %int %128 %76
%130 = OpSRem %int %129 %int_34
%131 = OpIMul %int %43 %int_32
%132 = OpIAdd %int %131 %130
%133 = OpSLessThan %bool %132 %int_257
%134 = OpLogicalAnd %bool %127 %133
OpSelectionMerge %137 None
OpBranchConditional %134 %135 %136
%135 = OpLabel
%139 = OpIMul %int %69 %int_4
%140 = OpIAdd %int %139 %76
%141 = OpSRem %int %140 %int_34
%142 = OpIMul %int %43 %int_32
%144 = OpIMul %int %69 %int_4
%145 = OpIMul %int %65 %int_102
%146 = OpIAdd %int %145 %144
%147 = OpIAdd %int %146 %76
%148 = OpSDiv %int %147 %int_34
%149 = OpIMul %int %148 %int_256
%151 = OpIMul %int %41 %int_1024
%153 = OpIMul %int %62 %int_65536
%154 = OpIAdd %int %153 %151
%155 = OpIAdd %int %154 %149
%156 = OpIAdd %int %155 %142
%157 = OpIAdd %int %156 %141
%158 = OpISub %int %157 %int_257
%159 = OpInBoundsAccessChain %_ptr_Uniform_float %12 %int_0 %158
%160 = OpLoad %float %159 None
OpBranch %137
%136 = OpLabel
OpBranch %137
%137 = OpLabel
%161 = OpPhi %float %160 %135 %float_0 %136
%163 = OpIMul %int %69 %int_4
%164 = OpIMul %int %65 %int_102
%165 = OpIAdd %int %164 %163
%166 = OpIAdd %int %165 %76
%167 = OpInBoundsAccessChain %_ptr_Workgroup_float %33 %int_0 %166
OpStore %167 %161 None
OpBranch %101
%101 = OpLabel
OpBranch %96
%96 = OpLabel
OpBranch %87
%87 = OpLabel
OpBranch %74
%74 = OpLabel
%168 = OpIAdd %int %76 %int_1
OpBranch %72
%75 = OpLabel
%169 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_2
%170 = OpLoad %int %169
%171 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_1
%172 = OpLoad %int %171
%173 = OpAccessChain %_ptr_Input_int %gl_LocalInvocationID %int_0
%174 = OpLoad %int %173
%176 = OpSDiv %int %174 %int_9
%177 = OpIAdd %int %176 %170
%178 = OpSLessThan %bool %177 %int_2
OpSelectionMerge %180 None
OpBranchConditional %178 %179 %180 128 1
%179 = OpLabel
%181 = OpSDiv %int %174 %int_3
%182 = OpIMul %int %170 %int_3
%183 = OpIAdd %int %182 %181
%184 = OpSLessThan %bool %183 %int_6
OpSelectionMerge %186 None
OpBranchConditional %184 %185 %186 128 1
%185 = OpLabel
%188 = OpIMul %int %170 %int_9
%189 = OpIAdd %int %188 %174
%190 = OpSLessThan %bool %189 %int_18
OpSelectionMerge %192 None
OpBranchConditional %190 %191 %192 128 1
%191 = OpLabel
%193 = OpSLessThan %bool %174 %int_9
OpSelectionMerge %195 None
OpBranchConditional %193 %194 %195 128 1
%194 = OpLabel
%196 = OpIMul %int %62 %int_9
%198 = OpIMul %int %170 %int_27
%199 = OpIAdd %int %198 %196
%200 = OpIAdd %int %199 %174
%201 = OpInBoundsAccessChain %_ptr_Uniform_float %13 %int_0 %200
%202 = OpLoad %float %201 None
%203 = OpIMul %int %170 %int_9
%204 = OpIAdd %int %203 %174
%205 = OpInBoundsAccessChain %_ptr_Workgroup_float %38 %int_0 %204
OpStore %205 %202 None
OpBranch %195
%195 = OpLabel
OpBranch %192
%192 = OpLabel
OpBranch %186
%186 = OpLabel
OpBranch %180
%180 = OpLabel
OpControlBarrier %int_2 %int_2 %int_272
OpBranch %206
%206 = OpLabel
%210 = OpPhi %int %int_0 %180 %287 %208
%211 = OpSLessThan %bool %210 %int_3
OpLoopMerge %209 %208 Unroll
OpBranchConditional %211 %207 %209 128 1
%207 = OpLabel
OpBranch %212
%212 = OpLabel
%216 = OpPhi %int %int_0 %207 %286 %214
%217 = OpSLessThan %bool %216 %int_3
OpLoopMerge %215 %214 Unroll
OpBranchConditional %217 %213 %215 128 1
%213 = OpLabel
%218 = OpIMul %int %210 %int_3
%219 = OpIMul %int %46 %int_9
%220 = OpIAdd %int %219 %218
%221 = OpIAdd %int %220 %216
%222 = OpInBoundsAccessChain %_ptr_Workgroup_float %38 %int_0 %221
%223 = OpLoad %float %222 None
%224 = OpIMul %int %210 %int_34
%225 = OpIAdd %int %224 %50
%226 = OpIAdd %int %225 %216
%227 = OpInBoundsAccessChain %_ptr_Workgroup_float %33 %int_0 %226
%228 = OpLoad %float %227 None
%229 = OpFMul %float %228 %223
%230 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_0
%231 = OpLoad %float %230 None
%232 = OpFAdd %float %231 %229
%233 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_0
OpStore %233 %232 None
%234 = OpIMul %int %210 %int_3
%235 = OpIMul %int %46 %int_9
%236 = OpIAdd %int %235 %234
%237 = OpIAdd %int %236 %216
%238 = OpInBoundsAccessChain %_ptr_Workgroup_float %38 %int_0 %237
%239 = OpLoad %float %238 None
%240 = OpIMul %int %210 %int_34
%241 = OpIAdd %int %240 %50
%242 = OpIAdd %int %241 %216
%243 = OpIAdd %int %242 %int_34
%244 = OpInBoundsAccessChain %_ptr_Workgroup_float %33 %int_0 %243
%245 = OpLoad %float %244 None
%246 = OpFMul %float %245 %239
%247 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_1
%248 = OpLoad %float %247 None
%249 = OpFAdd %float %248 %246
%250 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_1
OpStore %250 %249 None
%251 = OpIMul %int %210 %int_3
%252 = OpIMul %int %46 %int_9
%253 = OpIAdd %int %252 %251
%254 = OpIAdd %int %253 %216
%255 = OpInBoundsAccessChain %_ptr_Workgroup_float %38 %int_0 %254
%256 = OpLoad %float %255 None
%258 = OpIMul %int %210 %int_34
%259 = OpIAdd %int %258 %50
%260 = OpIAdd %int %259 %216
%261 = OpIAdd %int %260 %int_68
%262 = OpInBoundsAccessChain %_ptr_Workgroup_float %33 %int_0 %261
%263 = OpLoad %float %262 None
%264 = OpFMul %float %263 %256
%265 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_2
%266 = OpLoad %float %265 None
%267 = OpFAdd %float %266 %264
%268 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_2
OpStore %268 %267 None
%269 = OpIMul %int %210 %int_3
%270 = OpIMul %int %46 %int_9
%271 = OpIAdd %int %270 %269
%272 = OpIAdd %int %271 %216
%273 = OpInBoundsAccessChain %_ptr_Workgroup_float %38 %int_0 %272
%274 = OpLoad %float %273 None
%275 = OpIMul %int %210 %int_34
%276 = OpIAdd %int %275 %50
%277 = OpIAdd %int %276 %216
%278 = OpIAdd %int %277 %int_102
%279 = OpInBoundsAccessChain %_ptr_Workgroup_float %33 %int_0 %278
%280 = OpLoad %float %279 None
%281 = OpFMul %float %280 %274
%282 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_3
%283 = OpLoad %float %282 None
%284 = OpFAdd %float %283 %281
%285 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_3
OpStore %285 %284 None
OpBranch %214
%214 = OpLabel
%286 = OpIAdd %int %216 %int_1
OpBranch %212
%215 = OpLabel
OpBranch %208
%208 = OpLabel
%287 = OpIAdd %int %210 %int_1
OpBranch %206
%209 = OpLabel
OpBranch %60
%60 = OpLabel
%288 = OpIAdd %int %62 %int_1
OpBranch %58
%61 = OpLabel
%289 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_0
%290 = OpLoad %float %289 None
%291 = OpIMul %int %43 %int_32
%292 = OpIMul %int %41 %int_1024
%293 = OpIMul %int %46 %int_65536
%294 = OpIAdd %int %293 %292
%295 = OpIAdd %int %294 %291
%296 = OpIAdd %int %295 %50
%297 = OpInBoundsAccessChain %_ptr_Uniform_float %14 %int_0 %296
OpStore %297 %290 None
%298 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_1
%299 = OpLoad %float %298 None
%300 = OpIMul %int %43 %int_32
%301 = OpIMul %int %41 %int_1024
%302 = OpIMul %int %46 %int_65536
%303 = OpIAdd %int %302 %301
%304 = OpIAdd %int %303 %300
%305 = OpIAdd %int %304 %50
%306 = OpIAdd %int %305 %int_256
%307 = OpInBoundsAccessChain %_ptr_Uniform_float %14 %int_0 %306
OpStore %307 %299 None
%308 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_2
%309 = OpLoad %float %308 None
%311 = OpIMul %int %43 %int_32
%312 = OpIMul %int %41 %int_1024
%313 = OpIMul %int %46 %int_65536
%314 = OpIAdd %int %313 %312
%315 = OpIAdd %int %314 %311
%316 = OpIAdd %int %315 %50
%317 = OpIAdd %int %316 %int_512
%318 = OpInBoundsAccessChain %_ptr_Uniform_float %14 %int_0 %317
OpStore %318 %309 None
%319 = OpInBoundsAccessChain %_ptr_Function_float %28 %int_0 %int_3
%320 = OpLoad %float %319 None
%322 = OpIMul %int %43 %int_32
%323 = OpIMul %int %41 %int_1024
%324 = OpIMul %int %46 %int_65536
%325 = OpIAdd %int %324 %323
%326 = OpIAdd %int %325 %322
%327 = OpIAdd %int %326 %50
%328 = OpIAdd %int %327 %int_768
%329 = OpInBoundsAccessChain %_ptr_Uniform_float %14 %int_0 %328
OpStore %329 %320 None
OpReturn
OpFunctionEnd
I intended to generate SPIR-V assembler with MLIR like TVM. Finally I want to generate the inference shaders for Vulkan, Metal and Direct3D 12 with MLIR and SPIRV-Cross. Thanks.
Hey @stakemura, thanks for the explanation; it's exciting to see this coming! :)
We are actively working on the SPIR-V dialect in MLIR and its conversion right now. The end goal is to take in computation graph expressed in TensorFlow (as TF dialect in MLIR) and lower it progressively to SPIR-V and run on Vulkan. So eventually we hope you can just write the style transfer or whatever other inference logic in high-level TensorFlow code. Right now we are still not quite there yet. The whole conversion flow is still under development. For the SPIR-V dialect itself, we haven't gotten to control flow constructs (which is the next step). So there are still functionalities missing to support the above use case. (If you can help us to make it happen that would be truly awesome!) If you are trying to utilize the SPIR-V dialect directly "as a SPIR-V builder", it can be a bit verbose. You will need to write C++ code to construct the IR manually; the deserializer can act as an example of how to call the APIs. Pay particular attention to those opBuilder.create<...>
calls. Let me know if you have other questions and I'm happy to help.
@antiagainst Are you directly active in the Kronos ML technical subgroup? https://www.phoronix.com/scan.php?page=news_item&px=SIGGRAPH-2019-Vulkan-ML
Hey @bhack, I started to participate in the TSG discussion.
Anything public?
Hey @bhack, thanks for the interest! But I don't think I'm in the position to speak publicly for the whole Vulkan ML TSG. You may watch the Khronos Group's official channels for updates. :)
Would C++/Rust with additional intrinsics be able to lower to MLIR and by extension spirv? What would need to be done to get this to work?
Hi @jon-chuang, please note that right now MLIR is part of LLVM monorepo so issues no this repo is not maintained anymore.
Your question here is quite vague. What C++/Rust features are you interested? What additional intrinsics? Which SPIR-V target environment (Vulkan/OpenCL/OpenGL/etc.) you are considering? We might be able to convert some depending on the particular answers to the above questions; still I'd assume they typically incur a significant amount of work.
Would you like to give me any information how to convert from MLIR to SPIR-V? I tried to use mlir-translate with serialize-spirv option, but I couldn't realize how to use this option.