%{
/*
 * Copyright © 2018 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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "i965_asm.h"

#define YYLTYPE YYLTYPE
typedef struct YYLTYPE
{
	int first_line;
	int first_column;
	int last_line;
	int last_column;
} YYLTYPE;

enum message_level {
	WARN,
	ERROR,
};

int yydebug = 1;

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)

static bool
isPowerofTwo(unsigned int x)
{
	return x && (!(x & (x - 1)));
}

static struct brw_reg
set_direct_src_operand(struct brw_reg *reg, int type)
{
	return brw_reg(reg->file,
		       reg->nr,
		       reg->subnr,
		       0,		// negate
		       0,		// abs
		       type,
		       0,		// vstride
		       0,		// width
		       0,		// hstride
		       BRW_SWIZZLE_NOOP,
		       WRITEMASK_XYZW);
}

static void
i965_asm_unary_instruction(int opcode, struct brw_codegen *p,
		           struct brw_reg dest, struct brw_reg src0)
{
	switch (opcode) {
	case BRW_OPCODE_BFREV:
		brw_BFREV(p, dest, src0);
		break;
	case BRW_OPCODE_CBIT:
		brw_CBIT(p, dest, src0);
		break;
	case BRW_OPCODE_F32TO16:
		brw_F32TO16(p, dest, src0);
		break;
	case BRW_OPCODE_F16TO32:
		brw_F16TO32(p, dest, src0);
		break;
	case BRW_OPCODE_MOV:
		brw_MOV(p, dest, src0);
		break;
	case BRW_OPCODE_FBL:
		brw_FBL(p, dest, src0);
		break;
	case BRW_OPCODE_FRC:
		brw_FRC(p, dest, src0);
		break;
	case BRW_OPCODE_FBH:
		brw_FBH(p, dest, src0);
		break;
	case BRW_OPCODE_NOT:
		brw_NOT(p, dest, src0);
		break;
	case BRW_OPCODE_RNDE:
		brw_RNDE(p, dest, src0);
		break;
	case BRW_OPCODE_RNDZ:
		brw_RNDZ(p, dest, src0);
		break;
	case BRW_OPCODE_RNDD:
		brw_RNDD(p, dest, src0);
		break;
	case BRW_OPCODE_LZD:
		brw_LZD(p, dest, src0);
		break;
	case BRW_OPCODE_DIM:
		brw_DIM(p, dest, src0);
		break;
	case BRW_OPCODE_RNDU:
		fprintf(stderr, "Opcode BRW_OPCODE_RNDU unhandled\n");
		break;
	default:
		fprintf(stderr, "Unsupported unary opcode\n");
	}
}

static void
i965_asm_binary_instruction(int opcode,
			    struct brw_codegen *p,
			    struct brw_reg dest,
			    struct brw_reg src0,
			    struct brw_reg src1)
{
	switch (opcode) {
	case BRW_OPCODE_ADDC:
		brw_ADDC(p, dest, src0, src1);
		break;
	case BRW_OPCODE_BFI1:
		brw_BFI1(p, dest, src0, src1);
		break;
	case BRW_OPCODE_DP2:
		brw_DP2(p, dest, src0, src1);
		break;
	case BRW_OPCODE_DP3:
		brw_DP3(p, dest, src0, src1);
		break;
	case BRW_OPCODE_DP4:
		brw_DP4(p, dest, src0, src1);
		break;
	case BRW_OPCODE_DPH:
		brw_DPH(p, dest, src0, src1);
		break;
	case BRW_OPCODE_LINE:
		brw_LINE(p, dest, src0, src1);
		break;
	case BRW_OPCODE_MAC:
		brw_MAC(p, dest, src0, src1);
		break;
	case BRW_OPCODE_MACH:
		brw_MACH(p, dest, src0, src1);
		break;
	case BRW_OPCODE_PLN:
		brw_PLN(p, dest, src0, src1);
		break;
	case BRW_OPCODE_ROL:
		brw_ROL(p, dest, src0, src1);
		break;
	case BRW_OPCODE_ROR:
		brw_ROR(p, dest, src0, src1);
		break;
	case BRW_OPCODE_SAD2:
		fprintf(stderr, "Opcode BRW_OPCODE_SAD2 unhandled\n");
		break;
	case BRW_OPCODE_SADA2:
		fprintf(stderr, "Opcode BRW_OPCODE_SADA2 unhandled\n");
		break;
	case BRW_OPCODE_SUBB:
		brw_SUBB(p, dest, src0, src1);
		break;
	case BRW_OPCODE_ADD:
		brw_ADD(p, dest, src0, src1);
		break;
	case BRW_OPCODE_CMP:
		/* Third parameter is conditional modifier
		 * which gets updated later
		 */
		brw_CMP(p, dest, 0, src0, src1);
		break;
	case BRW_OPCODE_AND:
		brw_AND(p, dest, src0, src1);
		break;
	case BRW_OPCODE_ASR:
		brw_ASR(p, dest, src0, src1);
		break;
	case BRW_OPCODE_AVG:
		brw_AVG(p, dest, src0, src1);
		break;
	case BRW_OPCODE_OR:
		brw_OR(p, dest, src0, src1);
		break;
	case BRW_OPCODE_SEL:
		brw_SEL(p, dest, src0, src1);
		break;
	case BRW_OPCODE_SHL:
		brw_SHL(p, dest, src0, src1);
		break;
	case BRW_OPCODE_SHR:
		brw_SHR(p, dest, src0, src1);
		break;
	case BRW_OPCODE_XOR:
		brw_XOR(p, dest, src0, src1);
		break;
	case BRW_OPCODE_MUL:
		brw_MUL(p, dest, src0, src1);
		break;
	default:
		fprintf(stderr, "Unsupported binary opcode\n");
	}
}

static void
i965_asm_ternary_instruction(int opcode,
			     struct brw_codegen *p,
			     struct brw_reg dest,
			     struct brw_reg src0,
			     struct brw_reg src1,
			     struct brw_reg src2)
{
	switch (opcode) {
	case BRW_OPCODE_MAD:
		brw_MAD(p, dest, src0, src1, src2);
		break;
	case BRW_OPCODE_CSEL:
		brw_CSEL(p, dest, src0, src1, src2);
		break;
	case BRW_OPCODE_LRP:
		brw_LRP(p, dest, src0, src1, src2);
		break;
	case BRW_OPCODE_BFE:
		brw_BFE(p, dest, src0, src1, src2);
		break;
	case BRW_OPCODE_BFI2:
		brw_BFI2(p, dest, src0, src1, src2);
		break;
	default:
		fprintf(stderr, "Unsupported ternary opcode\n");
	}
}

static void
i965_asm_set_instruction_options(struct brw_codegen *p,
				 struct options options)
{
	brw_inst_set_access_mode(p->devinfo, brw_last_inst,
			         options.access_mode);
	brw_inst_set_mask_control(p->devinfo, brw_last_inst,
				  options.mask_control);
	brw_inst_set_thread_control(p->devinfo, brw_last_inst,
				    options.thread_control);
	brw_inst_set_no_dd_check(p->devinfo, brw_last_inst,
			         options.no_dd_check);
	brw_inst_set_no_dd_clear(p->devinfo, brw_last_inst,
			         options.no_dd_clear);
	brw_inst_set_debug_control(p->devinfo, brw_last_inst,
			           options.debug_control);
	if (p->devinfo->gen >= 6)
		brw_inst_set_acc_wr_control(p->devinfo, brw_last_inst,
					    options.acc_wr_control);
	brw_inst_set_cmpt_control(p->devinfo, brw_last_inst,
				  options.compaction);
}

