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