%{ /* * Copyright © 2006 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Eric Anholt * */ #include #include #include #include #include #include #include "gen4asm.h" #include "brw_eu.h" #include "gen8_instruction.h" #pragma GCC diagnostic ignored "-Wformat-nonliteral" #define DEFAULT_EXECSIZE (ffs(program_defaults.execute_size) - 1) #define DEFAULT_DSTREGION -1 #define SWIZZLE(reg) (reg.dw1.bits.swizzle) #define GEN(i) (&(i)->insn.gen) #define GEN8(i) (&(i)->insn.gen8) #define YYLTYPE YYLTYPE typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE; extern int need_export; static struct src_operand src_null_reg = { .reg.file = BRW_ARCHITECTURE_REGISTER_FILE, .reg.nr = BRW_ARF_NULL, .reg.type = BRW_REGISTER_TYPE_UD, }; static struct brw_reg dst_null_reg = { .file = BRW_ARCHITECTURE_REGISTER_FILE, .nr = BRW_ARF_NULL, }; static struct brw_reg ip_dst = { .file = BRW_ARCHITECTURE_REGISTER_FILE, .nr = BRW_ARF_IP, .type = BRW_REGISTER_TYPE_UD, .address_mode = BRW_ADDRESS_DIRECT, .hstride = 1, .dw1.bits.writemask = BRW_WRITEMASK_XYZW, }; static struct src_operand ip_src = { .reg.file = BRW_ARCHITECTURE_REGISTER_FILE, .reg.nr = BRW_ARF_IP, .reg.type = BRW_REGISTER_TYPE_UD, .reg.address_mode = BRW_ADDRESS_DIRECT, .reg.dw1.bits.swizzle = BRW_SWIZZLE_NOOP, }; static int get_type_size(unsigned type); static void set_instruction_opcode(struct brw_program_instruction *instr, unsigned opcode); static int set_instruction_dest(struct brw_program_instruction *instr, struct brw_reg *dest); static int set_instruction_src0(struct brw_program_instruction *instr, struct src_operand *src, YYLTYPE *location); static int set_instruction_src1(struct brw_program_instruction *instr, struct src_operand *src, YYLTYPE *location); static int set_instruction_dest_three_src(struct brw_program_instruction *instr, struct brw_reg *dest); static int set_instruction_src0_three_src(struct brw_program_instruction *instr, struct src_operand *src); static int set_instruction_src1_three_src(struct brw_program_instruction *instr, struct src_operand *src); static int set_instruction_src2_three_src(struct brw_program_instruction *instr, struct src_operand *src); static void set_instruction_saturate(struct brw_program_instruction *instr, int saturate); static void set_instruction_options(struct brw_program_instruction *instr, struct options options); static void set_instruction_predicate(struct brw_program_instruction *instr, struct predicate *p); static void set_instruction_pred_cond(struct brw_program_instruction *instr, struct predicate *p, struct condition *c, YYLTYPE *location); static void set_direct_dst_operand(struct brw_reg *dst, struct brw_reg *reg, int type); static void set_direct_src_operand(struct src_operand *src, struct brw_reg *reg, int type); void set_branch_two_offsets(struct brw_program_instruction *insn, int jip_offset, int uip_offset); void set_branch_one_offset(struct brw_program_instruction *insn, int jip_offset); enum message_level { WARN, ERROR, }; static void message(enum message_level level, YYLTYPE *location, const char *fmt, ...) { static const char *level_str[] = { "warning", "error" }; va_list args; if (location) fprintf(stderr, "%s:%d:%d: %s: ", input_filename, location->first_line, location->first_column, level_str[level]); else fprintf(stderr, "%s:%s: ", input_filename, level_str[level]); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); } #define warn(flag, l, fmt, ...) \ do { \ if (warning_flags & WARN_ ## flag) \ message(WARN, l, fmt, ## __VA_ARGS__); \ } while(0) #define error(l, fmt, ...) \ do { \ message(ERROR, l, fmt, ## __VA_ARGS__); \ } while(0) /* like strcmp, but handles NULL pointers */ static bool strcmp0(const char *s1, const char* s2) { if (!s1) return -(s1 != s2); if (!s2) return s1 != s2; return strcmp (s1, s2); } static bool region_equal(struct region *r1, struct region *r2) { return memcmp(r1, r2, sizeof(struct region)) == 0; } static bool reg_equal(struct brw_reg *r1, struct brw_reg *r2) { return memcmp(r1, r2, sizeof(struct brw_reg)) == 0; } static bool declared_register_equal(struct declared_register *r1, struct declared_register *r2) { if (strcmp0(r1->name, r2->name) != 0) return false; if (!reg_equal(&r1->reg, &r2->reg)) return false; if (!region_equal(&r1->src_region, &r2->src_region)) return false; if (r1->element_size != r2->element_size || r1->dst_region != r2->dst_region) return false; return true; } static void brw_program_init(struct brw_program *p) { memset(p, 0, sizeof(struct brw_program)); } static void brw_program_append_entry(struct brw_program *p, struct brw_program_instruction *entry) { entry->next = NULL; if (p->last) p->last->next = entry; else p->first = entry; p->last = entry; } static void brw_program_add_instruction(struct brw_program *p, struct brw_program_instruction *instruction) { struct brw_program_instruction *list_entry; list_entry = calloc(1, sizeof(struct brw_program_instruction)); list_entry->type = GEN4ASM_INSTRUCTION_GEN; list_entry->insn.gen = instruction->insn.gen; brw_program_append_entry(p, list_entry); } static void brw_program_add_relocatable(struct brw_program *p, struct brw_program_instruction *instruction) { struct brw_program_instruction *list_entry; list_entry = calloc(1, sizeof(struct brw_program_instruction)); list_entry->type = GEN4ASM_INSTRUCTION_GEN_RELOCATABLE; list_entry->insn.gen = instruction->insn.gen; list_entry->reloc = instruction->reloc; brw_program_append_entry(p, list_entry); } static void brw_program_add_label(struct brw_program *p, const char *label) { struct brw_program_instruction *list_entry; list_entry = calloc(1, sizeof(struct brw_program_instruction)); list_entry->type = GEN4ASM_INSTRUCTION_LABEL; list_entry->insn.label.name = strdup(label); brw_program_append_entry(p, list_entry); } static int resolve_dst_region(struct declared_register *reference, int region) { int resolved = region; if (resolved == DEFAULT_DSTREGION) { if (reference) resolved = reference->dst_region; else resolved = 1; } assert(resolved == 1 || resolved == 2 || resolved == 3); return resolved; } static inline int access_mode(struct brw_program_instruction *insn) { if (IS_GENp(8)) return gen8_access_mode(GEN8(insn)); else return GEN(insn)->header.access_mode; } static inline int exec_size(struct brw_program_instruction *insn) { if (IS_GENp(8)) return gen8_exec_size(GEN8(insn)); else return GEN(insn)->header.execution_size; } static void set_execsize(struct brw_program_instruction *insn, int execsize) { if (IS_GENp(8)) gen8_set_exec_size(GEN8(insn), execsize); else GEN(insn)->header.execution_size = execsize; } static bool validate_dst_reg(struct brw_program_instruction *insn, struct brw_reg *reg) { if (reg->address_mode == BRW_ADDRESS_DIRECT && access_mode(insn) == BRW_ALIGN_1 && reg->dw1.bits.writemask != 0 && reg->dw1.bits.writemask != BRW_WRITEMASK_XYZW) { fprintf(stderr, "error: write mask set in align1 instruction\n"); return false; } if (reg->address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER && access_mode(insn) == BRW_ALIGN_16) { fprintf(stderr, "error: indirect Dst addr mode in align16 instruction\n"); return false; } return true; } static bool validate_src_reg(struct brw_program_instruction *insn, struct brw_reg reg, YYLTYPE *location) { int hstride_for_reg[] = {0, 1, 2, 4}; int vstride_for_reg[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256}; int width_for_reg[] = {1, 2, 4, 8, 16}; int execsize_for_reg[] = {1, 2, 4, 8, 16, 32}; int width, hstride, vstride, execsize; if (reg.file == BRW_IMMEDIATE_VALUE) return true; if (access_mode(insn) == BRW_ALIGN_1 && SWIZZLE(reg) && SWIZZLE(reg) != BRW_SWIZZLE_NOOP) { error(location, "swizzle bits set in align1 instruction\n"); return false; } if (reg.address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER && access_mode(insn) == BRW_ALIGN_16) { fprintf(stderr, "error: indirect Source addr mode in align16 instruction\n"); return false; } assert(reg.hstride >= 0 && reg.hstride < ARRAY_SIZE(hstride_for_reg)); hstride = hstride_for_reg[reg.hstride]; if (reg.vstride == 0xf) { vstride = -1; } else { assert(reg.vstride >= 0 && reg.vstride < ARRAY_SIZE(vstride_for_reg)); vstride = vstride_for_reg[reg.vstride]; } assert(reg.width >= 0 && reg.width < ARRAY_SIZE(width_for_reg)); width = width_for_reg[reg.width]; assert(exec_size(insn) >= 0 && exec_size(insn) < ARRAY_SIZE(execsize_for_reg)); execsize = execsize_for_reg[exec_size(insn)]; /* Register Region Restrictions */ /* B. If ExecSize = Width and HorzStride ≠ 0, VertStride must be set to * Width * HorzStride. */ if (execsize == width && hstride != 0) { if (vstride != -1 && vstride != width * hstride) warn(ALL, location, "execution size == width and hstride != 0 but " "vstride is not width * hstride\n"); } /* D. If Width = 1, HorzStride must be 0 regardless of the values of * ExecSize and VertStride. * * FIXME: In "advanced mode" hstride is set to 1, this is probably a bug * to fix, but it changes the generated opcodes and thus needs validation. */ if (width == 1 && hstride != 0) warn(ALL, location, "region width is 1 but horizontal stride is %d " " (should be 0)\n", hstride); /* E. If ExecSize = Width = 1, both VertStride and HorzStride must be 0. * This defines a scalar. */ if (execsize == 1 && width == 1) { if (hstride != 0) warn(ALL, location, "execution size and region width are 1 but " "horizontal stride is %d (should be 0)\n", hstride); if (vstride != 0) warn(ALL, location, "execution size and region width are 1 but " "vertical stride is %d (should be 0)\n", vstride); } return true; } static int get_subreg_address(unsigned regfile, unsigned type, unsigned subreg, unsigned address_mode) { int unit_size = 1; assert(address_mode == BRW_ADDRESS_DIRECT); assert(regfile != BRW_IMMEDIATE_VALUE); if (advanced_flag) unit_size = get_type_size(type); return subreg * unit_size; } /* only used in indirect address mode. * input: sub-register number of an address register * output: the value of AddrSubRegNum in the instruction binary code * * input output(advanced_flag==0) output(advanced_flag==1) * a0.0 0 0 * a0.1 invalid input 1 * a0.2 1 2 * a0.3 invalid input 3 * a0.4 2 4 * a0.5 invalid input 5 * a0.6 3 6 * a0.7 invalid input 7 * a0.8 4 invalid input * a0.10 5 invalid input * a0.12 6 invalid input * a0.14 7 invalid input */ static int get_indirect_subreg_address(unsigned subreg) { return advanced_flag == 0 ? subreg / 2 : subreg; } static void resolve_subnr(struct brw_reg *reg) { if (reg->file == BRW_IMMEDIATE_VALUE) return; if (reg->address_mode == BRW_ADDRESS_DIRECT) reg->subnr = get_subreg_address(reg->file, reg->type, reg->subnr, reg->address_mode); else reg->subnr = get_indirect_subreg_address(reg->subnr); } %} %locations %start ROOT %union { char *string; int integer; double number; struct brw_program_instruction instruction; struct brw_program program; struct region region; struct regtype regtype; struct brw_reg reg; struct condition condition; struct predicate predicate; struct options options; struct declared_register symbol_reg; imm32_t imm32; struct src_operand src_operand; } %token COLON %token SEMICOLON %token LPAREN RPAREN %token LANGLE RANGLE %token LCURLY RCURLY %token LSQUARE RSQUARE %token COMMA EQ %token ABS DOT %token PLUS MINUS MULTIPLY DIVIDE %token TYPE_UD TYPE_D TYPE_UW TYPE_W TYPE_UB TYPE_B %token TYPE_VF TYPE_HF TYPE_V TYPE_F %token ALIGN1 ALIGN16 SECHALF COMPR SWITCH ATOMIC NODDCHK NODDCLR %token MASK_DISABLE BREAKPOINT ACCWRCTRL EOT %token SEQ ANY2H ALL2H ANY4H ALL4H ANY8H ALL8H ANY16H ALL16H ANYV ALLV %token ZERO EQUAL NOT_ZERO NOT_EQUAL GREATER GREATER_EQUAL LESS LESS_EQUAL %token ROUND_INCREMENT OVERFLOW UNORDERED %token GENREG MSGREG ADDRESSREG ACCREG FLAGREG %token MASKREG AMASK IMASK LMASK CMASK %token MASKSTACKREG LMS IMS MASKSTACKDEPTHREG IMSD LMSD %token NOTIFYREG STATEREG CONTROLREG IPREG %token GENREGFILE MSGREGFILE %token MOV FRC RNDU RNDD RNDE RNDZ NOT LZD %token MUL MAC MACH LINE SAD2 SADA2 DP4 DPH DP3 DP2 %token AVG ADD SEL AND OR XOR SHR SHL ASR CMP CMPN PLN %token ADDC BFI1 BFREV CBIT F16TO32 F32TO16 FBH FBL %token SEND SENDC NOP JMPI IF IFF WHILE ELSE BREAK CONT HALT MSAVE %token PUSH MREST POP WAIT DO ENDIF ILLEGAL %token MATH_INST %token MAD LRP BFE BFI2 SUBB %token CALL RET %token BRD BRC %token NULL_TOKEN MATH SAMPLER GATEWAY READ WRITE URB THREAD_SPAWNER VME DATA_PORT CRE %token MSGLEN RETURNLEN %token ALLOCATE USED COMPLETE TRANSPOSE INTERLEAVE %token SATURATE %token INTEGER %token STRING %token NUMBER %token INV LOG EXP SQRT RSQ POW SIN COS SINCOS INTDIV INTMOD %token INTDIVMOD %token SIGNED SCALAR %token X Y Z W %token KERNEL_PRAGMA END_KERNEL_PRAGMA CODE_PRAGMA END_CODE_PRAGMA %token REG_COUNT_PAYLOAD_PRAGMA REG_COUNT_TOTAL_PRAGMA DECLARE_PRAGMA %token BASE ELEMENTSIZE SRCREGION DSTREGION TYPE %token DEFAULT_EXEC_SIZE_PRAGMA DEFAULT_REG_TYPE_PRAGMA %precedence SUBREGNUM %precedence SNDOPR %left PLUS MINUS %left MULTIPLY DIVIDE %precedence UMINUS %precedence DOT %precedence STR_SYMBOL_REG %precedence EMPTEXECSIZE %precedence LPAREN %type exp sndopr %type simple_int %type instruction unaryinstruction binaryinstruction %type binaryaccinstruction trinaryinstruction sendinstruction %type syncinstruction %type msgtarget %type mathinstruction %type nopinstruction %type relocatableinstruction breakinstruction %type ifelseinstruction loopinstruction haltinstruction %type multibranchinstruction subroutineinstruction jumpinstruction %type label %type instrseq %type instoption %type unaryop binaryop binaryaccop breakop %type trinaryop %type sendop %type conditionalmodifier %type predicate %type instoptions instoption_list %type condition saturate negate abs chansel %type writemask_x writemask_y writemask_z writemask_w %type srcimmtype execsize dstregion immaddroffset %type subregnum sampler_datatype %type urb_swizzle urb_allocate urb_used urb_complete %type math_function math_signed math_scalar %type predctrl predstate %type region region_wh indirectregion declare_srcregion; %type regtype %type directgenreg directmsgreg addrreg accreg flagreg maskreg %type maskstackreg notifyreg /* %type maskstackdepthreg */ %type statereg controlreg ipreg nullreg %type dstoperandex_typed srcarchoperandex_typed %type sendleadreg %type indirectgenreg indirectmsgreg addrparam %type mask_subreg maskstack_subreg %type declare_elementsize declare_dstregion declare_type /* %type maskstackdepth_subreg */ %type symbol_reg symbol_reg_p; %type imm32 %type dst dstoperand dstoperandex dstreg post_dst writemask %type declare_base %type directsrcoperand srcarchoperandex directsrcaccoperand %type indirectsrcoperand %type src srcimm imm32reg payload srcacc srcaccimm swizzle %type relativelocation relativelocation2 %code { #undef error #define error(l, fmt, ...) \ do { \ message(ERROR, l, fmt, ## __VA_ARGS__); \ YYERROR; \ } while(0) static void add_option(struct options *options, int option) { switch (option) { case ALIGN1: options->access_mode = BRW_ALIGN_1; break; case ALIGN16: options->access_mode = BRW_ALIGN_16; break; case SECHALF: options->compression_control |= BRW_COMPRESSION_2NDHALF; break; case COMPR: if (!IS_GENp(6)) options->compression_control |= BRW_COMPRESSION_COMPRESSED; break; case SWITCH: options->thread_control |= BRW_THREAD_SWITCH; break; case ATOMIC: options->thread_control |= BRW_THREAD_ATOMIC; break; case NODDCHK: options->dependency_control |= BRW_DEPENDENCY_NOTCHECKED; break; case NODDCLR: options->dependency_control |= BRW_DEPENDENCY_NOTCLEARED; break; case MASK_DISABLE: options->mask_control = BRW_MASK_DISABLE; break; case BREAKPOINT: options->debug_control = BRW_DEBUG_BREAKPOINT; break; case ACCWRCTRL: options->acc_wr_control = BRW_ACCUMULATOR_WRITE_ENABLE; break; case EOT: options->end_of_thread = 1; break; } } } %% simple_int: INTEGER { $$ = $1; } | MINUS INTEGER { $$ = -$2;} ; exp: INTEGER { $$ = $1; } | exp PLUS exp { $$ = $1 + $3; } | exp MINUS exp { $$ = $1 - $3; } | exp MULTIPLY exp { $$ = $1 * $3; } | exp DIVIDE exp { if ($3) $$ = $1 / $3; else YYERROR;} | MINUS exp %prec UMINUS { $$ = -$2;} | LPAREN exp RPAREN { $$ = $2; } ; ROOT: instrseq { compiled_program = $1; } ; label: STRING COLON ; declare_base: BASE EQ dstreg { $$ = $3; } ; declare_elementsize: ELEMENTSIZE EQ exp { $$ = $3; } ; declare_srcregion: %empty /* empty */ { /* XXX is this default correct?*/ memset (&$$, '\0', sizeof ($$)); $$.vert_stride = ffs(0); $$.width = BRW_WIDTH_1; $$.horiz_stride = ffs(0); } | SRCREGION EQ region { $$ = $3; } ; declare_dstregion: %empty /* empty */ { $$ = 1; } | DSTREGION EQ dstregion { $$ = $3; } ; declare_type: TYPE EQ regtype { $$ = $3.type; } ; declare_pragma: DECLARE_PRAGMA STRING declare_base declare_elementsize declare_srcregion declare_dstregion declare_type { struct declared_register reg, *found, *new_reg; reg.name = $2; reg.reg = $3; reg.element_size = $4; reg.src_region = $5; reg.dst_region = $6; reg.reg.type = $7; found = find_register($2); if (found) { if (!declared_register_equal(®, found)) error(&@1, "%s already defined and definitions " "don't agree\n", $2); free($2); // $2 has been malloc'ed by strdup } else { new_reg = malloc(sizeof(struct declared_register)); *new_reg = reg; insert_register(new_reg); } } ; reg_count_total_pragma: REG_COUNT_TOTAL_PRAGMA exp ; reg_count_payload_pragma: REG_COUNT_PAYLOAD_PRAGMA exp ; default_exec_size_pragma: DEFAULT_EXEC_SIZE_PRAGMA exp { program_defaults.execute_size = $2; } ; default_reg_type_pragma: DEFAULT_REG_TYPE_PRAGMA regtype { program_defaults.register_type = $2.type; } ; pragma: reg_count_total_pragma |reg_count_payload_pragma |default_exec_size_pragma |default_reg_type_pragma |declare_pragma ; instrseq: instrseq pragma { $$ = $1; } | instrseq instruction SEMICOLON { brw_program_add_instruction(&$1, &$2); $$ = $1; } | instruction SEMICOLON { brw_program_init(&$$); brw_program_add_instruction(&$$, &$1); } | instrseq relocatableinstruction SEMICOLON { brw_program_add_relocatable(&$1, &$2); $$ = $1; } | relocatableinstruction SEMICOLON { brw_program_init(&$$); brw_program_add_relocatable(&$$, &$1); } | instrseq SEMICOLON { $$ = $1; } | instrseq label { brw_program_add_label(&$1, $2); $$ = $1; } | label { brw_program_init(&$$); brw_program_add_label(&$$, $1); } | pragma { $$.first = NULL; $$.last = NULL; } | instrseq error SEMICOLON { $$ = $1; } ; /* 1.4.1: Instruction groups */ // binaryinstruction: Source operands cannot be accumulators // binaryaccinstruction: Source operands can be accumulators instruction: unaryinstruction | binaryinstruction | binaryaccinstruction | trinaryinstruction | sendinstruction | syncinstruction | mathinstruction | nopinstruction ; /* relocatableinstruction are instructions that needs a relocation pass */ relocatableinstruction: ifelseinstruction | loopinstruction | haltinstruction | multibranchinstruction | subroutineinstruction | jumpinstruction | breakinstruction ; ifelseinstruction: ENDIF { // for Gen4 if(IS_GENp(6)) // For gen6+. error(&@1, "should be 'ENDIF execsize relativelocation'\n"); memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; GEN(&$$)->bits1.da1.dest_horiz_stride = 1; GEN(&$$)->bits1.da1.src1_reg_file = BRW_ARCHITECTURE_REGISTER_FILE; GEN(&$$)->bits1.da1.src1_reg_type = BRW_REGISTER_TYPE_UD; } | ENDIF execsize relativelocation instoptions { // for Gen6+ /* Gen6, Gen7 bspec: predication is prohibited */ if(!IS_GENp(6)) // for gen6- error(&@1, "ENDIF Syntax error: should be 'ENDIF'\n"); memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); set_execsize(&$$, $2); $$.reloc.first_reloc_target = $3.reloc_target; $$.reloc.first_reloc_offset = $3.imm32; } | ELSE execsize relativelocation instoptions { if(!IS_GENp(6)) { // for Gen4, Gen5. gen_level < 60 /* Set the istack pop count, which must always be 1. */ $3.imm32 |= (1 << 16); memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; ip_dst.width = $2; set_instruction_dest(&$$, &ip_dst); set_instruction_src0(&$$, &ip_src, NULL); set_instruction_src1(&$$, &$3, NULL); $$.reloc.first_reloc_target = $3.reloc_target; $$.reloc.first_reloc_offset = $3.imm32; } else if(IS_GENp(6)) { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); set_execsize(&$$, $2); $$.reloc.first_reloc_target = $3.reloc_target; $$.reloc.first_reloc_offset = $3.imm32; } else { error(&@1, "'ELSE' instruction is not implemented.\n"); } } | predicate IF execsize relativelocation { /* The branch instructions require that the IP register * be the destination and first source operand, while the * offset is the second source operand. The offset is added * to the pre-incremented IP. */ if(IS_GENp(7)) /* Error in Gen7+. */ error(&@2, "IF should be 'IF execsize JIP UIP'\n"); memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); if(!IS_GENp(6)) { GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; ip_dst.width = $3; set_instruction_dest(&$$, &ip_dst); set_instruction_src0(&$$, &ip_src, NULL); set_instruction_src1(&$$, &$4, NULL); } $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; } | predicate IF execsize relativelocation relativelocation { /* for Gen7+ */ if(!IS_GENp(7)) error(&@2, "IF should be 'IF execsize relativelocation'\n"); memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); set_execsize(&$$, $3); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; $$.reloc.second_reloc_target = $5.reloc_target; $$.reloc.second_reloc_offset = $5.imm32; } ; loopinstruction: predicate WHILE execsize relativelocation instoptions { if(!IS_GENp(6)) { /* The branch instructions require that the IP register * be the destination and first source operand, while the * offset is the second source operand. The offset is added * to the pre-incremented IP. */ ip_dst.width = $3; set_instruction_dest(&$$, &ip_dst); memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; set_instruction_src0(&$$, &ip_src, NULL); set_instruction_src1(&$$, &$4, NULL); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; } else if (IS_GENp(6)) { /* Gen6 spec: dest must have the same element size as src0. dest horizontal stride must be 1. */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); set_execsize(&$$, $3); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; } else { error(&@2, "'WHILE' instruction is not implemented!\n"); } } | DO { // deprecated memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); }; haltinstruction: predicate HALT execsize relativelocation relativelocation instoptions { // for Gen6, Gen7 /* Gen6, Gen7 bspec: dst and src0 must be the null reg. */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; $$.reloc.second_reloc_target = $5.reloc_target; $$.reloc.second_reloc_offset = $5.imm32; dst_null_reg.width = $3; set_instruction_dest(&$$, &dst_null_reg); set_instruction_src0(&$$, &src_null_reg, NULL); }; multibranchinstruction: predicate BRD execsize relativelocation instoptions { /* Gen7 bspec: dest must be null. use Switch option */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); if (IS_GENp(8)) gen8_set_thread_control(GEN8(&$$), gen8_thread_control(GEN8(&$$)) | BRW_THREAD_SWITCH); else GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; dst_null_reg.width = $3; set_instruction_dest(&$$, &dst_null_reg); } | predicate BRC execsize relativelocation relativelocation instoptions { /* Gen7 bspec: dest must be null. src0 must be null. use Switch option */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); if (IS_GENp(8)) gen8_set_thread_control(GEN8(&$$), gen8_thread_control(GEN8(&$$)) | BRW_THREAD_SWITCH); else GEN(&$$)->header.thread_control |= BRW_THREAD_SWITCH; $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; $$.reloc.second_reloc_target = $5.reloc_target; $$.reloc.second_reloc_offset = $5.imm32; dst_null_reg.width = $3; set_instruction_dest(&$$, &dst_null_reg); set_instruction_src0(&$$, &src_null_reg, NULL); } ; subroutineinstruction: predicate CALL execsize dst relativelocation instoptions { /* Gen6 bspec: source, dest type should be DWORD. dest must be QWord aligned. source0 region control must be <2,2,1>. execution size must be 2. QtrCtrl is prohibited. JIP is an immediate operand, must be of type W. Gen7 bspec: source, dest type should be DWORD. dest must be QWord aligned. source0 region control must be <2,2,1>. execution size must be 2. */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); $4.type = BRW_REGISTER_TYPE_D; /* dest type should be DWORD */ $4.width = BRW_WIDTH_2; /* execution size must be 2. */ set_instruction_dest(&$$, &$4); struct src_operand src0; memset(&src0, 0, sizeof(src0)); src0.reg.type = BRW_REGISTER_TYPE_D; /* source type should be DWORD */ /* source0 region control must be <2,2,1>. */ src0.reg.hstride = 1; /*encoded 1*/ src0.reg.width = BRW_WIDTH_2; src0.reg.vstride = 2; /*encoded 2*/ set_instruction_src0(&$$, &src0, NULL); $$.reloc.first_reloc_target = $5.reloc_target; $$.reloc.first_reloc_offset = $5.imm32; } | predicate RET execsize dstoperandex src instoptions { /* Gen6, 7: source cannot be accumulator. dest must be null. src0 region control must be <2,2,1> (not specified clearly. should be same as CALL) */ memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); dst_null_reg.width = BRW_WIDTH_2; /* execution size of RET should be 2 */ set_instruction_dest(&$$, &dst_null_reg); $5.reg.type = BRW_REGISTER_TYPE_D; $5.reg.hstride = 1; /*encoded 1*/ $5.reg.width = BRW_WIDTH_2; $5.reg.vstride = 2; /*encoded 2*/ set_instruction_src0(&$$, &$5, NULL); } ; unaryinstruction: predicate unaryop conditionalmodifier saturate execsize dst srcaccimm instoptions { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_instruction_saturate(&$$, $4); $6.width = $5; set_instruction_options(&$$, $8); set_instruction_pred_cond(&$$, &$1, &$3, &@3); if (set_instruction_dest(&$$, &$6) != 0) YYERROR; if (set_instruction_src0(&$$, &$7, &@7) != 0) YYERROR; if (!IS_GENp(6) && get_type_size(GEN(&$$)->bits1.da1.dest_reg_type) * (1 << $6.width) == 64) GEN(&$$)->header.compression_control = BRW_COMPRESSION_COMPRESSED; } ; unaryop: MOV | FRC | RNDU | RNDD | RNDE | RNDZ | NOT | LZD | BFREV | CBIT | F16TO32 | F32TO16 | FBH | FBL ; // Source operands cannot be accumulators binaryinstruction: predicate binaryop conditionalmodifier saturate execsize dst src srcimm instoptions { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_instruction_saturate(&$$, $4); set_instruction_options(&$$, $9); set_instruction_pred_cond(&$$, &$1, &$3, &@3); $6.width = $5; if (set_instruction_dest(&$$, &$6) != 0) YYERROR; if (set_instruction_src0(&$$, &$7, &@7) != 0) YYERROR; if (set_instruction_src1(&$$, &$8, &@8) != 0) YYERROR; if (!IS_GENp(6) && get_type_size(GEN(&$$)->bits1.da1.dest_reg_type) * (1 << $6.width) == 64) GEN(&$$)->header.compression_control = BRW_COMPRESSION_COMPRESSED; } ; /* bspec: BFI1 should not access accumulator. */ binaryop: MUL | MAC | MACH | LINE | SAD2 | SADA2 | DP4 | DPH | DP3 | DP2 | PLN | BFI1 ; // Source operands can be accumulators binaryaccinstruction: predicate binaryaccop conditionalmodifier saturate execsize dst srcacc srcimm instoptions { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_instruction_saturate(&$$, $4); $6.width = $5; set_instruction_options(&$$, $9); set_instruction_pred_cond(&$$, &$1, &$3, &@3); if (set_instruction_dest(&$$, &$6) != 0) YYERROR; if (set_instruction_src0(&$$, &$7, &@7) != 0) YYERROR; if (set_instruction_src1(&$$, &$8, &@8) != 0) YYERROR; if (!IS_GENp(6) && get_type_size(GEN(&$$)->bits1.da1.dest_reg_type) * (1 << $6.width) == 64) GEN(&$$)->header.compression_control = BRW_COMPRESSION_COMPRESSED; } ; /* TODO: bspec says ADDC/SUBB/CMP/CMPN/SHL/BFI1 cannot use accumulator as dest. */ binaryaccop: AVG | ADD | SEL | AND | OR | XOR | SHR | SHL | ASR | CMP | CMPN | ADDC | SUBB ; trinaryop: MAD | LRP | BFE | BFI2 ; trinaryinstruction: predicate trinaryop conditionalmodifier saturate execsize dst src src src instoptions { memset(&$$, 0, sizeof($$)); set_instruction_pred_cond(&$$, &$1, &$3, &@3); set_instruction_opcode(&$$, $2); set_instruction_saturate(&$$, $4); set_instruction_options(&$$, $10); $6.width = $5; if (set_instruction_dest_three_src(&$$, &$6)) YYERROR; if (set_instruction_src0_three_src(&$$, &$7)) YYERROR; if (set_instruction_src1_three_src(&$$, &$8)) YYERROR; if (set_instruction_src2_three_src(&$$, &$9)) YYERROR; } ; sendop: SEND | SENDC ; sendinstruction: predicate sendop execsize exp post_dst payload msgtarget MSGLEN exp RETURNLEN exp instoptions { /* Send instructions are messy. The first argument is the * post destination -- the grf register that the response * starts from. The second argument is the current * destination, which is the start of the message arguments * to the shared function, and where src0 payload is loaded * to if not null. The payload is typically based on the * grf 0 thread payload of your current thread, and is * implicitly loaded if non-null. */ memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); $5.width = $3; GEN(&$$)->header.destreg__conditionalmod = $4; /* msg reg index */ set_instruction_predicate(&$$, &$1); if (set_instruction_dest(&$$, &$5) != 0) YYERROR; if (IS_GENp(6)) { struct src_operand src0; memset(&src0, 0, sizeof(src0)); src0.reg.address_mode = BRW_ADDRESS_DIRECT; if (IS_GENp(7)) src0.reg.file = BRW_GENERAL_REGISTER_FILE; else src0.reg.file = BRW_MESSAGE_REGISTER_FILE; src0.reg.type = BRW_REGISTER_TYPE_D; src0.reg.nr = $4; src0.reg.subnr = 0; set_instruction_src0(&$$, &src0, NULL); } else { if (set_instruction_src0(&$$, &$6, &@6) != 0) YYERROR; } if (IS_GENp(9)) { gen8_set_src1_reg_file(GEN8(&$$), BRW_IMMEDIATE_VALUE); gen8_set_src1_reg_type(GEN8(&$$), BRW_REGISTER_TYPE_D); gen9_set_send_extdesc(GEN8(&$$), 0); } else if (IS_GENp(8)) { gen8_set_src1_reg_file(GEN8(&$$), BRW_IMMEDIATE_VALUE); gen8_set_src1_reg_type(GEN8(&$$), BRW_REGISTER_TYPE_D); } else { GEN(&$$)->bits1.da1.src1_reg_file = BRW_IMMEDIATE_VALUE; GEN(&$$)->bits1.da1.src1_reg_type = BRW_REGISTER_TYPE_D; } if (IS_GENp(8)) { GEN8(&$$)->data[3] = GEN8(&$7)->data[3]; gen8_set_sfid(GEN8(&$$), gen8_sfid(GEN8(&$7))); gen8_set_mlen(GEN8(&$$), $9); gen8_set_rlen(GEN8(&$$), $11); gen8_set_eot(GEN8(&$$), $12.end_of_thread); } else if (IS_GENp(5)) { if (IS_GENp(6)) { GEN(&$$)->header.destreg__conditionalmod = GEN(&$7)->bits2.send_gen5.sfid; } else { GEN(&$$)->header.destreg__conditionalmod = $4; /* msg reg index */ GEN(&$$)->bits2.send_gen5.sfid = GEN(&$7)->bits2.send_gen5.sfid; GEN(&$$)->bits2.send_gen5.end_of_thread = $12.end_of_thread; } GEN(&$$)->bits3.generic_gen5 = GEN(&$7)->bits3.generic_gen5; GEN(&$$)->bits3.generic_gen5.msg_length = $9; GEN(&$$)->bits3.generic_gen5.response_length = $11; GEN(&$$)->bits3.generic_gen5.end_of_thread = $12.end_of_thread; } else { GEN(&$$)->header.destreg__conditionalmod = $4; /* msg reg index */ GEN(&$$)->bits3.generic = GEN(&$7)->bits3.generic; GEN(&$$)->bits3.generic.msg_length = $9; GEN(&$$)->bits3.generic.response_length = $11; GEN(&$$)->bits3.generic.end_of_thread = $12.end_of_thread; } } | predicate sendop execsize dst sendleadreg payload directsrcoperand instoptions { if (IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); GEN(&$$)->header.destreg__conditionalmod = $5.nr; /* msg reg index */ set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; if (set_instruction_src0(&$$, &$6, &@6) != 0) YYERROR; /* XXX is this correct? */ if (set_instruction_src1(&$$, &$7, &@7) != 0) YYERROR; } | predicate sendop execsize dst sendleadreg payload imm32reg instoptions { if (IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); if ($7.reg.type != BRW_REGISTER_TYPE_UD && $7.reg.type != BRW_REGISTER_TYPE_D && $7.reg.type != BRW_REGISTER_TYPE_V) { error (&@7, "non-int D/UD/V representation: %d," "type=%d\n", $7.reg.dw1.ud, $7.reg.type); } memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); GEN(&$$)->header.destreg__conditionalmod = $5.nr; /* msg reg index */ set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; if (set_instruction_src0(&$$, &$6, &@6) != 0) YYERROR; if (set_instruction_src1(&$$, &$7, &@7) != 0) YYERROR; } | predicate sendop execsize dst sendleadreg sndopr imm32reg instoptions { struct src_operand src0; if (!IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); if ($7.reg.type != BRW_REGISTER_TYPE_UD && $7.reg.type != BRW_REGISTER_TYPE_D && $7.reg.type != BRW_REGISTER_TYPE_V) { error(&@7,"non-int D/UD/V representation: %d," "type=%d\n", $7.reg.dw1.ud, $7.reg.type); } memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; memset(&src0, 0, sizeof(src0)); src0.reg.address_mode = BRW_ADDRESS_DIRECT; if (IS_GENp(7)) { src0.reg.file = BRW_GENERAL_REGISTER_FILE; src0.reg.type = BRW_REGISTER_TYPE_UB; } else { src0.reg.file = BRW_MESSAGE_REGISTER_FILE; src0.reg.type = BRW_REGISTER_TYPE_D; } src0.reg.nr = $5.nr; src0.reg.subnr = 0; set_instruction_src0(&$$, &src0, NULL); set_instruction_src1(&$$, &$7, NULL); if (IS_GENp(9)) { gen8_set_sfid(GEN8(&$$), $6 & EX_DESC_SFID_MASK); gen8_set_eot(GEN8(&$$), !!($6 & EX_DESC_EOT_MASK)); gen9_set_send_extdesc(GEN8(&$$), $6 & EX_DESC_FUNC_MASK); } else if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), $6 & EX_DESC_SFID_MASK); gen8_set_eot(GEN8(&$$), !!($6 & EX_DESC_EOT_MASK)); } else { GEN(&$$)->header.destreg__conditionalmod = ($6 & EX_DESC_SFID_MASK); /* SFID */ GEN(&$$)->bits3.generic_gen5.end_of_thread = !!($6 & EX_DESC_EOT_MASK); } } | predicate sendop execsize dst sendleadreg sndopr directsrcoperand instoptions { struct src_operand src0; if (!IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); if ($7.reg.file != BRW_ARCHITECTURE_REGISTER_FILE || ($7.reg.nr & 0xF0) != BRW_ARF_ADDRESS || ($7.reg.nr & 0x0F) != 0 || $7.reg.subnr != 0) { error (&@7, "scalar register must be a0.0<0;1,0>:ud\n"); } memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; memset(&src0, 0, sizeof(src0)); src0.reg.address_mode = BRW_ADDRESS_DIRECT; if (IS_GENp(7)) { src0.reg.file = BRW_GENERAL_REGISTER_FILE; src0.reg.type = BRW_REGISTER_TYPE_UB; } else { src0.reg.file = BRW_MESSAGE_REGISTER_FILE; src0.reg.type = BRW_REGISTER_TYPE_D; } src0.reg.nr = $5.nr; src0.reg.subnr = 0; set_instruction_src0(&$$, &src0, NULL); set_instruction_src1(&$$, &$7, &@7); if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), $6 & EX_DESC_SFID_MASK); gen8_set_eot(GEN8(&$$), !!($6 & EX_DESC_EOT_MASK)); gen9_set_send_extdesc(GEN8(&$$), $6 & EX_DESC_FUNC_MASK); } else if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), $6 & EX_DESC_SFID_MASK); gen8_set_eot(GEN8(&$$), !!($6 & EX_DESC_EOT_MASK)); } else { GEN(&$$)->header.destreg__conditionalmod = ($6 & EX_DESC_SFID_MASK); /* SFID */ GEN(&$$)->bits3.generic_gen5.end_of_thread = !!($6 & EX_DESC_EOT_MASK); } } | predicate sendop execsize dst sendleadreg payload sndopr imm32reg instoptions { if (IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); if ($8.reg.type != BRW_REGISTER_TYPE_UD && $8.reg.type != BRW_REGISTER_TYPE_D && $8.reg.type != BRW_REGISTER_TYPE_V) { error(&@8, "non-int D/UD/V representation: %d," "type=%d\n", $8.reg.dw1.ud, $8.reg.type); } memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); GEN(&$$)->header.destreg__conditionalmod = $5.nr; /* msg reg index */ set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; if (set_instruction_src0(&$$, &$6, &@6) != 0) YYERROR; if (set_instruction_src1(&$$, &$8, &@8) != 0) YYERROR; if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = ($7 & EX_DESC_SFID_MASK); GEN(&$$)->bits3.generic_gen5.end_of_thread = !!($7 & EX_DESC_EOT_MASK); } } | predicate sendop execsize dst sendleadreg payload exp directsrcoperand instoptions { if (IS_GENp(6)) error(&@2, "invalid syntax for send on gen6+\n"); memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); GEN(&$$)->header.destreg__conditionalmod = $5.nr; /* msg reg index */ set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; if (set_instruction_src0(&$$, &$6, &@6) != 0) YYERROR; /* XXX is this correct? */ if (set_instruction_src1(&$$, &$8, &@8) != 0) YYERROR; if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = $7; } } ; sndopr: exp %prec SNDOPR { $$ = $1; } ; jumpinstruction: predicate JMPI execsize relativelocation2 { /* The jump instruction requires that the IP register * be the destination and first source operand, while the * offset is the second source operand. The next instruction * is the post-incremented IP plus the offset. */ memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); if(advanced_flag) { if (IS_GENp(8)) gen8_set_mask_control(GEN8(&$$), BRW_MASK_DISABLE); else GEN(&$$)->header.mask_control = BRW_MASK_DISABLE; } set_instruction_predicate(&$$, &$1); ip_dst.width = BRW_WIDTH_1; set_instruction_dest(&$$, &ip_dst); set_instruction_src0(&$$, &ip_src, NULL); set_instruction_src1(&$$, &$4, NULL); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; } ; mathinstruction: predicate MATH_INST execsize dst src srcimm math_function instoptions { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); if (IS_GENp(8)) gen8_set_math_function(GEN8(&$$), $7); else GEN(&$$)->header.destreg__conditionalmod = $7; set_instruction_options(&$$, $8); set_instruction_predicate(&$$, &$1); $4.width = $3; if (set_instruction_dest(&$$, &$4) != 0) YYERROR; if (set_instruction_src0(&$$, &$5, &@5) != 0) YYERROR; if (set_instruction_src1(&$$, &$6, &@6) != 0) YYERROR; } ; breakinstruction: predicate breakop execsize relativelocation relativelocation instoptions { // for Gen6, Gen7 memset(&$$, 0, sizeof($$)); set_instruction_predicate(&$$, &$1); set_instruction_opcode(&$$, $2); set_execsize(&$$, $3); $$.reloc.first_reloc_target = $4.reloc_target; $$.reloc.first_reloc_offset = $4.imm32; $$.reloc.second_reloc_target = $5.reloc_target; $$.reloc.second_reloc_offset = $5.imm32; } ; breakop: BREAK | CONT ; /* maskpushop: MSAVE | PUSH ; */ syncinstruction: predicate WAIT notifyreg { struct brw_reg notify_dst; struct src_operand notify_src; memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $2); set_direct_dst_operand(¬ify_dst, &$3, BRW_REGISTER_TYPE_D); notify_dst.width = BRW_WIDTH_1; set_instruction_dest(&$$, ¬ify_dst); set_direct_src_operand(¬ify_src, &$3, BRW_REGISTER_TYPE_D); set_instruction_src0(&$$, ¬ify_src, NULL); set_instruction_src1(&$$, &src_null_reg, NULL); } ; nopinstruction: NOP { memset(&$$, 0, sizeof($$)); set_instruction_opcode(&$$, $1); }; /* XXX! */ payload: directsrcoperand ; post_dst: dst ; msgtarget: NULL_TOKEN { if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), BRW_SFID_NULL); gen8_set_header_present(GEN8(&$$), 0); } else if (IS_GENp(5)) { GEN(&$$)->bits2.send_gen5.sfid= BRW_SFID_NULL; GEN(&$$)->bits3.generic_gen5.header_present = 0; /* ??? */ } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_NULL; } } | SAMPLER LPAREN INTEGER COMMA INTEGER COMMA sampler_datatype RPAREN { if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), BRW_SFID_SAMPLER); gen8_set_header_present(GEN8(&$$), 1); /* ??? */ gen8_set_binding_table_index(GEN8(&$$), $3); gen8_set_sampler(GEN8(&$$), $5); gen8_set_sampler_simd_mode(GEN8(&$$), 2); /* SIMD16 */ } else if (IS_GENp(7)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_SAMPLER; GEN(&$$)->bits3.generic_gen5.header_present = 1; /* ??? */ GEN(&$$)->bits3.sampler_gen7.binding_table_index = $3; GEN(&$$)->bits3.sampler_gen7.sampler = $5; GEN(&$$)->bits3.sampler_gen7.simd_mode = 2; /* SIMD16, maybe we should add a new parameter */ } else if (IS_GENp(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_SAMPLER; GEN(&$$)->bits3.generic_gen5.header_present = 1; /* ??? */ GEN(&$$)->bits3.sampler_gen5.binding_table_index = $3; GEN(&$$)->bits3.sampler_gen5.sampler = $5; GEN(&$$)->bits3.sampler_gen5.simd_mode = 2; /* SIMD16, maybe we should add a new parameter */ } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_SAMPLER; GEN(&$$)->bits3.sampler.binding_table_index = $3; GEN(&$$)->bits3.sampler.sampler = $5; switch ($7) { case TYPE_F: GEN(&$$)->bits3.sampler.return_format = BRW_SAMPLER_RETURN_FORMAT_FLOAT32; break; case TYPE_UD: GEN(&$$)->bits3.sampler.return_format = BRW_SAMPLER_RETURN_FORMAT_UINT32; break; case TYPE_D: GEN(&$$)->bits3.sampler.return_format = BRW_SAMPLER_RETURN_FORMAT_SINT32; break; } } } | MATH math_function saturate math_signed math_scalar { if (IS_GENp(6)) { error (&@1, "Gen6+ doesn't have math function\n"); } else if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_MATH; GEN(&$$)->bits3.generic_gen5.header_present = 0; GEN(&$$)->bits3.math_gen5.function = $2; set_instruction_saturate(&$$, $3); GEN(&$$)->bits3.math_gen5.int_type = $4; GEN(&$$)->bits3.math_gen5.precision = BRW_MATH_PRECISION_FULL; GEN(&$$)->bits3.math_gen5.data_type = $5; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_MATH; GEN(&$$)->bits3.math.function = $2; set_instruction_saturate(&$$, $3); GEN(&$$)->bits3.math.int_type = $4; GEN(&$$)->bits3.math.precision = BRW_MATH_PRECISION_FULL; GEN(&$$)->bits3.math.data_type = $5; } } | GATEWAY { if (IS_GENp(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_MESSAGE_GATEWAY; GEN(&$$)->bits3.generic_gen5.header_present = 0; /* ??? */ } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_MESSAGE_GATEWAY; } } | READ LPAREN INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER RPAREN { if (IS_GENp(9)) { if ($5 != 0 && $5 != GEN6_SFID_DATAPORT_RENDER_CACHE && $5 != GEN7_SFID_DATAPORT_DATA_CACHE && $5 != HSW_SFID_DATAPORT_DATA_CACHE1 && $5 != SKL_SFID_DATAPORT_DCR0 && $5 != SKL_SFID_DATAPORT_DATA_CACHE2) { error (&@9, "error: wrong cache type\n"); } if ($5 == 0) gen8_set_sfid(GEN8(&$$), HSW_SFID_DATAPORT_DATA_CACHE1); else gen8_set_sfid(GEN8(&$$), $5); gen8_set_header_present(GEN8(&$$), 1); gen8_set_dp_binding_table_index(GEN8(&$$), $3); gen8_set_dp_message_control(GEN8(&$$), $7); gen8_set_dp_message_type(GEN8(&$$), $9); gen8_set_dp_category(GEN8(&$$), 0); } else if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), GEN6_SFID_DATAPORT_SAMPLER_CACHE); gen8_set_header_present(GEN8(&$$), 1); gen8_set_dp_binding_table_index(GEN8(&$$), $3); gen8_set_dp_message_control(GEN8(&$$), $7); gen8_set_dp_message_type(GEN8(&$$), $9); gen8_set_dp_category(GEN8(&$$), 0); } else if (IS_GENx(7)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_SAMPLER_CACHE; GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.gen7_dp.binding_table_index = $3; GEN(&$$)->bits3.gen7_dp.msg_control = $7; GEN(&$$)->bits3.gen7_dp.msg_type = $9; } else if (IS_GENx(6)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_SAMPLER_CACHE; GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.gen6_dp_sampler_const_cache.binding_table_index = $3; GEN(&$$)->bits3.gen6_dp_sampler_const_cache.msg_control = $7; GEN(&$$)->bits3.gen6_dp_sampler_const_cache.msg_type = $9; } else if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_DATAPORT_READ; GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.dp_read_gen5.binding_table_index = $3; GEN(&$$)->bits3.dp_read_gen5.target_cache = $5; GEN(&$$)->bits3.dp_read_gen5.msg_control = $7; GEN(&$$)->bits3.dp_read_gen5.msg_type = $9; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_DATAPORT_READ; GEN(&$$)->bits3.dp_read.binding_table_index = $3; GEN(&$$)->bits3.dp_read.target_cache = $5; GEN(&$$)->bits3.dp_read.msg_control = $7; GEN(&$$)->bits3.dp_read.msg_type = $9; } } | WRITE LPAREN INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER RPAREN { if (IS_GENp(8)) { if (IS_GENp(9)) { if ($9 != 0 && $9 != GEN6_SFID_DATAPORT_RENDER_CACHE && $9 != GEN7_SFID_DATAPORT_DATA_CACHE && $9 != HSW_SFID_DATAPORT_DATA_CACHE1 && $9 != SKL_SFID_DATAPORT_DATA_CACHE2) { error (&@9, "error: wrong cache type\n"); } } else { if ($9 != 0 && $9 != GEN6_SFID_DATAPORT_RENDER_CACHE && $9 != GEN7_SFID_DATAPORT_DATA_CACHE && $9 != HSW_SFID_DATAPORT_DATA_CACHE1) { error (&@9, "error: wrong cache type\n"); } } if ($9 == 0) gen8_set_sfid(GEN8(&$$), GEN6_SFID_DATAPORT_RENDER_CACHE); else gen8_set_sfid(GEN8(&$$), $9); gen8_set_header_present(GEN8(&$$), 1); gen8_set_dp_binding_table_index(GEN8(&$$), $3); gen8_set_dp_message_control(GEN8(&$$), $5); gen8_set_dp_message_type(GEN8(&$$), $7); gen8_set_dp_category(GEN8(&$$), 0); } else if (IS_GENx(7)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_RENDER_CACHE; GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.gen7_dp.binding_table_index = $3; GEN(&$$)->bits3.gen7_dp.msg_control = $5; GEN(&$$)->bits3.gen7_dp.msg_type = $7; } else if (IS_GENx(6)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_RENDER_CACHE; /* Sandybridge supports headerlesss message for render target write. * Currently the GFX assembler doesn't support it. so the program must provide * message header */ GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.gen6_dp.binding_table_index = $3; GEN(&$$)->bits3.gen6_dp.msg_control = $5; GEN(&$$)->bits3.gen6_dp.msg_type = $7; GEN(&$$)->bits3.gen6_dp.send_commit_msg = $9; } else if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_DATAPORT_WRITE; GEN(&$$)->bits3.generic_gen5.header_present = 1; GEN(&$$)->bits3.dp_write_gen5.binding_table_index = $3; GEN(&$$)->bits3.dp_write_gen5.last_render_target = ($5 & 0x8) >> 3; GEN(&$$)->bits3.dp_write_gen5.msg_control = $5 & 0x7; GEN(&$$)->bits3.dp_write_gen5.msg_type = $7; GEN(&$$)->bits3.dp_write_gen5.send_commit_msg = $9; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_DATAPORT_WRITE; GEN(&$$)->bits3.dp_write.binding_table_index = $3; /* The msg control field of brw_struct.h is split into * msg control and last_render_target, even though * last_render_target isn't common to all write messages. */ GEN(&$$)->bits3.dp_write.last_render_target = ($5 & 0x8) >> 3; GEN(&$$)->bits3.dp_write.msg_control = $5 & 0x7; GEN(&$$)->bits3.dp_write.msg_type = $7; GEN(&$$)->bits3.dp_write.send_commit_msg = $9; } } | WRITE LPAREN INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER RPAREN { if (IS_GENp(8)) { if (IS_GENp(9)) { if ($9 != 0 && $9 != GEN6_SFID_DATAPORT_RENDER_CACHE && $9 != GEN7_SFID_DATAPORT_DATA_CACHE && $9 != HSW_SFID_DATAPORT_DATA_CACHE1 && $9 != SKL_SFID_DATAPORT_DATA_CACHE2) { error (&@9, "error: wrong cache type\n"); } } else { if ($9 != 0 && $9 != GEN6_SFID_DATAPORT_RENDER_CACHE && $9 != GEN7_SFID_DATAPORT_DATA_CACHE && $9 != HSW_SFID_DATAPORT_DATA_CACHE1) { error (&@9, "error: wrong cache type\n"); } } if ($9 == 0) gen8_set_sfid(GEN8(&$$), GEN6_SFID_DATAPORT_RENDER_CACHE); else gen8_set_sfid(GEN8(&$$), $9); gen8_set_header_present(GEN8(&$$), ($11 != 0)); gen8_set_dp_binding_table_index(GEN8(&$$), $3); gen8_set_dp_message_control(GEN8(&$$), $5); gen8_set_dp_message_type(GEN8(&$$), $7); gen8_set_dp_category(GEN8(&$$), 0); } else if (IS_GENx(7)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_RENDER_CACHE; GEN(&$$)->bits3.generic_gen5.header_present = ($11 != 0); GEN(&$$)->bits3.gen7_dp.binding_table_index = $3; GEN(&$$)->bits3.gen7_dp.msg_control = $5; GEN(&$$)->bits3.gen7_dp.msg_type = $7; } else if (IS_GENx(6)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_DATAPORT_RENDER_CACHE; GEN(&$$)->bits3.generic_gen5.header_present = ($11 != 0); GEN(&$$)->bits3.gen6_dp.binding_table_index = $3; GEN(&$$)->bits3.gen6_dp.msg_control = $5; GEN(&$$)->bits3.gen6_dp.msg_type = $7; GEN(&$$)->bits3.gen6_dp.send_commit_msg = $9; } else if (IS_GENx(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_DATAPORT_WRITE; GEN(&$$)->bits3.generic_gen5.header_present = ($11 != 0); GEN(&$$)->bits3.dp_write_gen5.binding_table_index = $3; GEN(&$$)->bits3.dp_write_gen5.last_render_target = ($5 & 0x8) >> 3; GEN(&$$)->bits3.dp_write_gen5.msg_control = $5 & 0x7; GEN(&$$)->bits3.dp_write_gen5.msg_type = $7; GEN(&$$)->bits3.dp_write_gen5.send_commit_msg = $9; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_DATAPORT_WRITE; GEN(&$$)->bits3.dp_write.binding_table_index = $3; /* The msg control field of brw_struct.h is split into * msg control and last_render_target, even though * last_render_target isn't common to all write messages. */ GEN(&$$)->bits3.dp_write.last_render_target = ($5 & 0x8) >> 3; GEN(&$$)->bits3.dp_write.msg_control = $5 & 0x7; GEN(&$$)->bits3.dp_write.msg_type = $7; GEN(&$$)->bits3.dp_write.send_commit_msg = $9; } } | URB INTEGER urb_swizzle urb_allocate urb_used urb_complete { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_URB; if (IS_GENp(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_URB; GEN(&$$)->bits3.generic_gen5.header_present = 1; set_instruction_opcode(&$$, BRW_URB_OPCODE_WRITE); GEN(&$$)->bits3.urb_gen5.offset = $2; GEN(&$$)->bits3.urb_gen5.swizzle_control = $3; GEN(&$$)->bits3.urb_gen5.pad = 0; GEN(&$$)->bits3.urb_gen5.allocate = $4; GEN(&$$)->bits3.urb_gen5.used = $5; GEN(&$$)->bits3.urb_gen5.complete = $6; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_URB; set_instruction_opcode(&$$, BRW_URB_OPCODE_WRITE); GEN(&$$)->bits3.urb.offset = $2; GEN(&$$)->bits3.urb.swizzle_control = $3; GEN(&$$)->bits3.urb.pad = 0; GEN(&$$)->bits3.urb.allocate = $4; GEN(&$$)->bits3.urb.used = $5; GEN(&$$)->bits3.urb.complete = $6; } } | THREAD_SPAWNER LPAREN INTEGER COMMA INTEGER COMMA INTEGER RPAREN { if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), BRW_SFID_THREAD_SPAWNER); gen8_set_header_present(GEN8(&$$), 0); /* Must be 0 */ gen8_set_ts_opcode(GEN8(&$$), $3); gen8_set_ts_request_type(GEN8(&$$), $5); gen8_set_ts_resource_select(GEN8(&$$), $7); } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_THREAD_SPAWNER; if (IS_GENp(5)) { GEN(&$$)->bits2.send_gen5.sfid = BRW_SFID_THREAD_SPAWNER; GEN(&$$)->bits3.generic_gen5.header_present = 0; GEN(&$$)->bits3.thread_spawner_gen5.opcode = $3; GEN(&$$)->bits3.thread_spawner_gen5.requester_type = $5; GEN(&$$)->bits3.thread_spawner_gen5.resource_select = $7; } else { GEN(&$$)->bits3.generic.msg_target = BRW_SFID_THREAD_SPAWNER; GEN(&$$)->bits3.thread_spawner.opcode = $3; GEN(&$$)->bits3.thread_spawner.requester_type = $5; GEN(&$$)->bits3.thread_spawner.resource_select = $7; } } } | VME LPAREN INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER RPAREN { GEN(&$$)->bits3.generic.msg_target = GEN6_SFID_VME; if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), GEN6_SFID_VME); gen8_set_header_present(GEN8(&$$), 1); /* Must be 1 */ gen8_set_vme_binding_table_index(GEN8(&$$), $3); gen8_set_vme_message_type(GEN8(&$$), $9); } else if (IS_GENp(6)) { GEN(&$$)->bits2.send_gen5.sfid = GEN6_SFID_VME; GEN(&$$)->bits3.vme_gen6.binding_table_index = $3; GEN(&$$)->bits3.vme_gen6.search_path_index = $5; GEN(&$$)->bits3.vme_gen6.lut_subindex = $7; GEN(&$$)->bits3.vme_gen6.message_type = $9; GEN(&$$)->bits3.generic_gen5.header_present = 1; } else { error (&@1, "Gen6- doesn't have vme function\n"); } } | CRE LPAREN INTEGER COMMA INTEGER RPAREN { if (IS_GENp(8)) { gen8_set_sfid(GEN8(&$$), HSW_SFID_CRE); gen8_set_header_present(GEN8(&$$), 1); /* Must be 1 */ gen8_set_cre_binding_table_index(GEN8(&$$), $3); gen8_set_cre_message_type(GEN8(&$$), $5); } else { if (gen_level < 75) error (&@1, "Below Gen7.5 doesn't have CRE function\n"); GEN(&$$)->bits3.generic.msg_target = HSW_SFID_CRE; GEN(&$$)->bits2.send_gen5.sfid = HSW_SFID_CRE; GEN(&$$)->bits3.cre_gen75.binding_table_index = $3; GEN(&$$)->bits3.cre_gen75.message_type = $5; GEN(&$$)->bits3.generic_gen5.header_present = 1; } } | DATA_PORT LPAREN INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER COMMA INTEGER RPAREN { if (IS_GENp(8)) { if ($3 != GEN6_SFID_DATAPORT_SAMPLER_CACHE && $3 != GEN6_SFID_DATAPORT_RENDER_CACHE && $3 != GEN6_SFID_DATAPORT_CONSTANT_CACHE && $3 != GEN7_SFID_DATAPORT_DATA_CACHE && $3 != HSW_SFID_DATAPORT_DATA_CACHE1) { error (&@3, "error: wrong cache type\n"); } gen8_set_sfid(GEN8(&$$), $3); gen8_set_header_present(GEN8(&$$), ($13 != 0)); gen8_set_dp_binding_table_index(GEN8(&$$), $9); gen8_set_dp_message_control(GEN8(&$$), $7); gen8_set_dp_message_type(GEN8(&$$), $5); gen8_set_dp_category(GEN8(&$$), $11); } else { GEN(&$$)->bits2.send_gen5.sfid = $3; GEN(&$$)->bits3.generic_gen5.header_present = ($13 != 0); if (IS_GENp(7)) { if ($3 != GEN6_SFID_DATAPORT_SAMPLER_CACHE && $3 != GEN6_SFID_DATAPORT_RENDER_CACHE && $3 != GEN6_SFID_DATAPORT_CONSTANT_CACHE && $3 != GEN7_SFID_DATAPORT_DATA_CACHE) { error (&@3, "error: wrong cache type\n"); } GEN(&$$)->bits3.gen7_dp.category = $11; GEN(&$$)->bits3.gen7_dp.binding_table_index = $9; GEN(&$$)->bits3.gen7_dp.msg_control = $7; GEN(&$$)->bits3.gen7_dp.msg_type = $5; } else if (IS_GENx(6)) { if ($3 != GEN6_SFID_DATAPORT_SAMPLER_CACHE && $3 != GEN6_SFID_DATAPORT_RENDER_CACHE && $3 != GEN6_SFID_DATAPORT_CONSTANT_CACHE) { error (&@3, "error: wrong cache type\n"); } GEN(&$$)->bits3.gen6_dp.send_commit_msg = $11; GEN(&$$)->bits3.gen6_dp.binding_table_index = $9; GEN(&$$)->bits3.gen6_dp.msg_control = $7; GEN(&$$)->bits3.gen6_dp.msg_type = $5; } else if (!IS_GENp(5)) { error (&@1, "Gen6- doesn't support data port for sampler/render/constant/data cache\n"); } } } ; urb_allocate: ALLOCATE { $$ = 1; } | %empty /* empty */ { $$ = 0; } ; urb_used: USED { $$ = 1; } | %empty /* empty */ { $$ = 0; } ; urb_complete: COMPLETE { $$ = 1; } | %empty /* empty */ { $$ = 0; } ; urb_swizzle: TRANSPOSE { $$ = BRW_URB_SWIZZLE_TRANSPOSE; } | INTERLEAVE { $$ = BRW_URB_SWIZZLE_INTERLEAVE; } | %empty /* empty */ { $$ = BRW_URB_SWIZZLE_NONE; } ; sampler_datatype: TYPE_F | TYPE_UD | TYPE_D ; math_function: INV | LOG | EXP | SQRT | POW | SIN | COS | SINCOS | INTDIV | INTMOD | INTDIVMOD | RSQ ; math_signed: %empty /* empty */ { $$ = 0; } | SIGNED { $$ = 1; } ; math_scalar: %empty /* empty */ { $$ = 0; } | SCALAR { $$ = 1; } ; /* 1.4.2: Destination register */ dst: dstoperand | dstoperandex ; dstoperand: symbol_reg dstregion { $$ = $1.reg; $$.hstride = resolve_dst_region(&$1, $2); } | dstreg dstregion writemask regtype { /* Returns an instruction with just the destination register * filled in. */ $$ = $1; $$.hstride = resolve_dst_region(NULL, $2); $$.dw1.bits.writemask = $3.dw1.bits.writemask; $$.type = $4.type; } ; /* The dstoperandex returns an instruction with just the destination register * filled in. */ dstoperandex: dstoperandex_typed dstregion regtype { $$ = $1; $$.hstride = resolve_dst_region(NULL, $2); $$.type = $3.type; } | maskstackreg { $$ = $1; $$.hstride = 1; $$.type = BRW_REGISTER_TYPE_UW; } | controlreg { $$ = $1; $$.hstride = 1; $$.type = BRW_REGISTER_TYPE_UD; } | ipreg { $$ = $1; $$.hstride = 1; $$.type = BRW_REGISTER_TYPE_UD; } | nullreg dstregion regtype { $$ = $1; $$.hstride = resolve_dst_region(NULL, $2); $$.type = $3.type; } ; dstoperandex_typed: accreg | flagreg | addrreg | maskreg ; symbol_reg: STRING %prec STR_SYMBOL_REG { struct declared_register *dcl_reg = find_register($1); if (dcl_reg == NULL) error(&@1, "can't find register %s\n", $1); memcpy(&$$, dcl_reg, sizeof(*dcl_reg)); free($1); // $1 has been malloc'ed by strdup } | symbol_reg_p { $$=$1; } ; symbol_reg_p: STRING LPAREN exp RPAREN { struct declared_register *dcl_reg = find_register($1); if (dcl_reg == NULL) error(&@1, "can't find register %s\n", $1); memcpy(&$$, dcl_reg, sizeof(*dcl_reg)); $$.reg.nr += $3; free($1); } | STRING LPAREN exp COMMA exp RPAREN { struct declared_register *dcl_reg = find_register($1); if (dcl_reg == NULL) error(&@1, "can't find register %s\n", $1); memcpy(&$$, dcl_reg, sizeof(*dcl_reg)); $$.reg.nr += $3; if(advanced_flag) { int size = get_type_size(dcl_reg->reg.type); $$.reg.nr += ($$.reg.subnr + $5) / (32 / size); $$.reg.subnr = ($$.reg.subnr + $5) % (32 / size); } else { $$.reg.nr += ($$.reg.subnr + $5) / 32; $$.reg.subnr = ($$.reg.subnr + $5) % 32; } free($1); } ; /* Returns a partially complete destination register consisting of the * direct or indirect register addressing fields, but not stride or writemask. */ dstreg: directgenreg { $$ = $1; $$.address_mode = BRW_ADDRESS_DIRECT; } | directmsgreg { $$ = $1; $$.address_mode = BRW_ADDRESS_DIRECT; } | indirectgenreg { $$ = $1; $$.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER; } | indirectmsgreg { $$ = $1; $$.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER; } ; /* 1.4.3: Source register */ srcaccimm: srcacc | imm32reg ; srcacc: directsrcaccoperand | indirectsrcoperand ; srcimm: directsrcoperand | indirectsrcoperand| imm32reg ; imm32reg: imm32 srcimmtype { union { int i; float f; } intfloat; uint32_t d; switch ($2) { case BRW_REGISTER_TYPE_UD: case BRW_REGISTER_TYPE_D: case BRW_REGISTER_TYPE_V: case BRW_REGISTER_TYPE_VF: switch ($1.r) { case imm32_d: d = $1.u.d; break; default: error (&@2, "non-int D/UD/V/VF representation: %d,type=%d\n", $1.r, $2); } break; case BRW_REGISTER_TYPE_UW: case BRW_REGISTER_TYPE_W: switch ($1.r) { case imm32_d: d = $1.u.d; break; default: error (&@2, "non-int W/UW representation\n"); } d &= 0xffff; d |= d << 16; break; case BRW_REGISTER_TYPE_F: switch ($1.r) { case imm32_f: intfloat.f = $1.u.f; break; case imm32_d: intfloat.f = (float) $1.u.d; break; default: error (&@2, "non-float F representation\n"); } d = intfloat.i; break; #if 0 case BRW_REGISTER_TYPE_VF: fprintf (stderr, "Immediate type VF not supported yet\n"); YYERROR; #endif default: error(&@2, "unknown immediate type %d\n", $2); } memset (&$$, '\0', sizeof ($$)); $$.reg.file = BRW_IMMEDIATE_VALUE; $$.reg.type = $2; $$.reg.dw1.ud = d; } ; directsrcaccoperand: directsrcoperand | accreg region regtype { set_direct_src_operand(&$$, &$1, $3.type); $$.reg.vstride = $2.vert_stride; $$.reg.width = $2.width; $$.reg.hstride = $2.horiz_stride; $$.default_region = $2.is_default; } ; /* Returns a source operand in the src0 fields of an instruction. */ srcarchoperandex: srcarchoperandex_typed region regtype { memset (&$$, '\0', sizeof ($$)); $$.reg.file = $1.file; $$.reg.type = $3.type; $$.reg.subnr = $1.subnr; $$.reg.nr = $1.nr; $$.reg.vstride = $2.vert_stride; $$.reg.width = $2.width; $$.reg.hstride = $2.horiz_stride; $$.default_region = $2.is_default; $$.reg.negate = 0; $$.reg.abs = 0; } | maskstackreg { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UB); } | controlreg { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); } /* | statereg { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); }*/ | notifyreg { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); } | ipreg { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); } | nullreg region regtype { if ($3.is_default) { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); } else { set_direct_src_operand(&$$, &$1, $3.type); } $$.default_region = 1; } ; srcarchoperandex_typed: flagreg | addrreg | maskreg ; sendleadreg: symbol_reg { memset (&$$, '\0', sizeof ($$)); $$.file = $1.reg.file; $$.nr = $1.reg.nr; $$.subnr = $1.reg.subnr; } | directgenreg | directmsgreg ; src: directsrcoperand | indirectsrcoperand ; directsrcoperand: negate abs symbol_reg region regtype { memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_DIRECT; $$.reg.file = $3.reg.file; $$.reg.nr = $3.reg.nr; $$.reg.subnr = $3.reg.subnr; if ($5.is_default) { $$.reg.type = $3.reg.type; } else { $$.reg.type = $5.type; } if ($4.is_default) { $$.reg.vstride = $3.src_region.vert_stride; $$.reg.width = $3.src_region.width; $$.reg.hstride = $3.src_region.horiz_stride; } else { $$.reg.vstride = $4.vert_stride; $$.reg.width = $4.width; $$.reg.hstride = $4.horiz_stride; } $$.reg.negate = $1; $$.reg.abs = $2; } | statereg region regtype { if($2.is_default ==1 && $3.is_default == 1) { set_direct_src_operand(&$$, &$1, BRW_REGISTER_TYPE_UD); } else{ memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_DIRECT; $$.reg.file = $1.file; $$.reg.nr = $1.nr; $$.reg.subnr = $1.subnr; $$.reg.vstride = $2.vert_stride; $$.reg.width = $2.width; $$.reg.hstride = $2.horiz_stride; $$.reg.type = $3.type; } } | negate abs directgenreg region swizzle regtype { memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_DIRECT; $$.reg.file = $3.file; $$.reg.nr = $3.nr; $$.reg.subnr = $3.subnr; $$.reg.type = $6.type; $$.reg.vstride = $4.vert_stride; $$.reg.width = $4.width; $$.reg.hstride = $4.horiz_stride; $$.default_region = $4.is_default; $$.reg.negate = $1; $$.reg.abs = $2; $$.reg.dw1.bits.swizzle = $5.reg.dw1.bits.swizzle; } | srcarchoperandex ; indirectsrcoperand: negate abs indirectgenreg indirectregion regtype swizzle { memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER; $$.reg.file = $3.file; $$.reg.subnr = $3.subnr; $$.reg.dw1.bits.indirect_offset = $3.dw1.bits.indirect_offset; $$.reg.type = $5.type; $$.reg.vstride = $4.vert_stride; $$.reg.width = $4.width; $$.reg.hstride = $4.horiz_stride; $$.reg.negate = $1; $$.reg.abs = $2; $$.reg.dw1.bits.swizzle = $6.reg.dw1.bits.swizzle; } ; /* 1.4.4: Address Registers */ /* Returns a partially-completed struct brw_reg consisting of the address * register fields for register-indirect access. */ addrparam: addrreg COMMA immaddroffset { if ($3 < -512 || $3 > 511) error(&@3, "Address immediate offset %d out of range\n", $3); memset (&$$, '\0', sizeof ($$)); $$.subnr = $1.subnr; $$.dw1.bits.indirect_offset = $3; } | addrreg { memset (&$$, '\0', sizeof ($$)); $$.subnr = $1.subnr; $$.dw1.bits.indirect_offset = 0; } ; /* The immaddroffset provides an immediate offset value added to the addresses * from the address register in register-indirect register access. */ immaddroffset: %empty /* empty */ { $$ = 0; } | exp ; /* 1.4.5: Register files and register numbers */ subregnum: DOT exp { $$ = $2; } | %empty %prec SUBREGNUM { /* Default to subreg 0 if unspecified. */ $$ = 0; } ; directgenreg: GENREG subregnum { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_GENERAL_REGISTER_FILE; $$.nr = $1; $$.subnr = $2; } ; indirectgenreg: GENREGFILE LSQUARE addrparam RSQUARE { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_GENERAL_REGISTER_FILE; $$.subnr = $3.subnr; $$.dw1.bits.indirect_offset = $3.dw1.bits.indirect_offset; } ; directmsgreg: MSGREG subregnum { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_MESSAGE_REGISTER_FILE; $$.nr = $1; $$.subnr = $2; } ; indirectmsgreg: MSGREGFILE LSQUARE addrparam RSQUARE { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_MESSAGE_REGISTER_FILE; $$.subnr = $3.subnr; $$.dw1.bits.indirect_offset = $3.dw1.bits.indirect_offset; } ; addrreg: ADDRESSREG subregnum { if ($1 != 0) error(&@2, "address register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_ADDRESS | $1; $$.subnr = $2; } ; accreg: ACCREG subregnum { if ($1 > 1) error(&@1, "accumulator register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_ACCUMULATOR | $1; $$.subnr = $2; } ; flagreg: FLAGREG subregnum { if ((!IS_GENp(7) && $1 > 0) || (IS_GENp(7) && $1 > 1)) { error(&@2, "flag register number %d out of range\n", $1); } if ($2 > 1) error(&@2, "flag subregister number %d out of range\n", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_FLAG | $1; $$.subnr = $2; } ; maskreg: MASKREG subregnum { if ($1 > 0) error(&@1, "mask register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_MASK; $$.subnr = $2; } | mask_subreg { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_MASK; $$.subnr = $1; } ; mask_subreg: AMASK | IMASK | LMASK | CMASK ; maskstackreg: MASKSTACKREG subregnum { if ($1 > 0) error(&@1, "mask stack register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_MASK_STACK; $$.subnr = $2; } | maskstack_subreg { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_MASK_STACK; $$.subnr = $1; } ; maskstack_subreg: IMS | LMS ; /* maskstackdepthreg: MASKSTACKDEPTHREG subregnum { if ($1 > 0) error(&@1, "mask stack register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.reg_file = BRW_ARCHITECTURE_REGISTER_FILE; $$.reg_nr = BRW_ARF_MASK_STACK_DEPTH; $$.subreg_nr = $2; } | maskstackdepth_subreg { memset (&$$, '\0', sizeof ($$)); $$.reg_file = BRW_ARCHITECTURE_REGISTER_FILE; $$.reg_nr = BRW_ARF_MASK_STACK_DEPTH; $$.subreg_nr = $1; } ; maskstackdepth_subreg: IMSD | LMSD ; */ notifyreg: NOTIFYREG regtype { int num_notifyreg = (IS_GENp(6)) ? 3 : 2; if ($1 > num_notifyreg) error(&@1, "notification register number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; if (IS_GENp(6)) { $$.nr = BRW_ARF_NOTIFICATION_COUNT; $$.subnr = $1; } else { $$.nr = BRW_ARF_NOTIFICATION_COUNT | $1; $$.subnr = 0; } } /* | NOTIFYREG regtype { if ($1 > 1) { fprintf(stderr, "notification register number %d out of range", $1); YYERROR; } memset (&$$, '\0', sizeof ($$)); $$.reg_file = BRW_ARCHITECTURE_REGISTER_FILE; $$.reg_nr = BRW_ARF_NOTIFICATION_COUNT; $$.subreg_nr = 0; } */ ; statereg: STATEREG subregnum { if ($1 > 0) error(&@1, "state register number %d out of range", $1); if ($2 > 1) error(&@2, "state subregister number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_STATE | $1; $$.subnr = $2; } ; controlreg: CONTROLREG subregnum { if ($1 > 0) error(&@1, "control register number %d out of range", $1); if ($2 > 2) error(&@2, "control subregister number %d out of range", $1); memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_CONTROL | $1; $$.subnr = $2; } ; ipreg: IPREG regtype { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_IP; $$.subnr = 0; } ; nullreg: NULL_TOKEN { memset (&$$, '\0', sizeof ($$)); $$.file = BRW_ARCHITECTURE_REGISTER_FILE; $$.nr = BRW_ARF_NULL; $$.subnr = 0; } ; /* 1.4.6: Relative locations */ relativelocation: simple_int { if (($1 > 32767) || ($1 < -32768)) error(&@1, "error: relative offset %d out of range \n", $1); memset (&$$, '\0', sizeof ($$)); $$.reg.file = BRW_IMMEDIATE_VALUE; $$.reg.type = BRW_REGISTER_TYPE_D; $$.imm32 = $1 & 0x0000ffff; } | STRING { memset (&$$, '\0', sizeof ($$)); $$.reg.file = BRW_IMMEDIATE_VALUE; $$.reg.type = BRW_REGISTER_TYPE_D; $$.reloc_target = $1; } ; relativelocation2: STRING { memset (&$$, '\0', sizeof ($$)); $$.reg.file = BRW_IMMEDIATE_VALUE; $$.reg.type = BRW_REGISTER_TYPE_D; $$.reloc_target = $1; } | exp { memset (&$$, '\0', sizeof ($$)); $$.reg.file = BRW_IMMEDIATE_VALUE; $$.reg.type = BRW_REGISTER_TYPE_D; $$.imm32 = $1; } | directgenreg region regtype { set_direct_src_operand(&$$, &$1, $3.type); $$.reg.vstride = $2.vert_stride; $$.reg.width = $2.width; $$.reg.hstride = $2.horiz_stride; $$.default_region = $2.is_default; } | symbol_reg_p { memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_DIRECT; $$.reg.file = $1.reg.file; $$.reg.nr = $1.reg.nr; $$.reg.subnr = $1.reg.subnr; $$.reg.type = $1.reg.type; $$.reg.vstride = $1.src_region.vert_stride; $$.reg.width = $1.src_region.width; $$.reg.hstride = $1.src_region.horiz_stride; } | indirectgenreg indirectregion regtype { memset (&$$, '\0', sizeof ($$)); $$.reg.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER; $$.reg.file = $1.file; $$.reg.subnr = $1.subnr; $$.reg.dw1.bits.indirect_offset = $1.dw1.bits.indirect_offset; $$.reg.type = $3.type; $$.reg.vstride = $2.vert_stride; $$.reg.width = $2.width; $$.reg.hstride = $2.horiz_stride; } ; /* 1.4.7: Regions */ dstregion: %empty /* empty */ { $$ = DEFAULT_DSTREGION; } |LANGLE exp RANGLE { /* Returns a value for a horiz_stride field of an * instruction. */ if ($2 != 1 && $2 != 2 && $2 != 4) error(&@2, "Invalid horiz size %d\n", $2); $$ = ffs($2); } ; region: %empty /* empty */ { /* XXX is this default value correct?*/ memset (&$$, '\0', sizeof ($$)); $$.vert_stride = ffs(0); $$.width = BRW_WIDTH_1; $$.horiz_stride = ffs(0); $$.is_default = 1; } |LANGLE exp RANGLE { /* XXX is this default value correct for accreg?*/ memset (&$$, '\0', sizeof ($$)); $$.vert_stride = ffs($2); $$.width = BRW_WIDTH_1; $$.horiz_stride = ffs(0); } |LANGLE exp COMMA exp COMMA exp RANGLE { memset (&$$, '\0', sizeof ($$)); $$.vert_stride = ffs($2); $$.width = ffs($4) - 1; $$.horiz_stride = ffs($6); } | LANGLE exp SEMICOLON exp COMMA exp RANGLE { memset (&$$, '\0', sizeof ($$)); $$.vert_stride = ffs($2); $$.width = ffs($4) - 1; $$.horiz_stride = ffs($6); } ; /* region_wh is used in specifying indirect operands where rather than having * a vertical stride, you use subsequent address registers to get a new base * offset for the next row. */ region_wh: LANGLE exp COMMA exp RANGLE { memset (&$$, '\0', sizeof ($$)); $$.vert_stride = BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL; $$.width = ffs($2) - 1; $$.horiz_stride = ffs($4); } ; indirectregion: region | region_wh ; /* 1.4.8: Types */ /* regtype returns an integer register type suitable for inserting into an * instruction. */ regtype: %empty /* empty */ { $$.type = program_defaults.register_type;$$.is_default = 1;} | TYPE_F { $$.type = BRW_REGISTER_TYPE_F;$$.is_default = 0; } | TYPE_UD { $$.type = BRW_REGISTER_TYPE_UD;$$.is_default = 0; } | TYPE_D { $$.type = BRW_REGISTER_TYPE_D;$$.is_default = 0; } | TYPE_UW { $$.type = BRW_REGISTER_TYPE_UW;$$.is_default = 0; } | TYPE_W { $$.type = BRW_REGISTER_TYPE_W;$$.is_default = 0; } | TYPE_UB { $$.type = BRW_REGISTER_TYPE_UB;$$.is_default = 0; } | TYPE_B { $$.type = BRW_REGISTER_TYPE_B;$$.is_default = 0; } ; srcimmtype: %empty /* empty */ { /* XXX change to default when pragma parse is done */ $$ = BRW_REGISTER_TYPE_D; } |TYPE_F { $$ = BRW_REGISTER_TYPE_F; } | TYPE_UD { $$ = BRW_REGISTER_TYPE_UD; } | TYPE_D { $$ = BRW_REGISTER_TYPE_D; } | TYPE_UW { $$ = BRW_REGISTER_TYPE_UW; } | TYPE_W { $$ = BRW_REGISTER_TYPE_W; } | TYPE_V { $$ = BRW_REGISTER_TYPE_V; } | TYPE_VF { $$ = BRW_REGISTER_TYPE_VF; } ; /* 1.4.10: Swizzle control */ /* Returns the swizzle control for an align16 instruction's source operand * in the src0 fields. */ swizzle: %empty /* empty */ { $$.reg.dw1.bits.swizzle = BRW_SWIZZLE_NOOP; } | DOT chansel { $$.reg.dw1.bits.swizzle = BRW_SWIZZLE4($2, $2, $2, $2); } | DOT chansel chansel chansel chansel { $$.reg.dw1.bits.swizzle = BRW_SWIZZLE4($2, $3, $4, $5); } ; chansel: X | Y | Z | W ; /* 1.4.9: Write mask */ /* Returns a partially completed struct brw_reg, with just the writemask bits * filled out. */ writemask: %empty /* empty */ { $$.dw1.bits.writemask = BRW_WRITEMASK_XYZW; } | DOT writemask_x writemask_y writemask_z writemask_w { $$.dw1.bits.writemask = $2 | $3 | $4 | $5; } ; writemask_x: %empty /* empty */ { $$ = 0; } | X { $$ = 1 << BRW_CHANNEL_X; } ; writemask_y: %empty /* empty */ { $$ = 0; } | Y { $$ = 1 << BRW_CHANNEL_Y; } ; writemask_z: %empty /* empty */ { $$ = 0; } | Z { $$ = 1 << BRW_CHANNEL_Z; } ; writemask_w: %empty /* empty */ { $$ = 0; } | W { $$ = 1 << BRW_CHANNEL_W; } ; /* 1.4.11: Immediate values */ imm32: exp { $$.r = imm32_d; $$.u.d = $1; } | NUMBER { $$.r = imm32_f; $$.u.f = $1; } ; /* 1.4.12: Predication and modifiers */ predicate: %empty /* empty */ { $$.pred_control = BRW_PREDICATE_NONE; $$.flag_reg_nr = 0; $$.flag_subreg_nr = 0; $$.pred_inverse = 0; } | LPAREN predstate flagreg predctrl RPAREN { $$.pred_control = $4; $$.flag_reg_nr = $3.nr; $$.flag_subreg_nr = $3.subnr; $$.pred_inverse = $2; } ; predstate: %empty /* empty */ { $$ = 0; } | PLUS { $$ = 0; } | MINUS { $$ = 1; } ; predctrl: %empty /* empty */ { $$ = BRW_PREDICATE_NORMAL; } | DOT X { $$ = BRW_PREDICATE_ALIGN16_REPLICATE_X; } | DOT Y { $$ = BRW_PREDICATE_ALIGN16_REPLICATE_Y; } | DOT Z { $$ = BRW_PREDICATE_ALIGN16_REPLICATE_Z; } | DOT W { $$ = BRW_PREDICATE_ALIGN16_REPLICATE_W; } | ANYV { $$ = BRW_PREDICATE_ALIGN1_ANYV; } | ALLV { $$ = BRW_PREDICATE_ALIGN1_ALLV; } | ANY2H { $$ = BRW_PREDICATE_ALIGN1_ANY2H; } | ALL2H { $$ = BRW_PREDICATE_ALIGN1_ALL2H; } | ANY4H { $$ = BRW_PREDICATE_ALIGN1_ANY4H; } | ALL4H { $$ = BRW_PREDICATE_ALIGN1_ALL4H; } | ANY8H { $$ = BRW_PREDICATE_ALIGN1_ANY8H; } | ALL8H { $$ = BRW_PREDICATE_ALIGN1_ALL8H; } | ANY16H { $$ = BRW_PREDICATE_ALIGN1_ANY16H; } | ALL16H { $$ = BRW_PREDICATE_ALIGN1_ALL16H; } ; negate: %empty /* empty */ { $$ = 0; } | MINUS { $$ = 1; } ; abs: %empty /* empty */ { $$ = 0; } | ABS { $$ = 1; } ; execsize: %empty /* empty */ %prec EMPTEXECSIZE { $$ = ffs(program_defaults.execute_size) - 1; } |LPAREN exp RPAREN { /* Returns a value for the execution_size field of an * instruction. */ if ($2 != 1 && $2 != 2 && $2 != 4 && $2 != 8 && $2 != 16 && $2 != 32) error(&@2, "Invalid execution size %d\n", $2); $$ = ffs($2) - 1; } ; saturate: %empty /* empty */ { $$ = BRW_INSTRUCTION_NORMAL; } | SATURATE { $$ = BRW_INSTRUCTION_SATURATE; } ; conditionalmodifier: condition { $$.cond = $1; $$.flag_reg_nr = 0; $$.flag_subreg_nr = -1; } | condition DOT flagreg { $$.cond = $1; $$.flag_reg_nr = ($3.nr & 0xF); $$.flag_subreg_nr = $3.subnr; } condition: %empty /* empty */ { $$ = BRW_CONDITIONAL_NONE; } | ZERO | EQUAL | NOT_ZERO | NOT_EQUAL | GREATER | GREATER_EQUAL | LESS | LESS_EQUAL | ROUND_INCREMENT | OVERFLOW | UNORDERED ; /* 1.4.13: Instruction options */ instoptions: %empty /* empty */ { memset(&$$, 0, sizeof($$)); } | LCURLY instoption_list RCURLY { $$ = $2; } ; instoption_list:instoption_list COMMA instoption { $$ = $1; add_option(&$$, $3); } | instoption_list instoption { $$ = $1; add_option(&$$, $2); } | %empty /* empty, header defaults to zeroes. */ { memset(&$$, 0, sizeof($$)); } ; instoption: ALIGN1 { $$ = ALIGN1; } | ALIGN16 { $$ = ALIGN16; } | SECHALF { $$ = SECHALF; } | COMPR { $$ = COMPR; } | SWITCH { $$ = SWITCH; } | ATOMIC { $$ = ATOMIC; } | NODDCHK { $$ = NODDCHK; } | NODDCLR { $$ = NODDCLR; } | MASK_DISABLE { $$ = MASK_DISABLE; } | BREAKPOINT { $$ = BREAKPOINT; } | ACCWRCTRL { $$ = ACCWRCTRL; } | EOT { $$ = EOT; } ; %% extern int yylineno; void yyerror (char *msg) { fprintf(stderr, "%s: %d: %s at \"%s\"\n", input_filename, yylineno, msg, lex_text()); ++errors; } static int get_type_size(unsigned type) { int size = 1; switch (type) { case BRW_REGISTER_TYPE_F: case BRW_REGISTER_TYPE_UD: case BRW_REGISTER_TYPE_D: size = 4; break; case BRW_REGISTER_TYPE_UW: case BRW_REGISTER_TYPE_W: size = 2; break; case BRW_REGISTER_TYPE_UB: case BRW_REGISTER_TYPE_B: size = 1; break; default: assert(0); size = 1; break; } return size; } static void reset_instruction_src_region(struct brw_instruction *instr, struct src_operand *src) { if (IS_GENp(8)) return; if (!src->default_region) return; if (src->reg.file == BRW_ARCHITECTURE_REGISTER_FILE && ((src->reg.nr & 0xF0) == BRW_ARF_ADDRESS)) { src->reg.vstride = ffs(0); src->reg.width = BRW_WIDTH_1; src->reg.hstride = ffs(0); } else if (src->reg.file == BRW_ARCHITECTURE_REGISTER_FILE && ((src->reg.nr & 0xF0) == BRW_ARF_ACCUMULATOR)) { int horiz_stride = 1, width, vert_stride; if (instr->header.compression_control == BRW_COMPRESSION_COMPRESSED) { width = 16; } else { width = 8; } if (width > (1 << instr->header.execution_size)) width = (1 << instr->header.execution_size); vert_stride = horiz_stride * width; src->reg.vstride = ffs(vert_stride); src->reg.width = ffs(width) - 1; src->reg.hstride = ffs(horiz_stride); } else if ((src->reg.file == BRW_ARCHITECTURE_REGISTER_FILE) && (src->reg.nr == BRW_ARF_NULL) && (instr->header.opcode == BRW_OPCODE_SEND)) { src->reg.vstride = ffs(8); src->reg.width = BRW_WIDTH_8; src->reg.hstride = ffs(1); } else { int horiz_stride = 1, width, vert_stride; if (instr->header.execution_size == 0) { /* scalar */ horiz_stride = 0; width = 1; vert_stride = 0; } else { if ((instr->header.opcode == BRW_OPCODE_MUL) || (instr->header.opcode == BRW_OPCODE_MAC) || (instr->header.opcode == BRW_OPCODE_CMP) || (instr->header.opcode == BRW_OPCODE_ASR) || (instr->header.opcode == BRW_OPCODE_ADD) || (instr->header.opcode == BRW_OPCODE_SHL)) { horiz_stride = 0; width = 1; vert_stride = 0; } else { width = (1 << instr->header.execution_size) / horiz_stride; vert_stride = horiz_stride * width; if (get_type_size(src->reg.type) * (width + src->reg.subnr) > 32) { horiz_stride = 0; width = 1; vert_stride = 0; } } } src->reg.vstride = ffs(vert_stride); src->reg.width = ffs(width) - 1; src->reg.hstride = ffs(horiz_stride); } } static void set_instruction_opcode(struct brw_program_instruction *instr, unsigned opcode) { if (IS_GENp(8)) gen8_set_opcode(GEN8(instr), opcode); else GEN(instr)->header.opcode = opcode; } /** * Fills in the destination register information in instr from the bits in dst. */ static int set_instruction_dest(struct brw_program_instruction *instr, struct brw_reg *dest) { if (!validate_dst_reg(instr, dest)) return 1; /* the assembler support expressing subnr in bytes or in number of * elements. */ resolve_subnr(dest); if (IS_GENp(8)) { gen8_set_exec_size(GEN8(instr), dest->width); gen8_set_dst(GEN8(instr), *dest); } else { brw_set_dest(&genasm_compile, GEN(instr), *dest); } return 0; } /* Sets the first source operand for the instruction. Returns 0 on success. */ static int set_instruction_src0(struct brw_program_instruction *instr, struct src_operand *src, YYLTYPE *location) { if (advanced_flag) reset_instruction_src_region(GEN(instr), src); if (!validate_src_reg(instr, src->reg, location)) return 1; /* the assembler support expressing subnr in bytes or in number of * elements. */ resolve_subnr(&src->reg); if (IS_GENp(8)) gen8_set_src0(GEN8(instr), src->reg); else brw_set_src0(&genasm_compile, GEN(instr), src->reg); return 0; } /* Sets the second source operand for the instruction. Returns 0 on success. */ static int set_instruction_src1(struct brw_program_instruction *instr, struct src_operand *src, YYLTYPE *location) { if (advanced_flag) reset_instruction_src_region(GEN(instr), src); if (!validate_src_reg(instr, src->reg, location)) return 1; /* the assembler support expressing subnr in bytes or in number of * elements. */ resolve_subnr(&src->reg); if (IS_GENp(8)) gen8_set_src1(GEN8(instr), src->reg); else brw_set_src1(&genasm_compile, GEN(instr), src->reg); return 0; } static int set_instruction_dest_three_src(struct brw_program_instruction *instr, struct brw_reg *dest) { resolve_subnr(dest); brw_set_3src_dest(&genasm_compile, GEN(instr), *dest); return 0; } static int set_instruction_src0_three_src(struct brw_program_instruction *instr, struct src_operand *src) { if (advanced_flag) reset_instruction_src_region(GEN(instr), src); resolve_subnr(&src->reg); // TODO: src0 modifier, src0 rep_ctrl brw_set_3src_src0(&genasm_compile, GEN(instr), src->reg); return 0; } static int set_instruction_src1_three_src(struct brw_program_instruction *instr, struct src_operand *src) { if (advanced_flag) reset_instruction_src_region(GEN(instr), src); resolve_subnr(&src->reg); // TODO: src1 modifier, src1 rep_ctrl brw_set_3src_src1(&genasm_compile, GEN(instr), src->reg); return 0; } static int set_instruction_src2_three_src(struct brw_program_instruction *instr, struct src_operand *src) { if (advanced_flag) reset_instruction_src_region(GEN(instr), src); resolve_subnr(&src->reg); // TODO: src2 modifier, src2 rep_ctrl brw_set_3src_src2(&genasm_compile, GEN(instr), src->reg); return 0; } static void set_instruction_saturate(struct brw_program_instruction *instr, int saturate) { if (IS_GENp(8)) gen8_set_saturate(GEN8(instr), saturate); else GEN(instr)->header.saturate = saturate; } static void set_instruction_options(struct brw_program_instruction *instr, struct options options) { if (IS_GENp(8)) { gen8_set_access_mode(GEN8(instr), options.access_mode); gen8_set_thread_control(GEN8(instr), options.thread_control); gen8_set_dep_control(GEN8(instr), options.dependency_control); gen8_set_mask_control(GEN8(instr), options.mask_control); gen8_set_debug_control(GEN8(instr), options.debug_control); gen8_set_acc_wr_control(GEN8(instr), options.acc_wr_control); gen8_set_eot(GEN8(instr), options.end_of_thread); } else { GEN(instr)->header.access_mode = options.access_mode; GEN(instr)->header.compression_control = options.compression_control; GEN(instr)->header.thread_control = options.thread_control; GEN(instr)->header.dependency_control = options.dependency_control; GEN(instr)->header.mask_control = options.mask_control; GEN(instr)->header.debug_control = options.debug_control; GEN(instr)->header.acc_wr_control = options.acc_wr_control; GEN(instr)->bits3.generic.end_of_thread = options.end_of_thread; } } static void set_instruction_predicate(struct brw_program_instruction *instr, struct predicate *p) { if (IS_GENp(8)) { gen8_set_pred_control(GEN8(instr), p->pred_control); gen8_set_pred_inv(GEN8(instr), p->pred_inverse); gen8_set_flag_reg_nr(GEN8(instr), p->flag_reg_nr); gen8_set_flag_subreg_nr(GEN8(instr), p->flag_subreg_nr); } else { GEN(instr)->header.predicate_control = p->pred_control; GEN(instr)->header.predicate_inverse = p->pred_inverse; GEN(instr)->bits2.da1.flag_reg_nr = p->flag_reg_nr; GEN(instr)->bits2.da1.flag_subreg_nr = p->flag_subreg_nr; } } static void set_instruction_pred_cond(struct brw_program_instruction *instr, struct predicate *p, struct condition *c, YYLTYPE *location) { set_instruction_predicate(instr, p); if (IS_GENp(8)) gen8_set_cond_modifier(GEN8(instr), c->cond); else GEN(instr)->header.destreg__conditionalmod = c->cond; if (c->flag_subreg_nr == -1) return; if (p->pred_control != BRW_PREDICATE_NONE && (p->flag_reg_nr != c->flag_reg_nr || p->flag_subreg_nr != c->flag_subreg_nr)) { warn(ALWAYS, location, "must use the same flag register if both " "prediction and conditional modifier are enabled\n"); } if (IS_GENp(8)) { gen8_set_flag_reg_nr(GEN8(instr), c->flag_reg_nr); gen8_set_flag_subreg_nr(GEN8(instr), c->flag_subreg_nr); } else { GEN(instr)->bits2.da1.flag_reg_nr = c->flag_reg_nr; GEN(instr)->bits2.da1.flag_subreg_nr = c->flag_subreg_nr; } } static void set_direct_dst_operand(struct brw_reg *dst, struct brw_reg *reg, int type) { *dst = *reg; dst->address_mode = BRW_ADDRESS_DIRECT; dst->type = type; dst->hstride = 1; dst->dw1.bits.writemask = BRW_WRITEMASK_XYZW; } static void set_direct_src_operand(struct src_operand *src, struct brw_reg *reg, int type) { memset(src, 0, sizeof(*src)); src->reg.address_mode = BRW_ADDRESS_DIRECT; src->reg.file = reg->file; src->reg.type = type; src->reg.subnr = reg->subnr; src->reg.nr = reg->nr; src->reg.vstride = 0; src->reg.width = 0; src->reg.hstride = 0; src->reg.negate = 0; src->reg.abs = 0; SWIZZLE(src->reg) = BRW_SWIZZLE_NOOP; } static inline int instruction_opcode(struct brw_program_instruction *insn) { if (IS_GENp(8)) return gen8_opcode(GEN8(insn)); else return GEN(insn)->header.opcode; } /* * return the offset used in native flow control (branch) instructions */ static inline int branch_offset(struct brw_program_instruction *insn, int offset) { /* * bspec: Unlike other flow control instructions, the offset used by JMPI * is relative to the incremented instruction pointer rather than the IP * value for the instruction itself. */ if (instruction_opcode(insn) == BRW_OPCODE_JMPI) offset--; /* * Gen4- bspec: the jump distance is in number of sixteen-byte units * Gen5+ bspec: the jump distance is in number of eight-byte units * Gen7.5+: the offset is in unit of 8bits for JMPI, 64bits for other flow * control instructions */ if (gen_level >= 75 && (instruction_opcode(insn) == BRW_OPCODE_JMPI)) offset *= 16; else if (gen_level >= 50) offset *= 2; return offset; } void set_branch_two_offsets(struct brw_program_instruction *insn, int jip_offset, int uip_offset) { int jip = branch_offset(insn, jip_offset); int uip = branch_offset(insn, uip_offset); assert(instruction_opcode(insn) != BRW_OPCODE_JMPI); if (IS_GENp(8)) { gen8_set_jip(GEN8(insn), jip); gen8_set_uip(GEN8(insn), uip); } else { GEN(insn)->bits3.break_cont.jip = jip; GEN(insn)->bits3.break_cont.uip = uip; } } void set_branch_one_offset(struct brw_program_instruction *insn, int jip_offset) { int jip = branch_offset(insn, jip_offset); if (IS_GENp(8)) { gen8_set_jip(GEN8(insn), jip); } else if (IS_GENx(7)) { /* Gen7 JMPI Restrictions in bspec: * The JIP data type must be Signed DWord */ if (instruction_opcode(insn) == BRW_OPCODE_JMPI) GEN(insn)->bits3.JIP = jip; else GEN(insn)->bits3.break_cont.jip = jip; } else if (IS_GENx(6)) { if ((instruction_opcode(insn) == BRW_OPCODE_CALL) || (instruction_opcode(insn) == BRW_OPCODE_JMPI)) GEN(insn)->bits3.JIP = jip; else GEN(insn)->bits1.branch_gen6.jump_count = jip; // for CASE,ELSE,FORK,IF,WHILE } else { GEN(insn)->bits3.JIP = jip; if (instruction_opcode(insn) == BRW_OPCODE_ELSE) GEN(insn)->bits3.break_cont.uip = 1; // Set the istack pop count, which must always be 1. } }