static void
i965_asm_set_dst_nr(struct brw_codegen *p,
	            struct brw_reg *reg,
	            struct options options)
{
	if (p->devinfo->gen <= 6) {
		if (reg->file == BRW_MESSAGE_REGISTER_FILE &&
		    options.qtr_ctrl == BRW_COMPRESSION_COMPRESSED &&
		    !options.is_compr)
			reg->nr |= BRW_MRF_COMPR4;
	}
}

static void
add_label(struct brw_codegen *p, const char* label_name, enum instr_label_type type)
{
	if (!label_name) {
		return;
	}

	struct instr_label *label = rzalloc(p->mem_ctx, struct instr_label);

	label->name = ralloc_strdup(p->mem_ctx, label_name);
	label->offset = p->next_insn_offset;
	label->type = type;

	list_addtail(&label->link, &instr_labels);
}

%}

%locations

%start ROOT

%union {
	char *string;
	double number;
	int integer;
	unsigned long long int llint;
	struct brw_reg reg;
	enum brw_reg_type reg_type;
	struct brw_codegen *program;
	struct predicate predicate;
	struct condition condition;
	struct options options;
	brw_inst *instruction;
}

%token ABS
%token COLON
%token COMMA
%token DOT
%token LANGLE RANGLE
%token LCURLY RCURLY
%token LPAREN RPAREN
%token LSQUARE RSQUARE
%token PLUS MINUS
%token SEMICOLON

/* datatypes */
%token <integer> TYPE_B TYPE_UB
%token <integer> TYPE_W TYPE_UW
%token <integer> TYPE_D TYPE_UD
%token <integer> TYPE_Q TYPE_UQ
%token <integer> TYPE_V TYPE_UV
%token <integer> TYPE_F TYPE_HF
%token <integer> TYPE_DF TYPE_NF
%token <integer> TYPE_VF

/* label */
%token <string> JUMP_LABEL
%token <string> JUMP_LABEL_TARGET

/* opcodes */
%token <integer> ADD ADD3 ADDC AND ASR AVG
%token <integer> BFE BFI1 BFI2 BFB BFREV BRC BRD BREAK
%token <integer> CALL CALLA CASE CBIT CMP CMPN CONT CSEL
%token <integer> DIM DO DPAS DPASW DP2 DP3 DP4 DP4A DPH
%token <integer> ELSE ENDIF F16TO32 F32TO16 FBH FBL FORK FRC
%token <integer> GOTO
%token <integer> HALT
%token <integer> IF IFF ILLEGAL
%token <integer> JMPI JOIN
%token <integer> LINE LRP LZD
%token <integer> MAC MACH MAD MADM MOV MOVI MUL MREST MSAVE
%token <integer> NENOP NOP NOT
%token <integer> OR
%token <integer> PLN POP PUSH
%token <integer> RET RNDD RNDE RNDU RNDZ ROL ROR
%token <integer> SAD2 SADA2 SEL SEND SENDC SENDS SENDSC SHL SHR SMOV SUBB SYNC
%token <integer> WAIT WHILE
%token <integer> XOR

/* extended math functions */
%token <integer> COS EXP FDIV INV INVM INTDIV INTDIVMOD INTMOD LOG POW RSQ
%token <integer> RSQRTM SIN SINCOS SQRT

/* shared functions for send */
%token CONST CRE DATA DP_DATA_1 GATEWAY MATH PIXEL_INTERP READ RENDER SAMPLER
%token THREAD_SPAWNER URB VME WRITE DP_SAMPLER

/* Conditional modifiers */
%token <integer> EQUAL GREATER GREATER_EQUAL LESS LESS_EQUAL NOT_EQUAL
%token <integer> NOT_ZERO OVERFLOW UNORDERED ZERO

/* register Access Modes */
%token ALIGN1 ALIGN16

/* accumulator write control */
%token ACCWREN

/* compaction control */
%token CMPTCTRL

/* compression control */
%token COMPR COMPR4 SECHALF

/* mask control (WeCtrl) */
%token WECTRL

/* debug control */
%token BREAKPOINT

/* dependency control */
%token NODDCLR NODDCHK

/* end of thread */
%token EOT

/* mask control */
%token MASK_DISABLE;

/* predicate control */
%token <integer> ANYV ALLV ANY2H ALL2H ANY4H ALL4H ANY8H ALL8H ANY16H ALL16H
%token <integer> ANY32H ALL32H

/* round instructions */
%token <integer> ROUND_INCREMENT

/* staturation */
%token SATURATE

/* thread control */
%token ATOMIC SWITCH

/* quater control */
%token QTR_2Q QTR_3Q QTR_4Q QTR_2H QTR_2N QTR_3N QTR_4N QTR_5N
%token QTR_6N QTR_7N QTR_8N

/* channels */
%token <integer> X Y Z W

/* reg files */
%token GENREGFILE MSGREGFILE

/* vertical stride in register region */
%token VxH

/* register type */
%token <integer> GENREG MSGREG ADDRREG ACCREG FLAGREG NOTIFYREG STATEREG
%token <integer> CONTROLREG IPREG PERFORMANCEREG THREADREG CHANNELENABLEREG
%token <integer> MASKREG

%token <integer> INTEGER
%token <llint> LONG
%token NULL_TOKEN

%precedence SUBREGNUM
%left PLUS MINUS
%precedence DOT
%precedence EMPTYEXECSIZE
%precedence LPAREN

%type <integer> execsize simple_int exp
%type <llint> exp2

/* predicate control */
%type <integer> predctrl predstate
%type <predicate> predicate

/* conditional modifier */
%type <condition> cond_mod
%type <integer> condModifiers

/* instruction options  */
%type <options> instoptions instoption_list
%type <integer> instoption

/* writemask */
%type <integer> writemask_x writemask_y writemask_z writemask_w
%type <integer> writemask

/* dst operand */
%type <reg> dst dstoperand dstoperandex dstoperandex_typed dstreg
%type <integer> dstregion

%type <integer> saturate relativelocation rellocation
%type <reg> relativelocation2

/* src operand */
%type <reg> directsrcoperand directsrcaccoperand indirectsrcoperand srcacc
%type <reg> srcarcoperandex srcaccimm srcarcoperandex_typed srcimm
%type <reg> indirectgenreg indirectregion
%type <reg> immreg src reg32 payload directgenreg_list addrparam region
%type <reg> region_wh directgenreg directmsgreg indirectmsgreg
%type <integer> swizzle

/* registers */
%type <reg> accreg addrreg channelenablereg controlreg flagreg ipreg
%type <reg> notifyreg nullreg performancereg threadcontrolreg statereg maskreg
%type <integer> subregnum

/* register types */
%type <reg_type> reg_type imm_type

/* immediate values */
%type <llint> immval

/* instruction opcodes */
%type <integer> unaryopcodes binaryopcodes binaryaccopcodes ternaryopcodes
%type <integer> sendop
%type <instruction> sendopcode

%type <integer> negate abs chansel math_function sharedfunction

%type <string> jumplabeltarget
%type <string> jumplabel

