sm4_parse.cpp revision 903e3257d071caeeec84a096069a78b55666f72d
199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant/**************************************************************************
299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant *
399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * Copyright 2010 Luca Barbieri
499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant *
5b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant * Permission is hereby granted, free of charge, to any person obtaining
6b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant * a copy of this software and associated documentation files (the
799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * "Software"), to deal in the Software without restriction, including
899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * without limitation the rights to use, copy, modify, merge, publish,
999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * distribute, sublicense, and/or sell copies of the Software, and to
1099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * permit persons to whom the Software is furnished to do so, subject to
1199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * the following conditions:
1299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant *
1399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * The above copyright notice and this permission notice (including the
1499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * next paragraph) shall be included in all copies or substantial
1599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * portions of the Software.
1699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant *
1799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
2199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant *
2599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant **************************************************************************/
2699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
2799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#include "sm4.h"
2899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#include "utils.h"
2999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
3099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#if 1
3199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#define check(x) assert(x)
3299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#define fail(x) assert(0 && (x))
3399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#else
3499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#define check(x) do {if(!(x)) throw(#x);} while(0)
3599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#define fail(x) throw(x)
3699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant#endif
3799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
3899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnantstruct sm4_parser
3999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant{
4099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	unsigned* tokens;
4199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	unsigned* tokens_end;
4299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	sm4_program& program;
4399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
4499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	sm4_parser(sm4_program& program, void* p_tokens, unsigned size)
4599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	: program(program)
4699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	{
4799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		tokens = (unsigned*)p_tokens;
4899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		tokens_end = (unsigned*)((char*)p_tokens + size);
4999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	}
5099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
5199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	/* TODO: byteswap if machine is big endian */
5299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	uint32_t read32()
5399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	{
5499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		check(tokens < tokens_end);
5599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		return bswap_le32(*tokens++);
5699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	}
5799be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
5899be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	template<typename T>
5999be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	void read_token(T* tok)
6099be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	{
6199be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		*(unsigned*)tok = read32();
6299be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	}
6399be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant
6499be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	uint64_t read64()
6599be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant	{
6699be8237db0c69ea05bb82bbb8fc8a2273c05743Howard Hinnant		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			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:
158relative:
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
183	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				unsigned customlen = read32() - 2;
201				skip(customlen);
202				continue;
203			}
204
205			if(opcode == SM4_OPCODE_HS_FORK_PHASE || opcode == SM4_OPCODE_HS_JOIN_PHASE)
206			{
207				// need to interleave these with the declarations or we cannot
208				// assign fork/join phase instance counts to phases
209				sm4_dcl& dcl = *new sm4_dcl;
210				program.dcls.push_back(&dcl);
211				dcl.opcode = opcode;
212			}
213
214			if((opcode >= SM4_OPCODE_DCL_RESOURCE && opcode <= SM4_OPCODE_DCL_GLOBAL_FLAGS)
215				|| (opcode >= SM4_OPCODE_DCL_STREAM && opcode <= SM4_OPCODE_DCL_RESOURCE_STRUCTURED))
216			{
217				sm4_dcl& dcl = *new sm4_dcl;
218				program.dcls.push_back(&dcl);
219				(sm4_token_instruction&)dcl = insntok;
220
221				sm4_token_instruction_extended exttok;
222				memcpy(&exttok, &insntok, sizeof(exttok));
223				while(exttok.extended)
224				{
225					read_token(&exttok);
226				}
227
228#define READ_OP_ANY dcl.op.reset(new sm4_op()); read_op(&*dcl.op);
229#define READ_OP(FILE) READ_OP_ANY
230				//check(dcl.op->file == SM4_FILE_##FILE);
231
232				switch(opcode)
233				{
234				case SM4_OPCODE_DCL_GLOBAL_FLAGS:
235					break;
236				case SM4_OPCODE_DCL_RESOURCE:
237					READ_OP(RESOURCE);
238					read_token(&dcl.rrt);
239					break;
240				case SM4_OPCODE_DCL_SAMPLER:
241					READ_OP(SAMPLER);
242					break;
243				case SM4_OPCODE_DCL_INPUT:
244				case SM4_OPCODE_DCL_INPUT_PS:
245					READ_OP(INPUT);
246					break;
247				case SM4_OPCODE_DCL_INPUT_SIV:
248				case SM4_OPCODE_DCL_INPUT_SGV:
249				case SM4_OPCODE_DCL_INPUT_PS_SIV:
250				case SM4_OPCODE_DCL_INPUT_PS_SGV:
251					READ_OP(INPUT);
252					dcl.sv = (sm4_sv)(uint16_t)read32();
253					break;
254				case SM4_OPCODE_DCL_OUTPUT:
255					READ_OP(OUTPUT);
256					break;
257				case SM4_OPCODE_DCL_OUTPUT_SIV:
258				case SM4_OPCODE_DCL_OUTPUT_SGV:
259					READ_OP(OUTPUT);
260					dcl.sv = (sm4_sv)(uint16_t)read32();
261					break;
262				case SM4_OPCODE_DCL_INDEX_RANGE:
263					READ_OP_ANY;
264					check(dcl.op->file == SM4_FILE_INPUT || dcl.op->file == SM4_FILE_OUTPUT);
265					dcl.num = read32();
266					break;
267				case SM4_OPCODE_DCL_TEMPS:
268					dcl.num = read32();
269					break;
270				case SM4_OPCODE_DCL_INDEXABLE_TEMP:
271					READ_OP(INDEXABLE_TEMP);
272					dcl.indexable_temp.num = read32();
273					dcl.indexable_temp.comps = read32();
274					break;
275				case SM4_OPCODE_DCL_CONSTANT_BUFFER:
276					READ_OP(CONSTANT_BUFFER);
277					break;
278				case SM4_OPCODE_DCL_GS_INPUT_PRIMITIVE:
279				case SM4_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
280					break;
281				case SM4_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
282					dcl.num = read32();
283					break;
284				case SM4_OPCODE_DCL_GS_INSTANCE_COUNT:
285					dcl.num = read32();
286					break;
287				case SM4_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
288				case SM4_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
289				case SM4_OPCODE_DCL_TESS_DOMAIN:
290				case SM4_OPCODE_DCL_TESS_PARTITIONING:
291				case SM4_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
292					break;
293				case SM4_OPCODE_DCL_HS_MAX_TESSFACTOR:
294					dcl.f32 = read32();
295					break;
296				case SM4_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
297					dcl.num = read32();
298					break;
299				case SM4_OPCODE_DCL_FUNCTION_BODY:
300					dcl.num = read32();
301					break;
302				case SM4_OPCODE_DCL_FUNCTION_TABLE:
303					dcl.num = read32();
304					dcl.data = malloc(dcl.num * sizeof(uint32_t));
305					for(unsigned i = 0; i < dcl.num; ++i)
306						((uint32_t*)dcl.data)[i] = read32();
307					break;
308				case SM4_OPCODE_DCL_INTERFACE:
309					dcl.intf.id = read32();
310					dcl.intf.expected_function_table_length = read32();
311					{
312						uint32_t v = read32();
313						dcl.intf.table_length = v & 0xffff;
314						dcl.intf.array_length = v >> 16;
315					}
316					dcl.data = malloc(dcl.intf.table_length * sizeof(uint32_t));
317					for(unsigned i = 0; i < dcl.intf.table_length; ++i)
318						((uint32_t*)dcl.data)[i] = read32();
319					break;
320				case SM4_OPCODE_DCL_THREAD_GROUP:
321					dcl.thread_group_size[0] = read32();
322					dcl.thread_group_size[1] = read32();
323					dcl.thread_group_size[2] = read32();
324					break;
325				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
326					READ_OP(UNORDERED_ACCESS_VIEW);
327					read_token(&dcl.rrt);
328					break;
329				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
330					READ_OP(UNORDERED_ACCESS_VIEW);
331					break;
332				case SM4_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
333					READ_OP(UNORDERED_ACCESS_VIEW);
334					dcl.structured.stride = read32();
335					break;
336				case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
337					READ_OP(THREAD_GROUP_SHARED_MEMORY);
338					dcl.num = read32();
339					break;
340				case SM4_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
341					READ_OP(THREAD_GROUP_SHARED_MEMORY);
342					dcl.structured.stride = read32();
343					dcl.structured.count = read32();
344					break;
345				case SM4_OPCODE_DCL_RESOURCE_RAW:
346					READ_OP(RESOURCE);
347					break;
348				case SM4_OPCODE_DCL_RESOURCE_STRUCTURED:
349					READ_OP(RESOURCE);
350					dcl.structured.stride = read32();
351					break;
352				case SM4_OPCODE_DCL_STREAM:
353					/* TODO: dcl_stream is undocumented: what is it? */
354					fail("Unhandled dcl_stream since it's undocumented");
355				default:
356					fail("Unhandled declaration");
357				}
358
359				check(tokens == insn_end);
360			}
361			else
362			{
363				sm4_insn& insn = *new sm4_insn;
364				program.insns.push_back(&insn);
365				(sm4_token_instruction&)insn = insntok;
366
367				sm4_token_instruction_extended exttok;
368				memcpy(&exttok, &insntok, sizeof(exttok));
369				while(exttok.extended)
370				{
371					read_token(&exttok);
372					if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_SAMPLE_CONTROLS)
373					{
374						insn.sample_offset[0] = exttok.sample_controls.offset_u;
375						insn.sample_offset[1] = exttok.sample_controls.offset_v;
376						insn.sample_offset[2] = exttok.sample_controls.offset_w;
377					}
378					else if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_DIM)
379						insn.resource_target = exttok.resource_target.target;
380					else if(exttok.type == SM4_TOKEN_INSTRUCTION_EXTENDED_TYPE_RESOURCE_RETURN_TYPE)
381					{
382						insn.resource_return_type[0] = exttok.resource_return_type.x;
383						insn.resource_return_type[1] = exttok.resource_return_type.y;
384						insn.resource_return_type[2] = exttok.resource_return_type.z;
385						insn.resource_return_type[3] = exttok.resource_return_type.w;
386					}
387				}
388
389				switch(opcode)
390				{
391				case SM4_OPCODE_INTERFACE_CALL:
392					insn.num = read32();
393					break;
394				default:
395					break;
396				}
397
398				unsigned op_num = 0;
399				while(tokens != insn_end)
400				{
401					check(tokens < insn_end);
402					check(op_num < SM4_MAX_OPS);
403					insn.ops[op_num].reset(new sm4_op);
404					read_op(&*insn.ops[op_num]);
405					++op_num;
406				}
407				insn.num_ops = op_num;
408			}
409		}
410	}
411
412	const char* parse()
413	{
414		try
415		{
416			do_parse();
417			return 0;
418		}
419		catch(const char* error)
420		{
421			return error;
422		}
423	}
424};
425
426sm4_program* sm4_parse(void* tokens, int size)
427{
428	sm4_program* program = new sm4_program;
429	sm4_parser parser(*program, tokens, size);
430	if(!parser.parse())
431		return program;
432	delete program;
433	return 0;
434}
435