3397 lines
103 KiB
Plaintext
3397 lines
103 KiB
Plaintext
%{
|
|
/*
|
|
* 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 <eric@anholt.net>
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include "gen4asm.h"
|
|
#include "brw_eu.h"
|
|
#include "gen8_instruction.h"
|
|
|
|
#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(sizeof(struct brw_program_instruction), 1);
|
|
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(sizeof(struct brw_program_instruction), 1);
|
|
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(sizeof(struct brw_program_instruction), 1);
|
|
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 <integer> TYPE_UD TYPE_D TYPE_UW TYPE_W TYPE_UB TYPE_B
|
|
%token <integer> 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 <integer> ZERO EQUAL NOT_ZERO NOT_EQUAL GREATER GREATER_EQUAL LESS LESS_EQUAL
|
|
%token <integer> ROUND_INCREMENT OVERFLOW UNORDERED
|
|
%token <integer> GENREG MSGREG ADDRESSREG ACCREG FLAGREG
|
|
%token <integer> MASKREG AMASK IMASK LMASK CMASK
|
|
%token <integer> MASKSTACKREG LMS IMS MASKSTACKDEPTHREG IMSD LMSD
|
|
%token <integer> NOTIFYREG STATEREG CONTROLREG IPREG
|
|
%token GENREGFILE MSGREGFILE
|
|
|
|
%token <integer> MOV FRC RNDU RNDD RNDE RNDZ NOT LZD
|
|
%token <integer> MUL MAC MACH LINE SAD2 SADA2 DP4 DPH DP3 DP2
|
|
%token <integer> AVG ADD SEL AND OR XOR SHR SHL ASR CMP CMPN PLN
|
|
%token <integer> ADDC BFI1 BFREV CBIT F16TO32 F32TO16 FBH FBL
|
|
%token <integer> SEND SENDC NOP JMPI IF IFF WHILE ELSE BREAK CONT HALT MSAVE
|
|
%token <integer> PUSH MREST POP WAIT DO ENDIF ILLEGAL
|
|
%token <integer> MATH_INST
|
|
%token <integer> MAD LRP BFE BFI2 SUBB
|
|
%token <integer> CALL RET
|
|
%token <integer> BRD BRC
|
|
|
|
%token NULL_TOKEN MATH SAMPLER GATEWAY READ WRITE URB THREAD_SPAWNER VME DATA_PORT CRE
|
|
|
|
%token MSGLEN RETURNLEN
|
|
%token <integer> ALLOCATE USED COMPLETE TRANSPOSE INTERLEAVE
|
|
%token SATURATE
|
|
|
|
%token <integer> INTEGER
|
|
%token <string> STRING
|
|
%token <number> NUMBER
|
|
|
|
%token <integer> INV LOG EXP SQRT RSQ POW SIN COS SINCOS INTDIV INTMOD
|
|
%token <integer> INTDIVMOD
|
|
%token SIGNED SCALAR
|
|
|
|
%token <integer> X Y Z W
|
|
|
|
%token <integer> KERNEL_PRAGMA END_KERNEL_PRAGMA CODE_PRAGMA END_CODE_PRAGMA
|
|
%token <integer> REG_COUNT_PAYLOAD_PRAGMA REG_COUNT_TOTAL_PRAGMA DECLARE_PRAGMA
|
|
%token <integer> BASE ELEMENTSIZE SRCREGION DSTREGION TYPE
|
|
|
|
%token <integer> 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 <integer> exp sndopr
|
|
%type <integer> simple_int
|
|
%type <instruction> instruction unaryinstruction binaryinstruction
|
|
%type <instruction> binaryaccinstruction trinaryinstruction sendinstruction
|
|
%type <instruction> syncinstruction
|
|
%type <instruction> msgtarget
|
|
%type <instruction> mathinstruction
|
|
%type <instruction> nopinstruction
|
|
%type <instruction> relocatableinstruction breakinstruction
|
|
%type <instruction> ifelseinstruction loopinstruction haltinstruction
|
|
%type <instruction> multibranchinstruction subroutineinstruction jumpinstruction
|
|
%type <string> label
|
|
%type <program> instrseq
|
|
%type <integer> instoption
|
|
%type <integer> unaryop binaryop binaryaccop breakop
|
|
%type <integer> trinaryop
|
|
%type <integer> sendop
|
|
%type <condition> conditionalmodifier
|
|
%type <predicate> predicate
|
|
%type <options> instoptions instoption_list
|
|
%type <integer> condition saturate negate abs chansel
|
|
%type <integer> writemask_x writemask_y writemask_z writemask_w
|
|
%type <integer> srcimmtype execsize dstregion immaddroffset
|
|
%type <integer> subregnum sampler_datatype
|
|
%type <integer> urb_swizzle urb_allocate urb_used urb_complete
|
|
%type <integer> math_function math_signed math_scalar
|
|
%type <integer> predctrl predstate
|
|
%type <region> region region_wh indirectregion declare_srcregion;
|
|
%type <regtype> regtype
|
|
%type <reg> directgenreg directmsgreg addrreg accreg flagreg maskreg
|
|
%type <reg> maskstackreg notifyreg
|
|
/* %type <reg> maskstackdepthreg */
|
|
%type <reg> statereg controlreg ipreg nullreg
|
|
%type <reg> dstoperandex_typed srcarchoperandex_typed
|
|
%type <reg> sendleadreg
|
|
%type <reg> indirectgenreg indirectmsgreg addrparam
|
|
%type <integer> mask_subreg maskstack_subreg
|
|
%type <integer> declare_elementsize declare_dstregion declare_type
|
|
/* %type <intger> maskstackdepth_subreg */
|
|
%type <symbol_reg> symbol_reg symbol_reg_p;
|
|
%type <imm32> imm32
|
|
%type <reg> dst dstoperand dstoperandex dstreg post_dst writemask
|
|
%type <reg> declare_base
|
|
%type <src_operand> directsrcoperand srcarchoperandex directsrcaccoperand
|
|
%type <src_operand> indirectsrcoperand
|
|
%type <src_operand> src srcimm imm32reg payload srcacc srcaccimm swizzle
|
|
%type <src_operand> 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.
|
|
}
|
|
}
|