%code {

static void
add_instruction_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->qtr_ctrl |= BRW_COMPRESSION_2NDHALF;
		break;
	case COMPR:
		options->qtr_ctrl |= BRW_COMPRESSION_COMPRESSED;
		options->is_compr = true;
		break;
	case COMPR4:
		options->qtr_ctrl |= 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->no_dd_check = true;
		break;
	case NODDCLR:
		options->no_dd_clear = BRW_DEPENDENCY_NOTCLEARED;
		break;
	case MASK_DISABLE:
		options->mask_control |= BRW_MASK_DISABLE;
		break;
	case BREAKPOINT:
		options->debug_control = BRW_DEBUG_BREAKPOINT;
		break;
	case WECTRL:
		options->mask_control |= BRW_WE_ALL;
		break;
	case CMPTCTRL:
		options->compaction = true;
		break;
	case ACCWREN:
		options->acc_wr_control = true;
		break;
	case EOT:
		options->end_of_thread = true;
		break;
	/* TODO : Figure out how to set instruction group and get rid of
	 * code below
	 */
	case QTR_2Q:
		options->qtr_ctrl = BRW_COMPRESSION_2NDHALF;
		break;
	case QTR_3Q:
		options->qtr_ctrl = BRW_COMPRESSION_COMPRESSED;
		break;
	case QTR_4Q:
		options->qtr_ctrl = 3;
		break;
	case QTR_2H:
		options->qtr_ctrl = BRW_COMPRESSION_COMPRESSED;
		break;
	case QTR_2N:
		options->qtr_ctrl = BRW_COMPRESSION_NONE;
		options->nib_ctrl = true;
		break;
	case QTR_3N:
		options->qtr_ctrl = BRW_COMPRESSION_2NDHALF;
		break;
	case QTR_4N:
		options->qtr_ctrl = BRW_COMPRESSION_2NDHALF;
		options->nib_ctrl = true;
		break;
	case QTR_5N:
		options->qtr_ctrl = BRW_COMPRESSION_COMPRESSED;
		break;
	case QTR_6N:
		options->qtr_ctrl = BRW_COMPRESSION_COMPRESSED;
		options->nib_ctrl = true;
		break;
	case QTR_7N:
		options->qtr_ctrl = 3;
		break;
	case QTR_8N:
		options->qtr_ctrl = 3;
		options->nib_ctrl = true;
		break;
	}
}
}
%%

ROOT:
	instrseq
	;

instrseq:
	instrseq instruction SEMICOLON
	| instrseq relocatableinstruction SEMICOLON
	| instruction SEMICOLON
	| relocatableinstruction SEMICOLON
	| instrseq jumplabeltarget
	| jumplabeltarget
	;

/* Instruction Group */
instruction:
	unaryinstruction
	| binaryinstruction
	| binaryaccinstruction
	| mathinstruction
	| nopinstruction
	| syncinstruction
	| ternaryinstruction
	| sendinstruction
	| illegalinstruction
	;

relocatableinstruction:
	jumpinstruction
	| branchinstruction
	| breakinstruction
	| loopinstruction
	;

illegalinstruction:
	ILLEGAL execsize instoptions
	{
		brw_next_insn(p, $1);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $2);
		i965_asm_set_instruction_options(p, $3);
	}
	;

/* Unary instruction */
unaryinstruction:
	predicate unaryopcodes saturate cond_mod execsize dst srcaccimm	instoptions
	{
		i965_asm_set_dst_nr(p, &$6, $8);
		brw_set_default_access_mode(p, $8.access_mode);
		i965_asm_unary_instruction($2, p, $6, $7);
		brw_pop_insn_state(p);
		i965_asm_set_instruction_options(p, $8);
		brw_inst_set_cond_modifier(p->devinfo, brw_last_inst,
					   $4.cond_modifier);

		if (p->devinfo->gen >= 7) {
			if ($2 != BRW_OPCODE_DIM) {
				brw_inst_set_flag_reg_nr(p->devinfo,
							 brw_last_inst,
							 $4.flag_reg_nr);
				brw_inst_set_flag_subreg_nr(p->devinfo,
							    brw_last_inst,
							    $4.flag_subreg_nr);
			}
		}

		if ($7.file != BRW_IMMEDIATE_VALUE) {
			brw_inst_set_src0_vstride(p->devinfo, brw_last_inst,
						  $7.vstride);
		}
		brw_inst_set_saturate(p->devinfo, brw_last_inst, $3);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $5);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $8.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $8.nib_ctrl);
	}
	;

unaryopcodes:
	BFREV
	| CBIT
	| DIM
	| F16TO32
	| F32TO16
	| FBH
	| FBL
	| FRC
	| LZD
	| MOV
	| NOT
	| RNDD
	| RNDE
	| RNDU
	| RNDZ
	;

/* Binary instruction */
binaryinstruction:
	predicate binaryopcodes saturate cond_mod execsize dst srcimm srcimm instoptions
	{
		i965_asm_set_dst_nr(p, &$6, $9);
		brw_set_default_access_mode(p, $9.access_mode);
		i965_asm_binary_instruction($2, p, $6, $7, $8);
		i965_asm_set_instruction_options(p, $9);
		brw_inst_set_cond_modifier(p->devinfo, brw_last_inst,
					   $4.cond_modifier);

		if (p->devinfo->gen >= 7) {
			brw_inst_set_flag_reg_nr(p->devinfo, brw_last_inst,
					         $4.flag_reg_nr);
			brw_inst_set_flag_subreg_nr(p->devinfo, brw_last_inst,
						    $4.flag_subreg_nr);
		}

		brw_inst_set_saturate(p->devinfo, brw_last_inst, $3);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $5);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $9.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $9.nib_ctrl);

		brw_pop_insn_state(p);
	}
	;

binaryopcodes:
	ADDC
	| BFI1
	| DP2
	| DP3
	| DP4
	| DPH
	| LINE
	| MAC
	| MACH
	| MUL
	| PLN
	| ROL
	| ROR
	| SAD2
	| SADA2
	| SUBB
	;

/* Binary acc instruction */
binaryaccinstruction:
	predicate binaryaccopcodes saturate cond_mod execsize dst srcacc srcimm instoptions
	{
		i965_asm_set_dst_nr(p, &$6, $9);
		brw_set_default_access_mode(p, $9.access_mode);
		i965_asm_binary_instruction($2, p, $6, $7, $8);
		brw_pop_insn_state(p);
		i965_asm_set_instruction_options(p, $9);
		brw_inst_set_cond_modifier(p->devinfo, brw_last_inst,
					   $4.cond_modifier);

		if (p->devinfo->gen >= 7) {
			if (!brw_inst_flag_reg_nr(p->devinfo, brw_last_inst)) {
				brw_inst_set_flag_reg_nr(p->devinfo,
							 brw_last_inst,
						         $4.flag_reg_nr);
				brw_inst_set_flag_subreg_nr(p->devinfo,
							    brw_last_inst,
							    $4.flag_subreg_nr);
			}
		}

		brw_inst_set_saturate(p->devinfo, brw_last_inst, $3);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $5);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $9.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $9.nib_ctrl);
	}
	;

binaryaccopcodes:
	ADD
	| AND
	| ASR
	| AVG
	| CMP
	| CMPN
	| OR
	| SEL
	| SHL
	| SHR
	| XOR
	;

