1 /**************************************************************************
2  *
3  * Copyright 2010 Luca Barbieri
4  *
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:
12  *
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.
16  *
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.
24  *
25  **************************************************************************/
26 
27 #include "sm4.h"
28 #include "utils.h"
29 
30 #if 1
31 #define check(x) assert(x)
32 #define fail(x) assert(0 && (x))
33 #else
34 #define check(x) do {if(!(x)) throw(#x);} while(0)
35 #define fail(x) throw(x)
36 #endif
37 
38 struct sm4_parser
39 {
40 	unsigned* tokens;
41 	unsigned* tokens_end;
42 	sm4_program& program;
43 
sm4_parsersm4_parser44 	sm4_parser(sm4_program& program, void* p_tokens, unsigned size)
45 	: program(program)
46 	{
47 		tokens = (unsigned*)p_tokens;
48 		tokens_end = (unsigned*)((char*)p_tokens + size);
49 	}
50 
51 	/* TODO: byteswap if machine is big endian */
read32sm4_parser52 	uint32_t read32()
53 	{
54 		check(tokens < tokens_end);
55 		return bswap_le32(*tokens++);
56 	}
57 
58 	template<typename T>
read_tokensm4_parser59 	void read_token(T* tok)
60 	{
61 		*(unsigned*)tok = read32();
62 	}
63 
read64sm4_parser64 	uint64_t read64()
65 	{
66 		unsigned a = read32();
67 		unsigned b = read32();
68 		return (uint64_t)a | ((uint64_t)b << 32);
69 	}
70 
skipsm4_parser71 	void skip(unsigned toskip)
72 	{
73 		tokens += toskip;
74 	}
75 
read_opsm4_parser76 	void read_op(sm4_op* pop)
77 	{
78 		sm4_op& op = *pop;
79 		sm4_token_operand optok;
80 		read_token(&optok);
81 		assert(optok.file < SM4_FILE_COUNT);
82 		op.swizzle[0] = 0;
83 		op.swizzle[1] = 1;
84 		op.swizzle[2] = 2;
85 		op.swizzle[3] = 3;
86 		op.mask = 0xf;
87 		switch(optok.comps_enum)
88 		{
89 		case SM4_OPERAND_COMPNUM_0:
90 			op.comps = 0;
91 			break;
92 		case SM4_OPERAND_COMPNUM_1:
93 			op.comps = 1;
94 			op.swizzle[1] = op.swizzle[2] = op.swizzle[3] = 0;
95 			break;
96 		case SM4_OPERAND_COMPNUM_4:
97 			op.comps = 4;
98 			op.mode = optok.mode;
99 			switch(optok.mode)
100 			{
101 			case SM4_OPERAND_MODE_MASK:
102 				op.mask = SM4_OPERAND_SEL_MASK(optok.sel);
103 				break;
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);
109 				break;
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);
112 				break;
113 			}
114 			break;
115 		case SM4_OPERAND_COMPNUM_N:
116 			fail("Unhandled operand component type");
117 		}
118 		op.file = (sm4_file)optok.file;
119 		op.num_indices = optok.num_indices;
120 
121 		if(optok.extended)
122 		{
123 			sm4_token_operand_extended optokext;
124 			read_token(&optokext);
125 			if(optokext.type == 0)
126 			{}
127 			else if(optokext.type == 1)
128 			{
129 				op.neg = optokext.neg;
130 				op.abs= optokext.abs;
131 			}
132 			else
133 				fail("Unhandled extended operand token type");
134 		}
135 
136 		for(unsigned i = 0; i < op.num_indices; ++i)
137 		{
138 			unsigned repr;
139 			if(i == 0)
140 				repr = optok.index0_repr;
141 			else if(i == 1)
142 				repr = optok.index1_repr;
143 			else if(i == 2)
144 				repr = optok.index2_repr;
145 			else
146 				fail("Unhandled operand index representation");
147 			op.indices[i].disp = 0;
148 			// TODO: is disp supposed to be signed here??
149 			switch(repr)
150 			{
151 			case SM4_OPERAND_INDEX_REPR_IMM32:
152 				op.indices[i].disp = (int32_t)read32();
153 				break;
154 			case SM4_OPERAND_INDEX_REPR_IMM64:
155 				op.indices[i].disp = read64();
156 				break;
157 			case SM4_OPERAND_INDEX_REPR_REG:
158 relative:
159 				op.indices[i].reg.reset(new sm4_op());
160 				read_op(&*op.indices[i].reg);
161 				break;
162 			case SM4_OPERAND_INDEX_REPR_REG_IMM32:
163 				op.indices[i].disp = (int32_t)read32();
164 				goto relative;
165 			case SM4_OPERAND_INDEX_REPR_REG_IMM64:
166 				op.indices[i].disp = read64();
167 				goto relative;
168 			}
169 		}
170 
171 		if(op.file == SM4_FILE_IMMEDIATE32)
172 		{
173 			for(unsigned i = 0; i < op.comps; ++i)
174 				op.imm_values[i].i32 = read32();
175 		}
176 		else if(op.file == SM4_FILE_IMMEDIATE64)
177 		{
178 			for(unsigned i = 0; i < op.comps; ++i)
179 				op.imm_values[i].i64 = read64();
180 		}
181 	}
182 
do_parsesm4_parser183 	void do_parse()
184 	{
185 		read_token(&program.version);
186 
187 		unsigned lentok = read32();
188 		tokens_end = tokens - 2 + lentok;
189 
190 		while(tokens != tokens_end)
191 		{
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);
197 
198 			if(opcode == SM4_OPCODE_CUSTOMDATA)
199 			{
200 				// immediate constant buffer data
201 				unsigned customlen = read32() - 2;
202 
203 				sm4_dcl& dcl = *new sm4_dcl;
204 				program.dcls.push_back(&dcl);
205 
206 				dcl.opcode = SM4_OPCODE_CUSTOMDATA;
207 				dcl.num = customlen;
208 				dcl.data = malloc(customlen * sizeof(tokens[0]));
209 
210 				memcpy(dcl.data, &tokens[0], customlen * sizeof(tokens[0]));
211 
212 				skip(customlen);
213 				continue;
214 			}
215 
216 			if(opcode == SM4_OPCODE_HS_FORK_PHASE || opcode == SM4_OPCODE_HS_JOIN_PHASE)
217 			{
218 				// need to interleave these with the declarations or we cannot
219 				// assign fork/join phase instance counts to phases
220 				sm4_dcl& dcl = *new sm4_dcl;
221 				program.dcls.push_back(&dcl);
222 				dcl.opcode = opcode;
223 			}
224 
225 			if((opcode >= SM4_OPCODE_DCL_RESOURCE && opcode <= SM4_OPCODE_DCL_GLOBAL_FLAGS)
226 				|| (opcode >= SM4_OPCODE_DCL_STREAM && opcode <= SM4_OPCODE_DCL_RESOURCE_STRUCTURED))
227 			{
228 				sm4_dcl& dcl = *new sm4_dcl;
229 				program.dcls.push_back(&dcl);
230 				(sm4_token_instruction&)dcl = insntok;
231 
232 				sm4_token_instruction_extended exttok;
233 				memcpy(&exttok, &insntok, sizeof(exttok));
234 				while(exttok.extended)
235 				{
236 					read_token(&exttok);
237 				}
238 
239 #define READ_OP_ANY dcl.op.reset(new sm4_op()); read_op(&*dcl.op);
240 #define READ_OP(FILE) READ_OP_ANY
241 				//check(dcl.op->file == SM4_FILE_##FILE);
242 
243 				switch(opcode)
244 				{
245 				case SM4_OPCODE_DCL_GLOBAL_FLAGS:
246 					break;
247 				case SM4_OPCODE_DCL_RESOURCE:
248 					READ_OP(RESOURCE);
249 					read_token(&dcl.rrt);
250 					break;
251 				case SM4_OPCODE_DCL_SAMPLER:
252 					READ_OP(SAMPLER);
253 					break;
254 				case SM4_OPCODE_DCL_INPUT:
255 				case SM4_OPCODE_DCL_INPUT_PS:
256 					READ_OP(INPUT);
257 					break;
258 				case SM4_OPCODE_DCL_INPUT_SIV:
259 				case SM4_OPCODE_DCL_INPUT_SGV:
260 				case SM4_OPCODE_DCL_INPUT_PS_SIV:
261 				case SM4_OPCODE_DCL_INPUT_PS_SGV:
262 					READ_OP(INPUT);
263 					dcl.sv = (sm4_sv)(uint16_t)read32();
264 					break;
265 				case SM4_OPCODE_DCL_OUTPUT:
266 					READ_OP(OUTPUT);
267 					break;
268 				case SM4_OPCODE_DCL_OUTPUT_SIV:
269 				case SM4_OPCODE_DCL_OUTPUT_SGV:
270 					READ_OP(OUTPUT);
271 					dcl.sv = (sm4_sv)(uint16_t)read32();
272 					break;
273 				case SM4_OPCODE_DCL_INDEX_RANGE:
274 					READ_OP_ANY;
275 					check(dcl.op->file == SM4_FILE_INPUT || dcl.op->file == SM4_FILE_OUTPUT);
276 					dcl.num = read32();
277 					break;
278 				case SM4_OPCODE_DCL_TEMPS:
279 					dcl.num = read32();
280 					break;
281 				case SM4_OPCODE_DCL_INDEXABLE_TEMP:
282 					READ_OP(INDEXABLE_TEMP);
283 					dcl.indexable_temp.num = read32();
284 					dcl.indexable_temp.comps = read32();
285 					break;
286 				case SM4_OPCODE_DCL_CONSTANT_BUFFER:
287 					READ_OP(CONSTANT_BUFFER);
288 					break;
289 				case SM4_OPCODE_DCL_GS_INPUT_PRIMITIVE:
290 				case SM4_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
291 					break;
292 				case SM4_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
293 					dcl.num = read32();
294 					break;
295 				case SM4_OPCODE_DCL_GS_INSTANCE_COUNT:
296 					dcl.num = read32();
297 					break;
298 				case SM4_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
299 				case SM4_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
300 				case SM4_OPCODE_DCL_TESS_DOMAIN:
301 				case SM4_OPCODE_DCL_TESS_PARTITIONING:
302 				case SM4_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
303 					break;
304 				case SM4_OPCODE_DCL_HS_MAX_TESSFACTOR:
305 					dcl.f32 = read32();
306 					break;
307 				case SM4_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
308 					dcl.num = read32();
309 					break;
310 				case SM4_OPCODE_DCL_FUNCTION_BODY:
311 					dcl.num = read32();
312 					break;
313 				case SM4_OPCODE_DCL_FUNCTION_TABLE:
314 					dcl.num = read32();
315 					dcl.data = malloc(dcl.num * sizeof(uint32_t));
316 					for(unsigned i = 0; i < dcl.num; ++i)
317 						((uint32_t*)dcl.data)[i] = read32();
318 					break;
319 				case SM4_OPCODE_DCL_INTERFACE:
320 					dcl.intf.id = read32();
321 					dcl.intf.expected_function_table_length = read32();
322 					{
323 						uint32_t v = read32();
324 						dcl.intf.table_length = v & 0xffff;
325 						dcl.intf.array_length = v >> 16;
326 					}
327 					dcl.data = malloc(dcl.intf.table_length * sizeof(uint32_t));
328 					for(unsigned i = 0; i < dcl.intf.table_length; ++i)
329 						((uint32_t*)dcl.data)[i] = read32();
330 					break;
331 				case SM4_OPCODE_DCL_THREAD_GROUP:
332 					dcl.thread_group_size[0] = read32();
333 					dcl.thread_group_size[1] = read32();
334 					dcl.thread_group_size[2] = read32();
335 					break;
336 				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
337 					READ_OP(UNORDERED_ACCESS_VIEW);
338 					read_token(&dcl.rrt);
339 					break;
340 				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
341 					READ_OP(UNORDERED_ACCESS_VIEW);
342 					break;
343 				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
344 					READ_OP(UNORDERED_ACCESS_VIEW);
345 					dcl.structured.stride = read32();
346 					break;
347 				case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
348 					READ_OP(THREAD_GROUP_SHARED_MEMORY);
349 					dcl.num = read32();
350 					break;
351 				case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
352 					READ_OP(THREAD_GROUP_SHARED_MEMORY);
353 					dcl.structured.stride = read32();
354 					dcl.structured.count = read32();
355 					break;
356 				case SM4_OPCODE_DCL_RESOURCE_RAW:
357 					READ_OP(RESOURCE);
358 					break;
359 				case SM4_OPCODE_DCL_RESOURCE_STRUCTURED:
360 					READ_OP(RESOURCE);
361 					dcl.structured.stride = read32();
362 					break;
363 				case SM4_OPCODE_DCL_STREAM:
364 					/* TODO: dcl_stream is undocumented: what is it? */
365 					fail("Unhandled dcl_stream since it's undocumented");
366 				default:
367 					fail("Unhandled declaration");
368 				}
369 
370 				check(tokens == insn_end);
371 			}
372 			else
373 			{
374 				sm4_insn& insn = *new sm4_insn;
375 				program.insns.push_back(&insn);
376 				(sm4_token_instruction&)insn = insntok;
377 
378 				sm4_token_instruction_extended exttok;
379 				memcpy(&exttok, &insntok, sizeof(exttok));
380 				while(exttok.extended)
381 				{
382 					read_token(&exttok);
383 					if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_SAMPLE_CONTROLS)
384 					{
385 						insn.sample_offset[0] = exttok.sample_controls.offset_u;
386 						insn.sample_offset[1] = exttok.sample_controls.offset_v;
387 						insn.sample_offset[2] = exttok.sample_controls.offset_w;
388 					}
389 					else if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_DIM)
390 						insn.resource_target = exttok.resource_target.target;
391 					else if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_RETURN_TYPE)
392 					{
393 						insn.resource_return_type[0] = exttok.resource_return_type.x;
394 						insn.resource_return_type[1] = exttok.resource_return_type.y;
395 						insn.resource_return_type[2] = exttok.resource_return_type.z;
396 						insn.resource_return_type[3] = exttok.resource_return_type.w;
397 					}
398 				}
399 
400 				switch(opcode)
401 				{
402 				case SM4_OPCODE_INTERFACE_CALL:
403 					insn.num = read32();
404 					break;
405 				default:
406 					break;
407 				}
408 
409 				unsigned op_num = 0;
410 				while(tokens != insn_end)
411 				{
412 					check(tokens < insn_end);
413 					check(op_num < SM4_MAX_OPS);
414 					insn.ops[op_num].reset(new sm4_op);
415 					read_op(&*insn.ops[op_num]);
416 					++op_num;
417 				}
418 				insn.num_ops = op_num;
419 			}
420 		}
421 	}
422 
parsesm4_parser423 	const char* parse()
424 	{
425 		try
426 		{
427 			do_parse();
428 			return 0;
429 		}
430 		catch(const char* error)
431 		{
432 			return error;
433 		}
434 	}
435 };
436 
sm4_parse(void * tokens,int size)437 sm4_program* sm4_parse(void* tokens, int size)
438 {
439 	sm4_program* program = new sm4_program;
440 	sm4_parser parser(*program, tokens, size);
441 	if(!parser.parse())
442 		return program;
443 	delete program;
444 	return 0;
445 }
446