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