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