1 /**************************************************************************
3 * Copyright 2010 Luca Barbieri
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 **************************************************************************/
31 #define check(x) assert(x)
32 #define fail(x) assert(0 && (x))
34 #define check(x) do {if(!(x)) throw(#x);} while(0)
35 #define fail(x) throw(x)
44 sm4_parser(sm4_program
& program
, void* p_tokens
, unsigned size
)
47 tokens
= (unsigned*)p_tokens
;
48 tokens_end
= (unsigned*)((char*)p_tokens
+ size
);
51 /* TODO: byteswap if machine is big endian */
54 check(tokens
< tokens_end
);
55 return bswap_le32(*tokens
++);
59 void read_token(T
* tok
)
61 *(unsigned*)tok
= read32();
66 unsigned a
= read32();
67 unsigned b
= read32();
68 return (uint64_t)a
| ((uint64_t)b
<< 32);
71 void skip(unsigned toskip
)
76 void read_op(sm4_op
* pop
)
79 sm4_token_operand optok
;
81 assert(optok
.file
< SM4_FILE_COUNT
);
87 switch(optok
.comps_enum
)
89 case SM4_OPERAND_COMPNUM_0
:
92 case SM4_OPERAND_COMPNUM_1
:
94 op
.swizzle
[1] = op
.swizzle
[2] = op
.swizzle
[3] = 0;
96 case SM4_OPERAND_COMPNUM_4
:
101 case SM4_OPERAND_MODE_MASK
:
102 op
.mask
= SM4_OPERAND_SEL_MASK(optok
.sel
);
104 case SM4_OPERAND_MODE_SWIZZLE
:
105 op
.swizzle
[0] = SM4_OPERAND_SEL_SWZ(optok
.sel
, 0);
106 op
.swizzle
[1] = SM4_OPERAND_SEL_SWZ(optok
.sel
, 1);
107 op
.swizzle
[2] = SM4_OPERAND_SEL_SWZ(optok
.sel
, 2);
108 op
.swizzle
[3] = SM4_OPERAND_SEL_SWZ(optok
.sel
, 3);
110 case SM4_OPERAND_MODE_SCALAR
:
111 op
.swizzle
[0] = op
.swizzle
[1] = op
.swizzle
[2] = op
.swizzle
[3] = SM4_OPERAND_SEL_SCALAR(optok
.sel
);
115 case SM4_OPERAND_COMPNUM_N
:
116 fail("Unhandled operand component type");
118 op
.file
= (sm4_file
)optok
.file
;
119 op
.num_indices
= optok
.num_indices
;
123 sm4_token_operand_extended optokext
;
124 read_token(&optokext
);
125 if(optokext
.type
== 0)
127 else if(optokext
.type
== 1)
129 op
.neg
= optokext
.neg
;
130 op
.abs
= optokext
.abs
;
133 fail("Unhandled extended operand token type");
136 for(unsigned i
= 0; i
< op
.num_indices
; ++i
)
140 repr
= optok
.index0_repr
;
142 repr
= optok
.index1_repr
;
144 repr
= optok
.index2_repr
;
146 fail("Unhandled operand index representation");
147 op
.indices
[0].disp
= 0;
148 // TODO: is disp supposed to be signed here??
151 case SM4_OPERAND_INDEX_REPR_IMM32
:
152 op
.indices
[i
].disp
= (int32_t)read32();
154 case SM4_OPERAND_INDEX_REPR_IMM64
:
155 op
.indices
[i
].disp
= read64();
157 case SM4_OPERAND_INDEX_REPR_REG
:
159 op
.indices
[i
].reg
.reset(new sm4_op());
160 read_op(&*op
.indices
[0].reg
);
162 case SM4_OPERAND_INDEX_REPR_REG_IMM32
:
163 op
.indices
[i
].disp
= (int32_t)read32();
165 case SM4_OPERAND_INDEX_REPR_REG_IMM64
:
166 op
.indices
[i
].disp
= read64();
171 if(op
.file
== SM4_FILE_IMMEDIATE32
)
173 for(unsigned i
= 0; i
< op
.comps
; ++i
)
174 op
.imm_values
[i
].i32
= read32();
176 else if(op
.file
== SM4_FILE_IMMEDIATE64
)
178 for(unsigned i
= 0; i
< op
.comps
; ++i
)
179 op
.imm_values
[i
].i64
= read64();
185 read_token(&program
.version
);
187 unsigned lentok
= read32();
188 tokens_end
= tokens
- 2 + lentok
;
190 while(tokens
!= tokens_end
)
192 sm4_token_instruction insntok
;
193 read_token(&insntok
);
194 unsigned* insn_end
= tokens
- 1 + insntok
.length
;
195 sm4_opcode opcode
= (sm4_opcode
)insntok
.opcode
;
196 check(opcode
< SM4_OPCODE_COUNT
);
198 if(opcode
== SM4_OPCODE_CUSTOMDATA
)
200 unsigned customlen
= read32() - 2;
205 if((opcode
>= SM4_OPCODE_DCL_RESOURCE
&& opcode
<= SM4_OPCODE_DCL_GLOBAL_FLAGS
)
206 || (opcode
>= SM4_OPCODE_DCL_STREAM
&& opcode
<= SM4_OPCODE_DCL_RESOURCE_STRUCTURED
))
208 sm4_dcl
& dcl
= *new sm4_dcl
;
209 program
.dcls
.push_back(&dcl
);
210 (sm4_token_instruction
&)dcl
= insntok
;
212 sm4_token_instruction_extended exttok
;
213 memcpy(&exttok
, &insntok
, sizeof(exttok
));
214 while(exttok
.extended
)
219 #define READ_OP_ANY dcl.op.reset(new sm4_op()); read_op(&*dcl.op);
220 #define READ_OP(FILE) READ_OP_ANY
221 //check(dcl.op->file == SM4_FILE_##FILE);
225 case SM4_OPCODE_DCL_GLOBAL_FLAGS
:
227 case SM4_OPCODE_DCL_RESOURCE
:
229 read_token(&dcl
.rrt
);
231 case SM4_OPCODE_DCL_SAMPLER
:
234 case SM4_OPCODE_DCL_INPUT
:
235 case SM4_OPCODE_DCL_INPUT_PS
:
238 case SM4_OPCODE_DCL_INPUT_SIV
:
239 case SM4_OPCODE_DCL_INPUT_SGV
:
240 case SM4_OPCODE_DCL_INPUT_PS_SIV
:
241 case SM4_OPCODE_DCL_INPUT_PS_SGV
:
243 dcl
.sv
= (sm4_sv
)(uint16_t)read32();
245 case SM4_OPCODE_DCL_OUTPUT
:
248 case SM4_OPCODE_DCL_OUTPUT_SIV
:
249 case SM4_OPCODE_DCL_OUTPUT_SGV
:
251 dcl
.sv
= (sm4_sv
)(uint16_t)read32();
253 case SM4_OPCODE_DCL_INDEX_RANGE
:
255 check(dcl
.op
->file
== SM4_FILE_INPUT
|| dcl
.op
->file
== SM4_FILE_OUTPUT
);
258 case SM4_OPCODE_DCL_TEMPS
:
261 case SM4_OPCODE_DCL_INDEXABLE_TEMP
:
262 READ_OP(INDEXABLE_TEMP
);
263 dcl
.indexable_temp
.num
= read32();
264 dcl
.indexable_temp
.comps
= read32();
266 case SM4_OPCODE_DCL_CONSTANT_BUFFER
:
267 READ_OP(CONSTANT_BUFFER
);
269 case SM4_OPCODE_DCL_GS_INPUT_PRIMITIVE
:
270 case SM4_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY
:
272 case SM4_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT
:
275 case SM4_OPCODE_DCL_GS_INSTANCE_COUNT
:
278 case SM4_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT
:
279 case SM4_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT
:
280 case SM4_OPCODE_DCL_TESS_DOMAIN
:
281 case SM4_OPCODE_DCL_TESS_PARTITIONING
:
282 case SM4_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE
:
284 case SM4_OPCODE_DCL_HS_MAX_TESSFACTOR
:
287 case SM4_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT
:
290 case SM4_OPCODE_DCL_FUNCTION_BODY
:
293 case SM4_OPCODE_DCL_FUNCTION_TABLE
:
295 dcl
.data
= malloc(dcl
.num
* sizeof(uint32_t));
296 for(unsigned i
= 0; i
< dcl
.num
; ++i
)
297 ((uint32_t*)dcl
.data
)[i
] = read32();
299 case SM4_OPCODE_DCL_INTERFACE
:
300 dcl
.intf
.id
= read32();
301 dcl
.intf
.expected_function_table_length
= read32();
303 uint32_t v
= read32();
304 dcl
.intf
.table_length
= v
& 0xffff;
305 dcl
.intf
.array_length
= v
>> 16;
307 dcl
.data
= malloc(dcl
.intf
.table_length
* sizeof(uint32_t));
308 for(unsigned i
= 0; i
< dcl
.intf
.table_length
; ++i
)
309 ((uint32_t*)dcl
.data
)[i
] = read32();
311 case SM4_OPCODE_DCL_THREAD_GROUP
:
312 dcl
.thread_group_size
[0] = read32();
313 dcl
.thread_group_size
[1] = read32();
314 dcl
.thread_group_size
[2] = read32();
316 case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED
:
317 READ_OP(UNORDERED_ACCESS_VIEW
);
318 read_token(&dcl
.rrt
);
320 case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW
:
321 READ_OP(UNORDERED_ACCESS_VIEW
);
323 case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED
:
324 READ_OP(UNORDERED_ACCESS_VIEW
);
325 dcl
.structured
.stride
= read32();
327 case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW
:
328 READ_OP(THREAD_GROUP_SHARED_MEMORY
);
331 case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED
:
332 READ_OP(THREAD_GROUP_SHARED_MEMORY
);
333 dcl
.structured
.stride
= read32();
334 dcl
.structured
.count
= read32();
336 case SM4_OPCODE_DCL_RESOURCE_RAW
:
339 case SM4_OPCODE_DCL_RESOURCE_STRUCTURED
:
341 dcl
.structured
.stride
= read32();
343 case SM4_OPCODE_DCL_STREAM
:
344 /* TODO: dcl_stream is undocumented: what is it? */
345 fail("Unhandled dcl_stream since it's undocumented");
347 fail("Unhandled declaration");
350 check(tokens
== insn_end
);
354 sm4_insn
& insn
= *new sm4_insn
;
355 program
.insns
.push_back(&insn
);
356 (sm4_token_instruction
&)insn
= insntok
;
358 sm4_token_instruction_extended exttok
;
359 memcpy(&exttok
, &insntok
, sizeof(exttok
));
360 while(exttok
.extended
)
363 if(exttok
.type
== SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_SAMPLE_CONTROLS
)
365 insn
.sample_offset
[0] = exttok
.sample_controls
.offset_u
;
366 insn
.sample_offset
[1] = exttok
.sample_controls
.offset_v
;
367 insn
.sample_offset
[2] = exttok
.sample_controls
.offset_w
;
369 else if(exttok
.type
== SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_DIM
)
370 insn
.resource_target
= exttok
.resource_target
.target
;
371 else if(exttok
.type
== SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_RETURN_TYPE
)
373 insn
.resource_return_type
[0] = exttok
.resource_return_type
.x
;
374 insn
.resource_return_type
[1] = exttok
.resource_return_type
.y
;
375 insn
.resource_return_type
[2] = exttok
.resource_return_type
.z
;
376 insn
.resource_return_type
[3] = exttok
.resource_return_type
.w
;
382 case SM4_OPCODE_INTERFACE_CALL
:
390 while(tokens
!= insn_end
)
392 check(tokens
< insn_end
);
393 check(op_num
< SM4_MAX_OPS
);
394 insn
.ops
[op_num
].reset(new sm4_op
);
395 read_op(&*insn
.ops
[op_num
]);
398 insn
.num_ops
= op_num
;
410 catch(const char* error
)
417 sm4_program
* sm4_parse(void* tokens
, int size
)
419 sm4_program
* program
= new sm4_program
;
420 sm4_parser
parser(*program
, tokens
, size
);