/* Math instruction */
mathinstruction:
	predicate MATH saturate math_function execsize dst src srcimm instoptions
	{
		brw_set_default_access_mode(p, $9.access_mode);
		gen6_math(p, $6, $4, $7, $8);
		i965_asm_set_instruction_options(p, $9);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $5);
		brw_inst_set_saturate(p->devinfo, brw_last_inst, $3);
		// TODO: set instruction group instead
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $9.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $9.nib_ctrl);

		brw_pop_insn_state(p);
	}
	;

math_function:
	COS
	| EXP
	| FDIV
	| INV
	| INVM
	| INTDIV
	| INTDIVMOD
	| INTMOD
	| LOG
	| POW
	| RSQ
	| RSQRTM
	| SIN
	| SQRT
	| SINCOS
	;

/* NOP instruction */
nopinstruction:
	NOP
	{
		brw_NOP(p);
	}
	;

/* Ternary operand instruction */
ternaryinstruction:
	predicate ternaryopcodes saturate cond_mod execsize dst src src src instoptions
	{
		brw_set_default_access_mode(p, $10.access_mode);
		i965_asm_ternary_instruction($2, p, $6, $7, $8, $9);
		brw_pop_insn_state(p);
		i965_asm_set_instruction_options(p, $10);
		brw_inst_set_cond_modifier(p->devinfo, brw_last_inst,
					   $4.cond_modifier);

		if (p->devinfo->gen >= 7) {
			brw_inst_set_3src_a16_flag_reg_nr(p->devinfo, brw_last_inst,
					         $4.flag_reg_nr);
			brw_inst_set_3src_a16_flag_subreg_nr(p->devinfo, brw_last_inst,
						    $4.flag_subreg_nr);
		}

		brw_inst_set_saturate(p->devinfo, brw_last_inst, $3);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $5);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $10.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $10.nib_ctrl);
	}
	;

ternaryopcodes:
	CSEL
	| BFE
	| BFI2
	| LRP
	| MAD
	;

/* Sync instruction */
syncinstruction:
	WAIT execsize dst instoptions
	{
		brw_next_insn(p, $1);
		i965_asm_set_instruction_options(p, $4);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $2);
		brw_set_default_access_mode(p, $4.access_mode);
		struct brw_reg dest = $3;
		dest.swizzle = brw_swizzle_for_mask(dest.writemask);
		if (dest.file != ARF || dest.nr != BRW_ARF_NOTIFICATION_COUNT)
			error(&@1, "WAIT must use the notification register\n");
		brw_set_dest(p, brw_last_inst, dest);
		brw_set_src0(p, brw_last_inst, dest);
		brw_set_src1(p, brw_last_inst, brw_null_reg());
		brw_inst_set_mask_control(p->devinfo, brw_last_inst, BRW_MASK_DISABLE);
	}
	;

/* Send instruction */
sendinstruction:
	predicate sendopcode execsize dst payload exp2 sharedfunction instoptions
	{
		i965_asm_set_instruction_options(p, $8);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, $4);
		brw_set_src0(p, brw_last_inst, $5);
		brw_inst_set_bits(brw_last_inst, 127, 96, $6);
		brw_inst_set_src1_file_type(p->devinfo, brw_last_inst,
				            BRW_IMMEDIATE_VALUE,
					    BRW_REGISTER_TYPE_UD);
		brw_inst_set_sfid(p->devinfo, brw_last_inst, $7);
		brw_inst_set_eot(p->devinfo, brw_last_inst, $8.end_of_thread);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $8.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $8.nib_ctrl);

		brw_pop_insn_state(p);
	}
	| predicate sendopcode execsize exp dst payload exp2 sharedfunction instoptions
	{
		i965_asm_set_instruction_options(p, $9);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_inst_set_base_mrf(p->devinfo, brw_last_inst, $4);
		brw_set_dest(p, brw_last_inst, $5);
		brw_set_src0(p, brw_last_inst, $6);
		brw_inst_set_bits(brw_last_inst, 127, 96, $7);
		brw_inst_set_src1_file_type(p->devinfo, brw_last_inst,
				            BRW_IMMEDIATE_VALUE,
					    BRW_REGISTER_TYPE_UD);
		brw_inst_set_sfid(p->devinfo, brw_last_inst, $8);
		brw_inst_set_eot(p->devinfo, brw_last_inst, $9.end_of_thread);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $9.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $9.nib_ctrl);

		brw_pop_insn_state(p);
	}
	| predicate sendopcode execsize dst payload payload exp2 sharedfunction instoptions
	{
		i965_asm_set_instruction_options(p, $9);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, $4);
		brw_set_src0(p, brw_last_inst, $5);
		brw_inst_set_bits(brw_last_inst, 127, 96, $7);
		brw_inst_set_sfid(p->devinfo, brw_last_inst, $8);
		brw_inst_set_eot(p->devinfo, brw_last_inst, $9.end_of_thread);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $9.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $9.nib_ctrl);

		brw_pop_insn_state(p);
	}
	| predicate SENDS execsize dst payload payload exp2 exp2 sharedfunction instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $10);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, $4);
		brw_set_src0(p, brw_last_inst, $5);
		brw_set_src1(p, brw_last_inst, $6);

		if (brw_inst_send_sel_reg32_ex_desc(p->devinfo, brw_last_inst)) {
			brw_inst_set_send_ex_desc_ia_subreg_nr(p->devinfo, brw_last_inst, $5.subnr);
		} else {
			brw_inst_set_sends_ex_desc(p->devinfo, brw_last_inst, $8);
		}

		brw_inst_set_bits(brw_last_inst, 127, 96, $7);
		brw_inst_set_sfid(p->devinfo, brw_last_inst, $9);
		brw_inst_set_eot(p->devinfo, brw_last_inst, $10.end_of_thread);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $10.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $10.nib_ctrl);

		brw_pop_insn_state(p);
	}
	| predicate SENDS execsize dst payload payload src exp2 sharedfunction instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $10);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, $4);
		brw_set_src0(p, brw_last_inst, $5);
		brw_set_src1(p, brw_last_inst, $6);

		brw_inst_set_send_sel_reg32_desc(p->devinfo, brw_last_inst, 1);
		brw_inst_set_sends_ex_desc(p->devinfo, brw_last_inst, $8);

		brw_inst_set_sfid(p->devinfo, brw_last_inst, $9);
		brw_inst_set_eot(p->devinfo, brw_last_inst, $10.end_of_thread);
		// TODO: set instruction group instead of qtr and nib ctrl
		brw_inst_set_qtr_control(p->devinfo, brw_last_inst,
				         $10.qtr_ctrl);

		if (p->devinfo->gen >= 7)
			brw_inst_set_nib_control(p->devinfo, brw_last_inst,
					         $10.nib_ctrl);

		brw_pop_insn_state(p);
	}
	;

sendop:
	SEND
	| SENDC
	;

sendopcode:
	sendop   { $$ = brw_next_insn(p, $1); }
	;

