Home | History | Annotate | Download | only in src
      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 
     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 			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 
    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 				// 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 
    423 	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 
    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