sharedfunction:
	NULL_TOKEN 	        { $$ = BRW_SFID_NULL; }
	| MATH 		        { $$ = BRW_SFID_MATH; }
	| GATEWAY 	        { $$ = BRW_SFID_MESSAGE_GATEWAY; }
	| READ 		        { $$ = BRW_SFID_DATAPORT_READ; }
	| WRITE 	        { $$ = BRW_SFID_DATAPORT_WRITE; }
	| URB 		        { $$ = BRW_SFID_URB; }
	| THREAD_SPAWNER 	{ $$ = BRW_SFID_THREAD_SPAWNER; }
	| VME 		        { $$ = BRW_SFID_VME; }
	| RENDER 	        { $$ = GEN6_SFID_DATAPORT_RENDER_CACHE; }
	| CONST 	        { $$ = GEN6_SFID_DATAPORT_CONSTANT_CACHE; }
	| DATA 		        { $$ = GEN7_SFID_DATAPORT_DATA_CACHE; }
	| PIXEL_INTERP 	        { $$ = GEN7_SFID_PIXEL_INTERPOLATOR; }
	| DP_DATA_1 	        { $$ = HSW_SFID_DATAPORT_DATA_CACHE_1; }
	| CRE 		        { $$ = HSW_SFID_CRE; }
	| SAMPLER	        { $$ = BRW_SFID_SAMPLER; }
	| DP_SAMPLER	        { $$ = GEN6_SFID_DATAPORT_SAMPLER_CACHE; }
	;

exp2:
	LONG 		{ $$ = $1; }
	| MINUS LONG 	{ $$ = -$2; }
	;

/* Jump instruction */
jumpinstruction:
	predicate JMPI execsize relativelocation2 instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, $4);
		brw_inst_set_pred_control(p->devinfo, brw_last_inst,
					  brw_inst_pred_control(p->devinfo,
								brw_last_inst));
		brw_pop_insn_state(p);
	}
	;

/* branch instruction */
branchinstruction:
	predicate ENDIF execsize JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		if (p->devinfo->gen == 6) {
			brw_set_dest(p, brw_last_inst, brw_imm_w(0x0));
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
		} else if (p->devinfo->gen == 7) {
			brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, brw_imm_w(0x0));
		} else {
			brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate ENDIF execsize relativelocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
					BRW_REGISTER_TYPE_D));
		brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
					BRW_REGISTER_TYPE_D));
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, $4);

		brw_inst_set_thread_control(p->devinfo, brw_last_inst,
						BRW_THREAD_SWITCH);

		brw_pop_insn_state(p);
	}
	| ELSE execsize JUMP_LABEL jumplabel instoptions
	{
		add_label(p, $3, INSTR_LABEL_JIP);
		add_label(p, $4, INSTR_LABEL_UIP);

		brw_next_insn(p, $1);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $2);

		if (p->devinfo->gen == 6) {
			brw_set_dest(p, brw_last_inst, brw_imm_w(0x0));
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
		} else if (p->devinfo->gen == 7) {
			brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, brw_imm_w(0));
		} else {
			brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			if (p->devinfo->gen < 12)
				brw_set_src0(p, brw_last_inst, brw_imm_d(0));
		}
	}
	| ELSE execsize relativelocation rellocation instoptions
	{
		brw_next_insn(p, $1);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $2);

		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $3);
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, $4);

		if (!p->single_program_flow)
			brw_inst_set_thread_control(p->devinfo, brw_last_inst,
						    BRW_THREAD_SWITCH);
	}
	| predicate IF execsize JUMP_LABEL jumplabel instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);
		add_label(p, $5, INSTR_LABEL_UIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		if (p->devinfo->gen == 6) {
			brw_set_dest(p, brw_last_inst, brw_imm_w(0x0));
			brw_set_src0(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src1(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
		} else if (p->devinfo->gen == 7) {
			brw_set_dest(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src0(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src1(p, brw_last_inst, brw_imm_w(0x0));
		} else {
			brw_set_dest(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			if (p->devinfo->gen < 12)
				brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate IF execsize relativelocation rellocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $4);
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, $5);

		if (!p->single_program_flow)
			brw_inst_set_thread_control(p->devinfo, brw_last_inst,
						    BRW_THREAD_SWITCH);

		brw_pop_insn_state(p);
	}
	| predicate IFF execsize JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		if (p->devinfo->gen == 6) {
			brw_set_src0(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src1(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
		} else if (p->devinfo->gen == 7) {
			brw_set_dest(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src0(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			brw_set_src1(p, brw_last_inst, brw_imm_w(0x0));
		} else {
			brw_set_dest(p, brw_last_inst,
				     vec1(retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D)));
			if (p->devinfo->gen < 12)
				brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate IFF execsize relativelocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $4);
		brw_set_src1(p, brw_last_inst, brw_imm_d($4));

		if (!p->single_program_flow)
			brw_inst_set_thread_control(p->devinfo, brw_last_inst,
						    BRW_THREAD_SWITCH);

		brw_pop_insn_state(p);
	}
	;

/* break instruction */
breakinstruction:
	predicate BREAK execsize JUMP_LABEL JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);
		add_label(p, $5, INSTR_LABEL_UIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		if (p->devinfo->gen >= 8) {
			brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		} else {
			brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate BREAK execsize relativelocation relativelocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $4);
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, $5);

		brw_pop_insn_state(p);
	}
	| predicate HALT execsize JUMP_LABEL JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);
		add_label(p, $5, INSTR_LABEL_UIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, retype(brw_null_reg(),
			     BRW_REGISTER_TYPE_D));

		if (p->devinfo->gen >= 8) {
			brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		} else {
			brw_set_src0(p, brw_last_inst, retype(brw_null_reg(),
				     BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate CONT execsize JUMP_LABEL JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);
		add_label(p, $5, INSTR_LABEL_UIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, brw_ip_reg());

		if (p->devinfo->gen >= 8) {
			brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		} else {
			brw_set_src0(p, brw_last_inst, brw_ip_reg());
			brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		}

		brw_pop_insn_state(p);
	}
	| predicate CONT execsize relativelocation relativelocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $6);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
		brw_set_dest(p, brw_last_inst, brw_ip_reg());

		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));

		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $4);
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, $5);

		brw_pop_insn_state(p);
	}
	;

/* loop instruction */
loopinstruction:
	predicate WHILE execsize JUMP_LABEL instoptions
	{
		add_label(p, $4, INSTR_LABEL_JIP);

		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		if (p->devinfo->gen >= 8) {
			brw_set_dest(p, brw_last_inst,
						retype(brw_null_reg(),
						BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst, brw_imm_d(0x0));
		} else if (p->devinfo->gen == 7) {
			brw_set_dest(p, brw_last_inst,
						retype(brw_null_reg(),
						BRW_REGISTER_TYPE_D));
			brw_set_src0(p, brw_last_inst,
						retype(brw_null_reg(),
						BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst,
						brw_imm_w(0x0));
		} else {
			brw_set_dest(p, brw_last_inst, brw_imm_w(0x0));
			brw_set_src0(p, brw_last_inst,
						retype(brw_null_reg(),
						BRW_REGISTER_TYPE_D));
			brw_set_src1(p, brw_last_inst,
						retype(brw_null_reg(),
						BRW_REGISTER_TYPE_D));
		}

		brw_pop_insn_state(p);
	}
	| predicate WHILE execsize relativelocation instoptions
	{
		brw_next_insn(p, $2);
		i965_asm_set_instruction_options(p, $5);
		brw_inst_set_exec_size(p->devinfo, brw_last_inst, $3);

		brw_set_dest(p, brw_last_inst, brw_ip_reg());
		brw_set_src0(p, brw_last_inst, brw_ip_reg());
		brw_set_src1(p, brw_last_inst, brw_imm_d(0x0));
		brw_inst_set_gen4_jump_count(p->devinfo, brw_last_inst, $4);
		brw_inst_set_gen4_pop_count(p->devinfo, brw_last_inst, 0);

		brw_pop_insn_state(p);
	}
	| DO execsize instoptions
	{
		brw_next_insn(p, $1);
		if (p->devinfo->gen < 6) {
			brw_inst_set_exec_size(p->devinfo, brw_last_inst, $2);
			i965_asm_set_instruction_options(p, $3);
			brw_set_dest(p, brw_last_inst, brw_null_reg());
			brw_set_src0(p, brw_last_inst, brw_null_reg());
			brw_set_src1(p, brw_last_inst, brw_null_reg());

			brw_inst_set_qtr_control(p->devinfo, brw_last_inst, BRW_COMPRESSION_NONE);
		}
	}
	;

/* Relative location */
relativelocation2:
	immreg
	| reg32
	;

simple_int:
	INTEGER 	        { $$ = $1; }
	| MINUS INTEGER 	{ $$ = -$2; }
	| LONG 		        { $$ = $1; }
	| MINUS LONG 	        { $$ = -$2; }
	;

rellocation:
	relativelocation
	| %empty { $$ = 0; }
	;

relativelocation:
	simple_int
	{
		$$ = $1;
	}
	;

jumplabel:
	JUMP_LABEL	{ $$ = $1; }
	| %empty	{ $$ = NULL; }
	;

jumplabeltarget:
	JUMP_LABEL_TARGET
	{
		struct target_label *label = rzalloc(p->mem_ctx, struct target_label);

		label->name = ralloc_strdup(p->mem_ctx, $1);
		label->offset = p->next_insn_offset;

		list_addtail(&label->link, &target_labels);
	}
	;

/* Destination register */
dst:
	dstoperand
	| dstoperandex
	;

dstoperand:
	dstreg dstregion writemask reg_type
	{
		$$ = $1;
		$$.vstride = BRW_VERTICAL_STRIDE_1;
		$$.width = BRW_WIDTH_1;
		$$.hstride = $2;
		$$.type = $4;
		$$.writemask = $3;
		$$.swizzle = BRW_SWIZZLE_NOOP;
		$$.subnr = $$.subnr * brw_reg_type_to_size($4);
	}
	;

dstoperandex:
	dstoperandex_typed dstregion writemask reg_type
	{
		$$ = $1;
		$$.hstride = $2;
		$$.type = $4;
		$$.writemask = $3;
		$$.subnr = $$.subnr * brw_reg_type_to_size($4);
	}
	/* BSpec says "When the conditional modifier is present, updates
	 * to the selected flag register also occur. In this case, the
	 * register region fields of the ‘null’ operand are valid."
	 */
	| nullreg dstregion writemask reg_type
	{
		$$ = $1;
		$$.vstride = BRW_VERTICAL_STRIDE_1;
		$$.width = BRW_WIDTH_1;
		$$.hstride = $2;
		$$.writemask = $3;
		$$.type = $4;
	}
	| threadcontrolreg
	{
		$$ = $1;
		$$.hstride = 1;
		$$.type = BRW_REGISTER_TYPE_UW;
	}
	;

dstoperandex_typed:
	accreg
	| addrreg
	| channelenablereg
	| controlreg
	| flagreg
	| ipreg
	| maskreg
	| notifyreg
	| performancereg
	| statereg
	;

dstreg:
	directgenreg
	{
		$$ = $1;
		$$.address_mode = BRW_ADDRESS_DIRECT;
	}
	| indirectgenreg
	{
		$$ = $1;
		$$.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER;
	}
	| directmsgreg
	{
		$$ = $1;
		$$.address_mode = BRW_ADDRESS_DIRECT;
	}
	| indirectmsgreg
	{
		$$ = $1;
		$$.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER;
	}
	;

/* Source register */
srcaccimm:
	srcacc
	| immreg
	;

immreg:
	immval imm_type
	{
		switch ($2) {
		case BRW_REGISTER_TYPE_UD:
			$$ = brw_imm_ud($1);
			break;
		case BRW_REGISTER_TYPE_D:
			$$ = brw_imm_d($1);
			break;
		case BRW_REGISTER_TYPE_UW:
			$$ = brw_imm_uw($1 | ($1 << 16));
			break;
		case BRW_REGISTER_TYPE_W:
			$$ = brw_imm_w($1);
			break;
		case BRW_REGISTER_TYPE_F:
			$$ = brw_imm_reg(BRW_REGISTER_TYPE_F);
			/* Set u64 instead of ud since DIM uses a 64-bit F-typed imm */
			$$.u64 = $1;
			break;
		case BRW_REGISTER_TYPE_V:
			$$ = brw_imm_v($1);
			break;
		case BRW_REGISTER_TYPE_UV:
			$$ = brw_imm_uv($1);
			break;
		case BRW_REGISTER_TYPE_VF:
			$$ = brw_imm_vf($1);
			break;
		case BRW_REGISTER_TYPE_Q:
			$$ = brw_imm_q($1);
			break;
		case BRW_REGISTER_TYPE_UQ:
			$$ = brw_imm_uq($1);
			break;
		case BRW_REGISTER_TYPE_DF:
			$$ = brw_imm_reg(BRW_REGISTER_TYPE_DF);
			$$.d64 = $1;
			break;
		default:
			error(&@2, "Unknown immediate type %s\n",
			      brw_reg_type_to_letters($2));
		}
	}
	;

reg32:
	directgenreg region reg_type
	{
		$$ = set_direct_src_operand(&$1, $3);
		$$ = stride($$, $2.vstride, $2.width, $2.hstride);
	}
	;

payload:
	directsrcoperand
	;

src:
	directsrcoperand
	| indirectsrcoperand
	;

srcacc:
	directsrcaccoperand
	| indirectsrcoperand
	;

srcimm:
	directsrcoperand
	| indirectsrcoperand
	| immreg
	;

directsrcaccoperand:
	directsrcoperand
	| accreg region reg_type
	{
		$$ = set_direct_src_operand(&$1, $3);
		$$.vstride = $2.vstride;
		$$.width = $2.width;
		$$.hstride = $2.hstride;
	}
	;

srcarcoperandex:
	srcarcoperandex_typed region reg_type
	{
		$$ = brw_reg($1.file,
			     $1.nr,
			     $1.subnr,
			     0,
			     0,
			     $3,
			     $2.vstride,
			     $2.width,
			     $2.hstride,
			     BRW_SWIZZLE_NOOP,
			     WRITEMASK_XYZW);
	}
	| nullreg region reg_type
	{
		$$ = set_direct_src_operand(&$1, $3);
		$$.vstride = $2.vstride;
		$$.width = $2.width;
		$$.hstride = $2.hstride;
	}
	| threadcontrolreg
	{
		$$ = set_direct_src_operand(&$1, BRW_REGISTER_TYPE_UW);
	}
	;

srcarcoperandex_typed:
	channelenablereg
	| controlreg
	| flagreg
	| ipreg
	| maskreg
	| statereg
	;

indirectsrcoperand:
	negate abs indirectgenreg indirectregion swizzle reg_type
	{
		$$ = brw_reg($3.file,
			     0,
			     $3.subnr,
			     $1,  // negate
			     $2,  // abs
			     $6,
			     $4.vstride,
			     $4.width,
			     $4.hstride,
			     $5,
			     WRITEMASK_X);

		$$.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER;
		// brw_reg set indirect_offset to 0 so set it to valid value
		$$.indirect_offset = $3.indirect_offset;
	}
	;

directgenreg_list:
	directgenreg
	| directmsgreg
	| notifyreg
	| addrreg
	| performancereg
	;

directsrcoperand:
	negate abs directgenreg_list region swizzle reg_type
	{
		$$ = brw_reg($3.file,
			     $3.nr,
			     $3.subnr,
			     $1,
			     $2,
			     $6,
			     $4.vstride,
			     $4.width,
			     $4.hstride,
			     $5,
			     WRITEMASK_X);
	}
	| srcarcoperandex
	;

/* Address register */
addrparam:
	addrreg exp
	{
		memset(&$$, '\0', sizeof($$));
		$$.subnr = $1.subnr;
		$$.indirect_offset = $2;
	}
	| addrreg
	;

/* Register files and register numbers */
exp:
	INTEGER 	{ $$ = $1; }
	| LONG 	        { $$ = $1; }
	;

subregnum:
	DOT exp 		        { $$ = $2; }
	| %empty %prec SUBREGNUM 	{ $$ = 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;
		$$.indirect_offset = $3.indirect_offset;
	}
	;

directmsgreg:
	MSGREG subregnum
	{
		$$.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;
		$$.indirect_offset = $3.indirect_offset;
	}
	;

addrreg:
	ADDRREG subregnum
	{
		int subnr = (p->devinfo->gen >= 8) ? 16 : 8;

		if ($2 > subnr)
			error(&@2, "Address sub register number %d"
				   "out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_ADDRESS;
		$$.subnr = $2;
	}
	;

accreg:
	ACCREG subregnum
	{
		int nr_reg;
		if (p->devinfo->gen < 8)
			nr_reg = 2;
		else
			nr_reg = 10;

		if ($1 > nr_reg)
			error(&@1, "Accumulator register number %d"
				   " out of range\n", $1);

		memset(&$$, '\0', sizeof($$));
		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_ACCUMULATOR;
		$$.subnr = $2;
	}
	;

flagreg:
	FLAGREG subregnum
	{
		// SNB = 1 flag reg and IVB+ = 2 flag reg
		int nr_reg = (p->devinfo->gen >= 7) ? 2 : 1;
		int subnr = nr_reg;

		if ($1 > nr_reg)
			error(&@1, "Flag register number %d"
				   " out of range \n", $1);
		if ($2 > subnr)
			error(&@2, "Flag subregister number %d"
				   " out of range\n", $2);

		$$.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\n", $1);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_MASK;
		$$.subnr = $2;
	}
	;

notifyreg:
	NOTIFYREG subregnum
	{
		int subnr = (p->devinfo->gen >= 11) ? 2 : 3;
		if ($2 > subnr)
			error(&@2, "Notification sub register number %d"
				   " out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_NOTIFICATION_COUNT;
		$$.subnr = $2;
	}
	;

statereg:
	STATEREG subregnum
	{
		if ($1 > 2)
			error(&@1, "State register number %d"
				   " out of range\n", $1);

		if ($2 > 4)
			error(&@2, "State sub register number %d"
				   " out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_STATE;
		$$.subnr = $2;
	}
	;

controlreg:
	CONTROLREG subregnum
	{
		if ($2 > 3)
			error(&@2, "control sub register number %d"
				   " out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_CONTROL;
		$$.subnr = $2;
	}
	;

ipreg:
	IPREG		{ $$ = brw_ip_reg(); }
	;

nullreg:
	NULL_TOKEN 	{ $$ = brw_null_reg(); }
	;

threadcontrolreg:
	THREADREG subregnum
	{
		if ($2 > 7)
			error(&@2, "Thread control sub register number %d"
				   " out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_TDR;
		$$.subnr = $2;
	}
	;

performancereg:
	PERFORMANCEREG subregnum
	{
		int subnr;
		if (p->devinfo->gen >= 10)
			subnr = 5;
		else if (p->devinfo->gen <= 8)
			subnr = 3;
		else
			subnr = 4;

		if ($2 > subnr)
			error(&@2, "Performance sub register number %d"
				   " out of range\n", $2);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_TIMESTAMP;
		$$.subnr = $2;
	}
	;

channelenablereg:
	CHANNELENABLEREG subregnum
	{
		if ($1 > 0)
			error(&@1, "Channel enable register number %d"
				   " out of range\n", $1);

		$$.file = BRW_ARCHITECTURE_REGISTER_FILE;
		$$.nr = BRW_ARF_MASK;
		$$.subnr = $2;
	}
	;

/* Immediate values */
immval:
	exp2
	{
		$$ = $1;
	}
	| LSQUARE exp2 COMMA exp2 COMMA exp2 COMMA exp2 RSQUARE
	{
		$$ = ($2 << 0) | ($4 << 8) | ($6 << 16) | ($8 << 24);
	}
	;

/* Regions */
dstregion:
	%empty
	{
		$$ = BRW_HORIZONTAL_STRIDE_1;
	}
	| LANGLE exp RANGLE
	{
		if ($2 != 0 && ($2 > 4 || !isPowerofTwo($2)))
			error(&@2, "Invalid Horizontal stride %d\n", $2);

		$$ = ffs($2);
	}
	;

indirectregion:
	region
	| region_wh
	;

region:
	%empty
	{
		$$ = stride($$, 0, 1, 0);
	}
	| LANGLE exp RANGLE
	{
		if ($2 != 0 && ($2 > 32 || !isPowerofTwo($2)))
			error(&@2, "Invalid VertStride %d\n", $2);

		$$ = stride($$, $2, 1, 0);
	}
	| LANGLE exp COMMA exp COMMA exp RANGLE
	{

		if ($2 != 0 && ($2 > 32 || !isPowerofTwo($2)))
			error(&@2, "Invalid VertStride %d\n", $2);

		if ($4 > 16 || !isPowerofTwo($4))
			error(&@4, "Invalid width %d\n", $4);

		if ($6 != 0 && ($6 > 4 || !isPowerofTwo($6)))
			error(&@6, "Invalid Horizontal stride in"
				   "  region_wh %d\n", $6);

		$$ = stride($$, $2, $4, $6);
	}
	| LANGLE exp SEMICOLON exp COMMA exp RANGLE
	{
		if ($2 != 0 && ($2 > 32 || !isPowerofTwo($2)))
			error(&@2, "Invalid VertStride %d\n", $2);

		if ($4 > 16 || !isPowerofTwo($4))
			error(&@4, "Invalid width %d\n", $4);

		if ($6 != 0 && ($6 > 4 || !isPowerofTwo($6)))
			error(&@6, "Invalid Horizontal stride in"
				   " region_wh %d\n", $6);

		$$ = stride($$, $2, $4, $6);
	}
	| LANGLE VxH COMMA exp COMMA exp RANGLE
	{
		if ($4 > 16 || !isPowerofTwo($4))
			error(&@4, "Invalid width %d\n", $4);

		if ($6 != 0 && ($6 > 4 || !isPowerofTwo($6)))
			error(&@6, "Invalid Horizontal stride in"
				   " region_wh %d\n", $6);

		$$ = brw_VxH_indirect(0, 0);
	}
	;

region_wh:
	LANGLE exp COMMA exp RANGLE
	{
		if ($2 > 16 || !isPowerofTwo($2))
			error(&@2, "Invalid width %d\n", $2);

		if ($4 != 0 && ($4 > 4 || !isPowerofTwo($4)))
			error(&@4, "Invalid Horizontal stride in"
				   " region_wh %d\n", $4);

		$$ = stride($$, 0, $2, $4);
		$$.vstride = BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL;
	}
	;

reg_type:
	  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_UB 	{ $$ = BRW_REGISTER_TYPE_UB; }
	| TYPE_B 	{ $$ = BRW_REGISTER_TYPE_B;  }
	| TYPE_DF 	{ $$ = BRW_REGISTER_TYPE_DF; }
	| TYPE_UQ 	{ $$ = BRW_REGISTER_TYPE_UQ; }
	| TYPE_Q 	{ $$ = BRW_REGISTER_TYPE_Q;  }
	| TYPE_HF 	{ $$ = BRW_REGISTER_TYPE_HF; }
	| TYPE_NF 	{ $$ = BRW_REGISTER_TYPE_NF; }
	;

imm_type:
	reg_type 	{ $$ = $1; }
	| TYPE_V 	{ $$ = BRW_REGISTER_TYPE_V;  }
	| TYPE_VF 	{ $$ = BRW_REGISTER_TYPE_VF; }
	| TYPE_UV 	{ $$ = BRW_REGISTER_TYPE_UV; }
	;

writemask:
	%empty
	{
		$$ = WRITEMASK_XYZW;
	}
	| DOT writemask_x writemask_y writemask_z writemask_w
	{
		$$ = $2 | $3 | $4 | $5;
	}
	;

writemask_x:
	%empty 	{ $$ = 0; }
	| X 	{ $$ = 1 << BRW_CHANNEL_X; }
	;

writemask_y:
	%empty 	{ $$ = 0; }
	| Y 	{ $$ = 1 << BRW_CHANNEL_Y; }
	;

writemask_z:
	%empty 	{ $$ = 0; }
	| Z 	{ $$ = 1 << BRW_CHANNEL_Z; }
	;

writemask_w:
	%empty 	{ $$ = 0; }
	| W 	{ $$ = 1 << BRW_CHANNEL_W; }
	;

swizzle:
	%empty
	{
		$$ = BRW_SWIZZLE_NOOP;
	}
	| DOT chansel
	{
		$$ = BRW_SWIZZLE4($2, $2, $2, $2);
	}
	| DOT chansel chansel chansel chansel
	{
		$$ = BRW_SWIZZLE4($2, $3, $4, $5);
	}
	;

chansel:
	X
	| Y
	| Z
	| W
	;

/* Instruction prediction and modifiers */
predicate:
	%empty
	{
		brw_push_insn_state(p);
		brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
		brw_set_default_flag_reg(p, 0, 0);
		brw_set_default_predicate_inverse(p, false);
	}
	| LPAREN predstate flagreg predctrl RPAREN
	{
		brw_push_insn_state(p);
		brw_set_default_predicate_inverse(p, $2);
		brw_set_default_flag_reg(p, $3.nr, $3.subnr);
		brw_set_default_predicate_control(p, $4);
	}
	;

predstate:
	%empty 	        { $$ = 0; }
	| PLUS 	        { $$ = 0; }
	| MINUS 	{ $$ = 1; }
	;

predctrl:
	%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
	| ALLV
	| ANY2H
	| ALL2H
	| ANY4H
	| ALL4H
	| ANY8H
	| ALL8H
	| ANY16H
	| ALL16H
	| ANY32H
	| ALL32H
	;

/* Source Modification */
negate:
	%empty 	        { $$ = 0; }
	| MINUS 	{ $$ = 1; }
	;

abs:
	%empty 	{ $$ = 0; }
	| ABS 	{ $$ = 1; }
	;

/* Flag (Conditional) Modifier */
cond_mod:
	condModifiers
	{
		$$.cond_modifier = $1;
		$$.flag_reg_nr = 0;
		$$.flag_subreg_nr = 0;
	}
	| condModifiers DOT flagreg
	{
		$$.cond_modifier = $1;
		$$.flag_reg_nr = $3.nr;
		$$.flag_subreg_nr = $3.subnr;
	}
	;

condModifiers:
	%empty 	{ $$ = BRW_CONDITIONAL_NONE; }
	| ZERO
	| EQUAL
	| NOT_ZERO
	| NOT_EQUAL
	| GREATER
	| GREATER_EQUAL
	| LESS
	| LESS_EQUAL
	| OVERFLOW
	| ROUND_INCREMENT
	| UNORDERED
	;

saturate:
	%empty 		{ $$ = BRW_INSTRUCTION_NORMAL; }
	| SATURATE 	{ $$ = BRW_INSTRUCTION_SATURATE; }
	;

/* Execution size */
execsize:
	%empty %prec EMPTYEXECSIZE
	{
		$$ = 0;
	}
	| LPAREN exp2 RPAREN
	{
		if ($2 > 32 || !isPowerofTwo($2))
			error(&@2, "Invalid execution size %llu\n", $2);

		$$ = cvt($2) - 1;
	}
	;

/* Instruction options */
instoptions:
	%empty
	{
		memset(&$$, 0, sizeof($$));
	}
	| LCURLY instoption_list RCURLY
	{
		memset(&$$, 0, sizeof($$));
		$$ = $2;
	}
	;

instoption_list:
	instoption_list COMMA instoption
	{
		memset(&$$, 0, sizeof($$));
		$$ = $1;
		add_instruction_option(&$$, $3);
	}
	| instoption_list instoption
	{
		memset(&$$, 0, sizeof($$));
		$$ = $1;
		add_instruction_option(&$$, $2);
	}
	| %empty
	{
		memset(&$$, 0, sizeof($$));
	}
	;

instoption:
	ALIGN1 	        { $$ = ALIGN1;}
	| ALIGN16 	{ $$ = ALIGN16; }
	| ACCWREN 	{ $$ = ACCWREN; }
	| SECHALF 	{ $$ = SECHALF; }
	| COMPR 	{ $$ = COMPR; }
	| COMPR4 	{ $$ = COMPR4; }
	| BREAKPOINT 	{ $$ = BREAKPOINT; }
	| NODDCLR 	{ $$ = NODDCLR; }
	| NODDCHK 	{ $$ = NODDCHK; }
	| MASK_DISABLE 	{ $$ = MASK_DISABLE; }
	| EOT 	        { $$ = EOT; }
	| SWITCH 	{ $$ = SWITCH; }
	| ATOMIC 	{ $$ = ATOMIC; }
	| CMPTCTRL 	{ $$ = CMPTCTRL; }
	| WECTRL 	{ $$ = WECTRL; }
	| QTR_2Q 	{ $$ = QTR_2Q; }
	| QTR_3Q 	{ $$ = QTR_3Q; }
	| QTR_4Q 	{ $$ = QTR_4Q; }
	| QTR_2H 	{ $$ = QTR_2H; }
	| QTR_2N 	{ $$ = QTR_2N; }
	| QTR_3N 	{ $$ = QTR_3N; }
	| QTR_4N 	{ $$ = QTR_4N; }
	| QTR_5N 	{ $$ = QTR_5N; }
	| QTR_6N 	{ $$ = QTR_6N; }
	| QTR_7N 	{ $$ = QTR_7N; }
	| QTR_8N 	{ $$ = QTR_8N; }
	;

%%

extern int yylineno;

void
yyerror(char *msg)
{
	fprintf(stderr, "%s: %d: %s at \"%s\"\n",
	        input_filename, yylineno, msg, lex_text());
	++errors;
}
