summaryrefslogtreecommitdiffstats
path: root/src/mesa/program
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/program')
-rw-r--r--src/mesa/program/program_lexer.l165
-rw-r--r--src/mesa/program/program_parse.y1492
-rw-r--r--src/mesa/program/program_parse_extra.c20
-rw-r--r--src/mesa/program/program_parser.h66
4 files changed, 1127 insertions, 616 deletions
diff --git a/src/mesa/program/program_lexer.l b/src/mesa/program/program_lexer.l
index 0a50dab97fd..af51ad2837b 100644
--- a/src/mesa/program/program_lexer.l
+++ b/src/mesa/program/program_lexer.l
@@ -21,11 +21,17 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
+
+extern "C" {
#include "main/glheader.h"
#include "main/imports.h"
#include "program/prog_instruction.h"
#include "program/prog_statevars.h"
#include "program/symbol_table.h"
+};
+
+#include "glsl_types.h"
+#include "ir.h"
#include "program/program_parser.h"
#include "program/program_parse.tab.h"
@@ -60,19 +66,34 @@
} while (0)
-#define return_opcode(condition, token, opcode, len) \
+#define return_opcode(condition, token, len) \
+ do { \
+ if (condition && \
+ _mesa_parse_instruction_suffix(yyextra, \
+ yytext + len, \
+ & yylval->opcode)) { \
+ yylval->opcode.opcode = 0; \
+ return token; \
+ } else { \
+ return handle_ident(yyextra, yytext, yylval); \
+ } \
+ } while (0)
+
+
+#define return_common(condition, token, _opcode, len) \
do { \
if (condition && \
_mesa_parse_instruction_suffix(yyextra, \
yytext + len, \
- & yylval->temp_inst)) { \
- yylval->temp_inst.Opcode = OPCODE_ ## opcode; \
+ & yylval->opcode)) { \
+ yylval->opcode.opcode = _opcode; \
return token; \
} else { \
return handle_ident(yyextra, yytext, yylval); \
} \
} while (0)
+
#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \
SWIZZLE_NIL, SWIZZLE_NIL)
@@ -182,74 +203,76 @@ OUTPUT { return OUTPUT; }
PARAM { return PARAM; }
TEMP { yylval->integer = at_temp; return TEMP; }
-ABS{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, ABS, 3); }
-ADD{sz}{cc}{sat} { return_opcode( 1, BIN_OP, ADD, 3); }
-ARL { return_opcode(require_ARB_vp, ARL, ARL, 3); }
-
-CMP{sat} { return_opcode(require_ARB_fp, TRI_OP, CMP, 3); }
-COS{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, COS, 3); }
-
-DDX{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDX, 3); }
-DDY{szf}{cc}{sat} { return_opcode(require_NV_fp, VECTOR_OP, DDY, 3); }
-DP3{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP3, 3); }
-DP4{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DP4, 3); }
-DPH{sz}{cc}{sat} { return_opcode( 1, BIN_OP, DPH, 3); }
-DST{szf}{cc}{sat} { return_opcode( 1, BIN_OP, DST, 3); }
-
-EX2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, EX2, 3); }
-EXP { return_opcode(require_ARB_vp, SCALAR_OP, EXP, 3); }
-
-FLR{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FLR, 3); }
-FRC{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, FRC, 3); }
-
-KIL { return_opcode(require_ARB_fp, KIL, KIL, 3); }
-
-LIT{szf}{cc}{sat} { return_opcode( 1, VECTOR_OP, LIT, 3); }
-LG2{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, LG2, 3); }
-LOG { return_opcode(require_ARB_vp, SCALAR_OP, LOG, 3); }
-LRP{sz}{cc}{sat} { return_opcode(require_ARB_fp, TRI_OP, LRP, 3); }
-
-MAD{sz}{cc}{sat} { return_opcode( 1, TRI_OP, MAD, 3); }
-MAX{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MAX, 3); }
-MIN{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MIN, 3); }
-MOV{sz}{cc}{sat} { return_opcode( 1, VECTOR_OP, MOV, 3); }
-MUL{sz}{cc}{sat} { return_opcode( 1, BIN_OP, MUL, 3); }
-
-PK2H { return_opcode(require_NV_fp, VECTOR_OP, PK2H, 4); }
-PK2US { return_opcode(require_NV_fp, VECTOR_OP, PK2US, 5); }
-PK4B { return_opcode(require_NV_fp, VECTOR_OP, PK4B, 4); }
-PK4UB { return_opcode(require_NV_fp, VECTOR_OP, PK4UB, 5); }
-POW{szf}{cc}{sat} { return_opcode( 1, BINSC_OP, POW, 3); }
-
-RCP{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RCP, 3); }
-RFL{szf}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, RFL, 3); }
-RSQ{szf}{cc}{sat} { return_opcode( 1, SCALAR_OP, RSQ, 3); }
-
-SCS{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SCS, 3); }
-SEQ{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SEQ, 3); }
-SFL{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SFL, 3); }
-SGE{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SGE, 3); }
-SGT{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SGT, 3); }
-SIN{szf}{cc}{sat} { return_opcode(require_ARB_fp, SCALAR_OP, SIN, 3); }
-SLE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SLE, 3); }
-SLT{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SLT, 3); }
-SNE{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, SNE, 3); }
-STR{sz}{cc}{sat} { return_opcode(require_NV_fp, BIN_OP, STR, 3); }
-SUB{sz}{cc}{sat} { return_opcode( 1, BIN_OP, SUB, 3); }
-SWZ{sat} { return_opcode( 1, SWZ, SWZ, 3); }
-
-TEX{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TEX, 3); }
-TXB{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXB, 3); }
-TXD{cc}{sat} { return_opcode(require_NV_fp, TXD_OP, TXD, 3); }
-TXP{cc}{sat} { return_opcode(require_ARB_fp, SAMPLE_OP, TXP, 3); }
-
-UP2H{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2H, 4); }
-UP2US{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP2US, 5); }
-UP4B{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4B, 4); }
-UP4UB{cc}{sat} { return_opcode(require_NV_fp, SCALAR_OP, UP4UB, 5); }
-
-X2D{szf}{cc}{sat} { return_opcode(require_NV_fp, TRI_OP, X2D, 3); }
-XPD{sat} { return_opcode( 1, BIN_OP, XPD, 3); }
+ABS{sz}{cc}{sat} { return_common( true, VECTOR_OP, ir_unop_abs, 3); }
+ADD{sz}{cc}{sat} { return_common( true, BIN_OP, ir_binop_add, 3); }
+ARL { return_opcode(require_ARB_vp, ARL, 3); }
+
+CMP{sat} { return_opcode(require_ARB_fp, CMP_OP, 3); }
+COS{szf}{cc}{sat} { return_common(require_ARB_fp, SCALAR_OP, ir_unop_cos, 3); }
+
+DDX{szf}{cc}{sat} { return_common(require_NV_fp, VECTOR_OP, ir_unop_dFdx, 3); }
+DDY{szf}{cc}{sat} { return_common(require_NV_fp, VECTOR_OP, ir_unop_dFdy, 3); }
+DP3{sz}{cc}{sat} { return_opcode( true, DP3_OP, 3); }
+DP4{sz}{cc}{sat} { return_opcode( true, DP4_OP, 3); }
+DPH{sz}{cc}{sat} { return_opcode( true, DPH_OP, 3); }
+DST{szf}{cc}{sat} { return_opcode( true, DST_OP, 3); }
+
+EX2{szf}{cc}{sat} { return_common( true, SCALAR_OP, ir_unop_exp, 3); }
+ /* FINISHME: Somehow communicate that this is the low precision version. */
+EXP { return_common(require_ARB_vp, SCALAR_OP, ir_unop_exp, 3); }
+
+FLR{sz}{cc}{sat} { return_common( true, VECTOR_OP, ir_unop_floor, 3); }
+FRC{sz}{cc}{sat} { return_common( true, VECTOR_OP, ir_unop_fract, 3); }
+
+KIL { return_opcode(require_ARB_fp, KIL, 3); }
+
+LIT{szf}{cc}{sat} { return_common( true, VECTOR_OP, ir_unop_lit, 3); }
+LG2{szf}{cc}{sat} { return_common( true, SCALAR_OP, ir_unop_log, 3); }
+ /* FINISHME: Somehow communicate that this is the low precision version. */
+LOG { return_common(require_ARB_vp, SCALAR_OP, ir_unop_log, 3); }
+LRP{sz}{cc}{sat} { return_opcode(require_ARB_fp, LRP_OP, 3); }
+
+MAD{sz}{cc}{sat} { return_common( true, MAD_OP, ir_binop_mul, 3); }
+MAX{sz}{cc}{sat} { return_common( true, BIN_OP, ir_binop_max, 3); }
+MIN{sz}{cc}{sat} { return_common( true, BIN_OP, ir_binop_min, 3); }
+MOV{sz}{cc}{sat} { return_common( true, MOV_OP, ir_binop_add, 3); }
+MUL{sz}{cc}{sat} { return_common( true, BIN_OP, ir_binop_mul, 3); }
+
+PK2H { return_opcode(require_NV_fp, PACK_OP, 4); }
+PK2US { return_opcode(require_NV_fp, PACK_OP, 5); }
+PK4B { return_opcode(require_NV_fp, PACK_OP, 4); }
+PK4UB { return_opcode(require_NV_fp, PACK_OP, 5); }
+POW{szf}{cc}{sat} { return_common( true, BINSC_OP, ir_binop_pow, 3); }
+
+RCP{szf}{cc}{sat} { return_common( true, SCALAR_OP, ir_unop_rcp, 3); }
+RFL{szf}{cc}{sat} { return_opcode(require_NV_fp, RFL_OP, 3); }
+RSQ{szf}{cc}{sat} { return_common( true, SCALAR_OP, ir_unop_rsq, 3); }
+
+SCS{sat} { return_opcode(require_ARB_fp, SCS_OP, 3); }
+SEQ{sz}{cc}{sat} { return_common(require_NV_fp, SET_OP, ir_binop_equal, 3); }
+SFL{sz}{cc}{sat} { return_opcode(require_NV_fp, SFL_OP, 3); }
+SGE{sz}{cc}{sat} { return_common( true, SET_OP, ir_binop_gequal, 3); }
+SGT{sz}{cc}{sat} { return_common(require_NV_fp, SET_OP, ir_binop_greater, 3); }
+SIN{szf}{cc}{sat} { return_common(require_ARB_fp, SCALAR_OP, ir_unop_sin, 3); }
+SLE{sz}{cc}{sat} { return_common(require_NV_fp, SET_OP, ir_binop_lequal, 3); }
+SLT{sz}{cc}{sat} { return_common( true, SET_OP, ir_binop_less, 3); }
+SNE{sz}{cc}{sat} { return_common(require_NV_fp, SET_OP, ir_binop_nequal, 3); }
+STR{sz}{cc}{sat} { return_opcode(require_NV_fp, STR_OP, 3); }
+SUB{sz}{cc}{sat} { return_common( true, BIN_OP, ir_binop_sub, 3); }
+SWZ{sat} { return_opcode( true, SWZ_OP, 3); }
+
+TEX{cc}{sat} { return_opcode(require_ARB_fp, TEX_OP, 3); }
+TXB{cc}{sat} { return_opcode(require_ARB_fp, TXB_OP, 3); }
+TXD{cc}{sat} { return_opcode(require_NV_fp, TXD_OP, 3); }
+TXP{cc}{sat} { return_opcode(require_ARB_fp, TXP_OP, 3); }
+
+UP2H{cc}{sat} { return_opcode(require_NV_fp, UNPACK_OP, 4); }
+UP2US{cc}{sat} { return_opcode(require_NV_fp, UNPACK_OP, 5); }
+UP4B{cc}{sat} { return_opcode(require_NV_fp, UNPACK_OP, 4); }
+UP4UB{cc}{sat} { return_opcode(require_NV_fp, UNPACK_OP, 5); }
+
+X2D{szf}{cc}{sat} { return_opcode(require_NV_fp, X2D_OP, 3); }
+XPD{sat} { return_opcode( true, XPD_OP, 3); }
vertex { return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); }
fragment { return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); }
diff --git a/src/mesa/program/program_parse.y b/src/mesa/program/program_parse.y
index 0c70307f013..8391392fe75 100644
--- a/src/mesa/program/program_parse.y
+++ b/src/mesa/program/program_parse.y
@@ -35,15 +35,37 @@ extern "C" {
#include "program/prog_instruction.h"
#include "program/symbol_table.h"
-#include "program/program_parser.h"
extern void *yy_scan_string(char *);
extern void yy_delete_buffer(void *);
-extern int yylex(union YYSTYPE*, struct YYLTYPE*, void*);
};
-static struct asm_symbol *declare_variable(struct asm_parser_state *state,
- char *name, enum asm_type t, struct YYLTYPE *locp);
+extern int yylex(union YYSTYPE*, struct YYLTYPE*, void*);
+
+#include "glsl_types.h"
+#include "ir.h"
+#include "program/program_parser.h"
+
+static ir_rvalue *saturate_value(void *mem_ctx, unsigned saturate_mode,
+ ir_rvalue *expr);
+
+static ir_rvalue *generate_rhs_for_write_mask(void *mem_ctx,
+ unsigned write_mask, ir_rvalue *v);
+
+static ir_assignment *emit_vector_assignment(void *mem_ctx,
+ ir_dereference *dst, unsigned write_mask, unsigned saturate_mode,
+ ir_rvalue *v);
+
+static ir_assignment *emit_scalar_assignment(void *mem_ctx,
+ ir_dereference *dst, unsigned write_mask, unsigned saturate_mode,
+ ir_rvalue *sc);
+
+static ir_texture *texture_instruction_common(struct asm_parser_state *state,
+ enum ir_texture_opcode opcode, ir_rvalue *tex_coord, unsigned unit,
+ const glsl_type *sampler_type, struct YYLTYPE *sampler_loc);
+
+static bool declare_variable(struct asm_parser_state *state, ir_variable *var,
+ enum asm_type t, struct YYLTYPE *locp);
static int add_state_reference(struct gl_program_parameter_list *param_list,
const gl_state_index tokens[STATE_LENGTH]);
@@ -54,10 +76,6 @@ static int initialize_symbol_from_state(struct gl_program *prog,
static int initialize_symbol_from_param(struct gl_program *prog,
struct asm_symbol *param_var, const unsigned tokens[STATE_LENGTH]);
-static int initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var, const struct asm_vector *vec,
- GLboolean allowSwizzle);
-
static int yyparse(struct asm_parser_state *state);
static char *make_error_string(const char *fmt, ...);
@@ -68,37 +86,6 @@ static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
static int validate_inputs(struct YYLTYPE *locp,
struct asm_parser_state *state);
-static void init_dst_reg(struct prog_dst_register *r);
-
-static void set_dst_reg(struct prog_dst_register *r,
- gl_register_file file, GLint index);
-
-static void init_src_reg(struct asm_src_register *r);
-
-static void set_src_reg(struct asm_src_register *r,
- gl_register_file file, GLint index);
-
-static void set_src_reg_swz(struct asm_src_register *r,
- gl_register_file file, GLint index, GLuint swizzle);
-
-static void asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst, const struct asm_src_register *src0,
- const struct asm_src_register *src1, const struct asm_src_register *src2);
-
-static struct asm_instruction *asm_instruction_copy_ctor(
- const struct prog_instruction *base, const struct prog_dst_register *dst,
- const struct asm_src_register *src0, const struct asm_src_register *src1,
- const struct asm_src_register *src2);
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE (!FALSE)
-#endif
-
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (YYID(N)) { \
@@ -127,13 +114,10 @@ static struct asm_instruction *asm_instruction_copy_ctor(
%lex-param { void *scanner }
%union {
- struct asm_instruction *inst;
- struct asm_symbol *sym;
+ ir_instruction *inst;
struct asm_symbol temp_sym;
struct asm_swizzle_mask swiz_mask;
- struct asm_src_register src_reg;
struct prog_dst_register dst_reg;
- struct prog_instruction temp_inst;
char *string;
unsigned result;
unsigned attrib;
@@ -141,8 +125,18 @@ static struct asm_instruction *asm_instruction_copy_ctor(
float real;
unsigned state[STATE_LENGTH];
int negate;
- struct asm_vector vector;
- gl_inst_opcode opcode;
+
+ ir_variable *var;
+ ir_rvalue *rvalue;
+
+ struct asm_opcode opcode;
+
+ struct {
+ ir_dereference *deref;
+ unsigned write_mask;
+ } lvalue;
+
+ const glsl_type *type;
struct {
unsigned swz;
@@ -163,8 +157,11 @@ static struct asm_instruction *asm_instruction_copy_ctor(
%token END
/* Tokens for instructions */
-%token <temp_inst> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP
-%token <temp_inst> ARL KIL SWZ TXD_OP
+%token <opcode> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP VECTOR_OP
+%token <opcode> ARL KIL CMP_OP DP3_OP DP4_OP DPH_OP DST_OP
+%token <opcode> LRP_OP MAD_OP MOV_OP PACK_OP
+%token <opcode> RFL_OP SCS_OP SET_OP SFL_OP STR_OP SWZ_OP
+%token <opcode> TEX_OP TXB_OP TXD_OP TXP_OP UNPACK_OP X2D_OP XPD_OP
%token <integer> INTEGER
%token <real> REAL
@@ -203,16 +200,18 @@ static struct asm_instruction *asm_instruction_copy_ctor(
%type <inst> TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction
%type <inst> KIL_instruction
-%type <dst_reg> dstReg maskedDstReg maskedAddrReg
-%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
+%type <var> dstReg
+%type <lvalue> maskedDstReg
+%type <rvalue> maskedAddrReg
+%type <rvalue> srcReg scalarUse scalarSrcReg swizzleSrcReg
%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
%type <ext_swizzle> extSwizComp extSwizSel
%type <swiz_mask> optionalMask
-%type <sym> progParamArray
+%type <rvalue> progParamArray
%type <integer> addrRegRelOffset addrRegPosOffset addrRegNegOffset
-%type <src_reg> progParamArrayMem progParamArrayAbs progParamArrayRel
-%type <sym> addrReg
+%type <rvalue> progParamArrayMem progParamArrayAbs progParamArrayRel
+%type <var> addrReg
%type <swiz_mask> addrComponent addrWriteMask
%type <dst_reg> ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask
@@ -224,7 +223,8 @@ static struct asm_instruction *asm_instruction_copy_ctor(
%type <integer> optTexImageUnitNum texImageUnitNum
%type <integer> optTexCoordUnitNum texCoordUnitNum
%type <integer> optLegacyTexUnitNum legacyTexUnitNum
-%type <integer> texImageUnit texTarget
+%type <integer> texImageUnit
+%type <type> texTarget
%type <integer> vtxAttribNum
%type <attrib> attribBinding vtxAttribItem fragAttribItem
@@ -261,13 +261,13 @@ static struct asm_instruction *asm_instruction_copy_ctor(
%type <state> programMultipleItem progEnvParams progLocalParams
%type <temp_sym> paramMultipleInit paramMultInitList paramMultipleItem
-%type <temp_sym> paramSingleItemUse
+%type <rvalue> paramSingleItemUse
%type <integer> progEnvParamNum progLocalParamNum
%type <state> progEnvParamNums progLocalParamNums
-%type <vector> paramConstDecl paramConstUse
-%type <vector> paramConstScalarDecl paramConstScalarUse paramConstVector
+%type <rvalue> paramConstDecl paramConstUse
+%type <rvalue> paramConstScalarDecl paramConstScalarUse paramConstVector
%type <real> signedFloatConstant
%type <negate> optionalSign
@@ -336,15 +336,7 @@ statementSequence: statementSequence statement
statement: instruction ';'
{
if ($1 != NULL) {
- if (state->inst_tail == NULL) {
- state->inst_head = $1;
- } else {
- state->inst_tail->next = $1;
- }
-
- state->inst_tail = $1;
- $1->next = NULL;
-
+ state->ir.push_tail($1);
state->prog->NumInstructions++;
}
}
@@ -379,142 +371,562 @@ TexInstruction: SAMPLE_instruction
ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
{
- $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL);
+ ir_expression *f2i =
+ new(state) ir_expression(ir_unop_f2i, glsl_type::int_type, $4);
+
+ $$ = new(state) ir_assignment($2, f2i, NULL);
}
;
VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ ir_rvalue *expr =
+ new(state) ir_expression($1.opcode, $4->type, $4);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | MOV_OP maskedDstReg ',' swizzleSrcReg
+ {
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, $4);
+ }
+ | PACK_OP maskedDstReg ',' swizzleSrcReg
+ {
+ /* FINISHME: Add support for "pack" opcodes.
+ */
+ $$ = NULL;
}
;
SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+ ir_rvalue *expr = new(state) ir_expression($1.opcode, $4->type, $4);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | SCS_OP maskedDstReg ',' scalarSrcReg
+ {
+ ir_rvalue *const angle = $4;
+
+ /* The ARB_fragment_program spec says, "The z and w components of
+ * the result vector are undefined." We'll simplify this by leaving
+ * those components unmodified.
+ */
+ $2.write_mask &= WRITEMASK_XY;
+
+ /* The only known architecture that implements an actual SCS
+ * instruction is i965. However, the driver doesn't use it. For
+ * that reason, emit SCS as separate instances of
+ * ir_unop_sin_reduced and ir_unop_cos_reduced.
+ *
+ * Note that if the program contains an instruction like
+ *
+ * SCS d.wz, s.x;
+ *
+ * no code will be emitted.
+ */
+ if (($2.write_mask & WRITEMASK_X) != 0) {
+ ir_rvalue *const sin_expr =
+ new(state) ir_expression(ir_unop_sin_reduced,
+ glsl_type::float_type, angle);
+ ir_instruction *const inst =
+ emit_vector_assignment(state,
+ $2.deref->clone(state, NULL),
+ WRITEMASK_X,
+ $1.saturate_mode,
+ sin_expr);
+ state->ir.push_tail(inst);
+ }
+
+ if (($2.write_mask & WRITEMASK_Y) != 0) {
+ ir_rvalue *const cos_expr =
+ new(state) ir_expression(ir_unop_cos_reduced,
+ glsl_type::float_type, angle);
+ ir_instruction *const inst =
+ emit_vector_assignment(state,
+ $2.deref->clone(state, NULL),
+ WRITEMASK_Y,
+ $1.saturate_mode,
+ cos_expr);
+ state->ir.push_tail(inst);
+ }
+
+ $$ = NULL;
+ }
+ | UNPACK_OP maskedDstReg ',' scalarSrcReg
+ {
+ /* FINISHME: Add support for "unpack" opcodes.
+ */
+ $$ = NULL;
}
;
BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
+ assert($1.opcode == ir_binop_pow);
+
+ ir_rvalue *expr =
+ new(state) ir_expression($1.opcode, $4->type, $4, $6);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
}
;
-
BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
+ ir_rvalue *expr =
+ new(state) ir_expression($1.opcode, $4->type, $4, $6);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
}
- ;
+ | DP3_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* Apply vec3 swizzles to the operands.
+ */
+ ir_rvalue *op0 = new(state) ir_swizzle($4, 0, 1, 2, 3, 3);
+ ir_rvalue *op1 = new(state) ir_swizzle($6, 0, 1, 2, 3, 3);
-TRIop_instruction: TRI_OP maskedDstReg ','
- swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_dot, glsl_type::float_type,
+ op0, op1);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | DP4_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_dot, glsl_type::float_type,
+ $4, $6);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | DPH_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
+ /* The first operand is replaced with vec4(op0.xyz, 1). Note that
+ * the operand is only cloned for two of the parameters of the
+ * ir_quadop_vector operation. This is intentional.
+ */
+ ir_rvalue *const op0 =
+ new(state) ir_expression(ir_quadop_vector,
+ glsl_type::vec4_type,
+ new(state) ir_swizzle($4,
+ 0, 0, 0, 0, 1),
+ new(state) ir_swizzle($4->clone(state, NULL),
+ 1, 0, 0, 0, 1),
+ new(state) ir_swizzle($4->clone(state, NULL),
+ 2, 0, 0, 0, 1),
+ new(state) ir_constant(1.0F));
+
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_dot, glsl_type::float_type,
+ op0, $6);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | DST_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* The ARB_vertex_program spec says that DST does:
+ * tmp0 = VectorLoad(op0);
+ * tmp1 = VectorLoad(op1);
+ * result.x = 1.0;
+ * result.y = tmp0.y * tmp1.y;
+ * result.z = tmp0.z;
+ * result.w = tmp1.w;
+ *
+ * This is implemented as:
+ *
+ * result = vec4(1.0, op0.y, op0.z, 1.0)
+ * * vec4(1.0, op1.y, 1.0, op1.w);
+ */
+ ir_rvalue *const op0 =
+ new(state) ir_expression(ir_quadop_vector,
+ glsl_type::vec4_type,
+ new(state) ir_constant(1.0F),
+ new(state) ir_swizzle($4,
+ 1, 0, 0, 0, 1),
+ new(state) ir_swizzle($4->clone(state, NULL),
+ 2, 0, 0, 0, 1),
+ new(state) ir_constant(1.0F));
+ ir_rvalue *const op1 =
+ new(state) ir_expression(ir_quadop_vector,
+ glsl_type::vec4_type,
+ new(state) ir_constant(1.0F),
+ new(state) ir_swizzle($6,
+ 1, 0, 0, 0, 1),
+ new(state) ir_constant(1.0F),
+ new(state) ir_swizzle($6->clone(state, NULL),
+ 3, 0, 0, 0, 1));
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec4_type,
+ op0, op1);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | RFL_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* The NV_fragment_program spec says that RFL does:
+ *
+ * axis = VectorLoad(op0);
+ * direction = VectorLoad(op1);
+ * tmp.w = (axis.x * axis.x + axis.y * axis.y +
+ * axis.z * axis.z);
+ * tmp.x = (axis.x * direction.x + axis.y * direction.y +
+ * axis.z * direction.z);
+ * tmp.x = 2.0 * tmp.x;
+ * tmp.x = tmp.x / tmp.w;
+ * result.x = tmp.x * axis.x - direction.x;
+ * result.y = tmp.x * axis.y - direction.y;
+ * result.z = tmp.x * axis.z - direction.z;
+ *
+ * tmp.x = 2.0 * dot(axis, direction) / dot(axis, axis)
+ */
+ ir_rvalue *const axis =
+ new(state) ir_swizzle($4, 0, 1, 2, 3, 3);
+ ir_rvalue *const direction =
+ new(state) ir_swizzle($6, 0, 1, 2, 3, 3);
+
+ ir_rvalue *denom =
+ new(state) ir_expression(ir_binop_dot, glsl_type::float_type,
+ axis, axis);
+
+ ir_rvalue *numer =
+ new(state) ir_expression(ir_binop_dot, glsl_type::float_type,
+ axis, direction);
+ ir_rvalue *tmp =
+ new(state) ir_expression(ir_binop_div, glsl_type::float_type,
+ numer, denom);
+
+ ir_constant *two = new(state) ir_constant(2.0f);
+
+ ir_rvalue *scale =
+ new(state) ir_expression(ir_binop_mul, glsl_type::float_type,
+ two, tmp);
+ ir_rvalue *scale_swiz =
+ new(state) ir_swizzle(scale, 0, 0, 0, 0, 3);
+
+ ir_rvalue *mul =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec3_type,
+ scale_swiz, axis);
+ ir_rvalue *sub =
+ new(state) ir_expression(ir_binop_sub, glsl_type::vec3_type,
+ mul, direction);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, sub);
+ }
+ | SET_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ ir_rvalue *cmp =
+ new(state) ir_expression($1.opcode, glsl_type::bvec4_type,
+ $4, $6);
+ ir_rvalue *b2f =
+ new(state) ir_expression(ir_unop_b2f, glsl_type::vec4_type, cmp);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, b2f);
+ }
+ | SFL_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* SFL - "set on false" always returns a vector of 0.0.
+ */
+ ir_rvalue *zero = ir_constant::zero(state, glsl_type::float_type);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, zero);
+ }
+ | STR_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* STR - "set on true" always returns a vector of 1.0.
+ */
+ ir_rvalue *const one = new(state) ir_constant(1.0F);
+
+ $$ = emit_scalar_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, one);
+ }
+ | XPD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* The ARB_vertex_program spec says that XPD does:
+ * tmp0 = VectorLoad(op0);
+ * tmp1 = VectorLoad(op1);
+ * result.x = tmp0.y * tmp1.z - tmp0.z * tmp1.y;
+ * result.y = tmp0.z * tmp1.x - tmp0.x * tmp1.z;
+ * result.z = tmp0.x * tmp1.y - tmp0.y * tmp1.x;
+ *
+ * No known hardware implements XPD as a native instruction.
+ * Instead generate the obvious sequence of multiplies and
+ * subtracts.
+ */
+ ir_expression *const mul1 =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec3_type,
+ new(state) ir_swizzle($4, 1, 2, 0, 0, 3),
+ new(state) ir_swizzle($6, 2, 0, 1, 0, 3));
+ ir_expression *const mul2 =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec3_type,
+ new(state) ir_swizzle($4, 2, 0, 1, 0, 3),
+ new(state) ir_swizzle($6, 1, 2, 0, 0, 3));
+ ir_expression *const sub =
+ new(state) ir_expression(ir_binop_sub, glsl_type::vec3_type,
+ mul1, mul2);
+
+ /* Since we're only generating three values, limit the write mask
+ * to at most .xyz.
+ */
+ $$ = emit_vector_assignment(state, $2.deref,
+ $2.write_mask & WRITEMASK_XYZ,
+ $1.saturate_mode, sub);
}
;
-SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+TRIop_instruction: CMP_OP maskedDstReg ','
+ swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
- if ($$ != NULL) {
- const GLbitfield tex_mask = (1U << $6);
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
+ /* The ARB_fragment_program spec says that CMP does:
+ *
+ * tmp0 = VectorLoad(op0);
+ * tmp1 = VectorLoad(op1);
+ * tmp2 = VectorLoad(op2);
+ * result.x = (tmp0.x < 0.0) ? tmp1.x : tmp2.x;
+ * result.y = (tmp0.y < 0.0) ? tmp1.y : tmp2.y;
+ * result.z = (tmp0.z < 0.0) ? tmp1.z : tmp2.z;
+ * result.w = (tmp0.w < 0.0) ? tmp1.w : tmp2.w;
+ *
+ * This is acomplished using two conditional assignments. For most
+ * backends, this will result in two CMP instructions being
+ * generated. This will look like:
+ *
+ * CMP dst, op0, op1, dst;
+ * CMP dst, op0, dst, op2;
+ *
+ * The peephole optimizer should be able to combine these into a
+ * single CMP instruction.
+ */
+ ir_rvalue *const cmp_rhs =
+ generate_rhs_for_write_mask(state, $2.write_mask, $4);
+ const glsl_type *const cmp_type =
+ glsl_type::get_instance(GLSL_TYPE_BOOL,
+ cmp_rhs->type->vector_elements, 1);
+ ir_rvalue *const cmp_expr =
+ new(state) ir_expression(ir_binop_less, cmp_type, cmp_rhs,
+ ir_constant::zero(state, cmp_rhs->type));
+ ir_rvalue *const not_expr =
+ new(state) ir_expression(ir_binop_gequal, cmp_type,
+ cmp_rhs->clone(state, NULL),
+ ir_constant::zero(state, cmp_rhs->type));
+
+ ir_rvalue *const op1 =
+ saturate_value(state, $1.saturate_mode,
+ generate_rhs_for_write_mask(state, $2.write_mask,
+ $6));
+ ir_rvalue *const op2 =
+ saturate_value(state, $1.saturate_mode,
+ generate_rhs_for_write_mask(state, $2.write_mask,
+ $8));
+
+ ir_instruction *inst;
+
+ inst = new(state) ir_assignment($2.deref,
+ op1,
+ cmp_expr,
+ $2.write_mask);
+ state->ir.push_tail(inst);
+
+ inst = new(state) ir_assignment($2.deref->clone(state, NULL),
+ op2,
+ not_expr,
+ $2.write_mask);
+ state->ir.push_tail(inst);
+
+ $$ = NULL;
+ }
+ | MAD_OP maskedDstReg ','
+ swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ ir_rvalue *mul =
+ new(state) ir_expression(ir_binop_mul, $4->type, $4, $6);
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_add, mul->type, mul, $8);
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | LRP_OP maskedDstReg ','
+ swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* The ARB_fragment_program spec says that LRP does:
+ *
+ * tmp0 = VectorLoad(op0);
+ * tmp1 = VectorLoad(op1);
+ * tmp2 = VectorLoad(op2);
+ * result.x = tmp0.x * tmp1.x + (1 - tmp0.x) * tmp2.x;
+ * result.y = tmp0.y * tmp1.y + (1 - tmp0.y) * tmp2.y;
+ * result.z = tmp0.z * tmp1.z + (1 - tmp0.z) * tmp2.z;
+ * result.w = tmp0.w * tmp1.w + (1 - tmp0.w) * tmp2.w;
+ *
+ * The per-component math can be rearranged slightly:
+ *
+ * result.x = (tmp0.x * tmp1.x) + tmp2.x - (tmp0.x * tmp2.x);
+ *
+ * result.x = (tmp0.x * tmp1.x) - (tmp0.x * tmp2.x) + tmp2.x;
+ *
+ * result.x = tmp0.x * (tmp1.x - tmp2.x) + tmp2.x;
+ *
+ * Becomes:
+ *
+ * SUB tmp, op1, op2;
+ * MAD result, op0, tmp, op2;
+ */
+ ir_rvalue *sub =
+ new(state) ir_expression(ir_binop_sub, $6->type, $6, $8);
+ ir_rvalue *mul =
+ new(state) ir_expression(ir_binop_mul, $4->type, $4, sub);
+ ir_rvalue *expr =
+ new(state) ir_expression(ir_binop_add, mul->type, mul, $8);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr);
+ }
+ | X2D_OP maskedDstReg ','
+ swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
+ {
+ /* The NV_fragment_program spec says that X2D does:
+ *
+ * tmp0 = VectorLoad(op0);
+ * tmp1 = VectorLoad(op1);
+ * tmp2 = VectorLoad(op2);
+ * result.x = tmp0.x + tmp1.x * tmp2.x + tmp1.y * tmp2.y;
+ * result.y = tmp0.y + tmp1.x * tmp2.z + tmp1.y * tmp2.w;
+ * result.z = tmp0.x + tmp1.x * tmp2.x + tmp1.y * tmp2.y;
+ * result.w = tmp0.y + tmp1.x * tmp2.z + tmp1.y * tmp2.w;
+ *
+ * Notice that result.x == result.z and result.y == result.w.
+ *
+ * This can be rewritten as:
+ *
+ * tmp3 = (tmp0 + (tmp1.xx * tmp2.xz + tmp1.yy * tmp2.yw))
+ * result = tmp3.xyxy
+ *
+ * Becomes:
+ *
+ * MAD tmp, op1.xxxx, op2.xzxz, op0.xyxy;
+ * MAD result, op1.yyyy, op2.ywyw, tmp;
+ */
+ ir_rvalue *const op0 = $4;
+ ir_rvalue *const op1 = $6;
+ ir_rvalue *const op2 = $8;
+
+ ir_rvalue *op1_xxxx =
+ new(state) ir_swizzle(op1, 0, 0, 0, 0, 4);
+ ir_rvalue *op1_yyyy =
+ new(state) ir_swizzle(op1, 1, 1, 1, 1, 4);
+ ir_rvalue *op2_xzxz =
+ new(state) ir_swizzle(op2, 0, 2, 0, 2, 4);
+ ir_rvalue *op2_ywyw =
+ new(state) ir_swizzle(op2, 1, 3, 1, 3, 4);
+ ir_rvalue *op0_xyxy =
+ new(state) ir_swizzle(op0, 0, 1, 0, 1, 4);
+
+ ir_rvalue *mul1 =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec4_type,
+ op1_xxxx, op2_xzxz);
+ ir_rvalue *expr1 =
+ new(state) ir_expression(ir_binop_add, glsl_type::vec4_type,
+ mul1, op0_xyxy);
+
+ ir_rvalue *mul2 =
+ new(state) ir_expression(ir_binop_mul, glsl_type::vec4_type,
+ op1_yyyy, op2_ywyw);
+ ir_rvalue *expr2 =
+ new(state) ir_expression(ir_binop_add, glsl_type::vec4_type,
+ mul2, expr1);
+
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, expr2);
+ }
+ ;
+
+SAMPLE_instruction: TEX_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ ir_texture *const tex =
+ texture_instruction_common(state, ir_tex, $4, $6, $8, & @8);
+
+ if (tex == NULL)
+ YYERROR;
- $$->Base.TexSrcUnit = $6;
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, tex);
+ }
+ | TXP_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ ir_texture *const tex =
+ texture_instruction_common(state, ir_tex, $4, $6, $8, & @8);
- if ($8 < 0) {
- shadow_tex = tex_mask;
+ if (tex == NULL)
+ YYERROR;
- $$->Base.TexSrcTarget = -$8;
- $$->Base.TexShadow = 1;
- } else {
- $$->Base.TexSrcTarget = $8;
- }
+ /* FINISHME: Set projector. Right now there is now way for the
+ * FINISHME: lexer to communicate the TXP opcode to the parser.
+ */
- target_mask = (1U << $$->Base.TexSrcTarget);
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, tex);
+ }
+ | TXB_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ ir_texture *const tex =
+ texture_instruction_common(state, ir_txb, $4, $6, $8, & @8);
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[$6] != 0)
- && ((state->prog->TexturesUsed[$6] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& @8, state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
+ if (tex == NULL)
+ YYERROR;
+ tex->lod_info.bias = new(state) ir_swizzle($4, 3, 3, 3, 3, 1);
- state->prog->TexturesUsed[$6] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, tex);
}
;
KIL_instruction: KIL swizzleSrcReg
{
- $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL);
- state->fragment.UsesKill = 1;
+ ir_constant *zero = ir_constant::zero(state, glsl_type::vec4_type);
+
+ ir_expression *cmp =
+ new(state) ir_expression(ir_binop_less, glsl_type::bvec4_type,
+ $2, zero);
+
+ ir_expression *any =
+ new(state) ir_expression(ir_unop_any, glsl_type::bool_type, cmp);
+
+ $$ = new(state) ir_discard(any);
}
| KIL ccTest
{
- $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
- $$->Base.DstReg.CondMask = $2.CondMask;
- $$->Base.DstReg.CondSwizzle = $2.CondSwizzle;
- $$->Base.DstReg.CondSrc = $2.CondSrc;
- state->fragment.UsesKill = 1;
+ /* FINISHME: Add support for NV-style condition codes.
+ */
+ $$ = NULL;
}
;
TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
{
- $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
- if ($$ != NULL) {
- const GLbitfield tex_mask = (1U << $10);
- GLbitfield shadow_tex = 0;
- GLbitfield target_mask = 0;
+ ir_texture *const tex =
+ texture_instruction_common(state, ir_txd, $4, $10, $12, & @12);
+ if (tex == NULL)
+ YYERROR;
- $$->Base.TexSrcUnit = $10;
-
- if ($12 < 0) {
- shadow_tex = tex_mask;
-
- $$->Base.TexSrcTarget = -$12;
- $$->Base.TexShadow = 1;
- } else {
- $$->Base.TexSrcTarget = $12;
- }
-
- target_mask = (1U << $$->Base.TexSrcTarget);
-
- /* If this texture unit was previously accessed and that access
- * had a different texture target, generate an error.
- *
- * If this texture unit was previously accessed and that access
- * had a different shadow mode, generate an error.
- */
- if ((state->prog->TexturesUsed[$10] != 0)
- && ((state->prog->TexturesUsed[$10] != target_mask)
- || ((state->prog->ShadowSamplers & tex_mask)
- != shadow_tex))) {
- yyerror(& @12, state,
- "multiple targets used on one texture image unit");
- YYERROR;
- }
-
+ tex->lod_info.grad.dPdx = $6;
+ tex->lod_info.grad.dPdx = $8;
- state->prog->TexturesUsed[$10] |= target_mask;
- state->prog->ShadowSamplers |= shadow_tex;
- }
+ $$ = emit_vector_assignment(state, $2.deref, $2.write_mask,
+ $1.saturate_mode, tex);
}
;
@@ -524,38 +936,90 @@ texImageUnit: TEXTURE_UNIT optTexImageUnitNum
}
;
-texTarget: TEX_1D { $$ = TEXTURE_1D_INDEX; }
- | TEX_2D { $$ = TEXTURE_2D_INDEX; }
- | TEX_3D { $$ = TEXTURE_3D_INDEX; }
- | TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; }
- | TEX_RECT { $$ = TEXTURE_RECT_INDEX; }
- | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; }
- | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; }
- | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; }
- | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; }
- | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; }
- | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; }
- | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; }
+texTarget: TEX_1D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_1D,
+ false, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_2D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_2D,
+ false, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_3D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_3D,
+ false, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_CUBE
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_CUBE,
+ false, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_RECT
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_RECT,
+ false, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_SHADOW1D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_1D,
+ true, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_SHADOW2D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_2D,
+ true, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_SHADOWRECT
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_RECT,
+ true, false, GLSL_TYPE_FLOAT);
+ }
+ | TEX_ARRAY1D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_1D,
+ false, true, GLSL_TYPE_FLOAT);
+ }
+ | TEX_ARRAY2D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_2D,
+ false, true, GLSL_TYPE_FLOAT);
+ }
+ | TEX_ARRAYSHADOW1D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_1D,
+ true, true, GLSL_TYPE_FLOAT);
+ }
+ | TEX_ARRAYSHADOW2D
+ {
+ $$ = glsl_type::get_sampler_instance(GLSL_SAMPLER_DIM_1D,
+ true, true, GLSL_TYPE_FLOAT);
+ }
;
-SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
+SWZ_instruction: SWZ_OP maskedDstReg ',' srcReg ',' extendedSwizzle
{
/* FIXME: Is this correct? Should the extenedSwizzle be applied
* FIXME: to the existing swizzle?
*/
+#if 0
$4.Base.Swizzle = $6.swizzle;
$4.Base.Negate = $6.mask;
$$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
+#else
+ $$ = NULL;
+#endif
}
;
scalarSrcReg: optionalSign scalarUse
{
- $$ = $2;
-
if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
+ $$ = new(state) ir_expression(ir_unop_neg, $2->type, $2);
+ } else {
+ $$ = $2;
}
}
| optionalSign '|' scalarUse '|'
@@ -567,100 +1031,96 @@ scalarSrcReg: optionalSign scalarUse
YYERROR;
}
+ ir_expression *abs_expr =
+ new(state) ir_expression(ir_unop_abs, $3->type, $3);
+
if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
+ $$ = new(state) ir_expression(ir_unop_neg, abs_expr->type,
+ abs_expr);
+ } else {
+ $$ = abs_expr;
}
-
- $$.Base.Abs = 1;
}
;
scalarUse: srcReg scalarSuffix
{
- $$ = $1;
-
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $2.swizzle);
+ $$ = new(state) ir_swizzle($1, GET_SWZ($2.swizzle, 0), 0, 0, 0, 1);
}
| paramConstScalarUse
{
- struct asm_symbol temp_sym;
-
- if (!state->option.NV_fragment) {
- yyerror(& @1, state, "expected scalar suffix");
- YYERROR;
- }
-
- memset(& temp_sym, 0, sizeof(temp_sym));
- temp_sym.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & temp_sym, & $1, GL_TRUE);
-
- set_src_reg_swz(& $$, PROGRAM_CONSTANT,
- temp_sym.param_binding_begin,
- temp_sym.param_binding_swizzle);
+ $$ = $1;
}
;
swizzleSrcReg: optionalSign srcReg swizzleSuffix
{
- $$ = $2;
+ const unsigned swz[4] = {
+ GET_SWZ($3.swizzle, 0), GET_SWZ($3.swizzle, 1),
+ GET_SWZ($3.swizzle, 2), GET_SWZ($3.swizzle, 3)
+ };
+
+ ir_rvalue *swz_expr = new(state) ir_swizzle($2, swz, 4);
if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
+ $$ = new(state) ir_expression(ir_unop_neg, swz_expr->type,
+ swz_expr);
+ } else {
+ $$ = swz_expr;
}
-
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $3.swizzle);
}
| optionalSign '|' srcReg swizzleSuffix '|'
{
- $$ = $3;
+ const unsigned swz[4] = {
+ GET_SWZ($4.swizzle, 0), GET_SWZ($4.swizzle, 1),
+ GET_SWZ($4.swizzle, 2), GET_SWZ($4.swizzle, 3)
+ };
- if (!state->option.NV_fragment) {
- yyerror(& @2, state, "unexpected character '|'");
- YYERROR;
- }
+ ir_rvalue *swz_expr = new(state) ir_swizzle($3, swz, 4);
+ ir_expression *abs_expr =
+ new(state) ir_expression(ir_unop_abs, swz_expr->type, swz_expr);
if ($1) {
- $$.Base.Negate = ~$$.Base.Negate;
+ $$ = new(state) ir_expression(ir_unop_neg, swz_expr->type,
+ abs_expr);
+ } else {
+ $$ = abs_expr;
}
-
- $$.Base.Abs = 1;
- $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $4.swizzle);
}
-
;
maskedDstReg: dstReg optionalMask optionalCcMask
{
- $$ = $1;
- $$.WriteMask = $2.mask;
- $$.CondMask = $3.CondMask;
- $$.CondSwizzle = $3.CondSwizzle;
- $$.CondSrc = $3.CondSrc;
-
- if ($$.File == PROGRAM_OUTPUT) {
+ if ($1->mode == ir_var_out) {
/* Technically speaking, this should check that it is in
* vertex program mode. However, PositionInvariant can never be
* set in fragment program mode, so it is somewhat irrelevant.
*/
if (state->option.PositionInvariant
- && ($$.Index == VERT_RESULT_HPOS)) {
+ && ($1->location == VERT_RESULT_HPOS)) {
yyerror(& @1, state, "position-invariant programs cannot "
"write position");
YYERROR;
}
- state->prog->OutputsWritten |= BITFIELD64_BIT($$.Index);
+ state->prog->OutputsWritten |= BITFIELD64_BIT($1->location);
}
+
+ $$.deref = new(state) ir_dereference_variable($1);
+ $$.write_mask = $2.mask;
+
+ /* FINISHME: Handle conditional write masks! */
}
;
maskedAddrReg: addrReg addrWriteMask
{
- set_dst_reg(& $$, PROGRAM_ADDRESS, 0);
- $$.WriteMask = $2.mask;
+ /* FINISHME: Once NV_vertex_program2_option is supported the
+ * FINISHME: addrWriteMask will need to be used. The right answer
+ * FINISHME: is probably to convert it to a swizzle and let the
+ * FINISHME: ARL/ARR/ARA convert the swizzle into a mask.
+ */
+ $$ = new(state) ir_dereference_variable($1);
}
;
@@ -776,136 +1236,117 @@ extSwizSel: INTEGER
srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */
{
- struct asm_symbol *const s = (struct asm_symbol *)
+ ir_variable *const var = (ir_variable *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
free($1);
- if (s == NULL) {
+ if (var == NULL) {
yyerror(& @1, state, "invalid operand variable");
YYERROR;
- } else if ((s->type != at_param) && (s->type != at_temp)
- && (s->type != at_attrib)) {
- yyerror(& @1, state, "invalid operand variable");
- YYERROR;
- } else if ((s->type == at_param) && s->param_is_array) {
- yyerror(& @1, state, "non-array access to array PARAM");
- YYERROR;
}
- init_src_reg(& $$);
- switch (s->type) {
- case at_temp:
- set_src_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
+ switch (ir_variable_mode(var->mode)) {
+ case ir_var_auto:
+ case ir_var_temporary:
break;
- case at_param:
- set_src_reg_swz(& $$, s->param_binding_type,
- s->param_binding_begin,
- s->param_binding_swizzle);
+
+ case ir_var_uniform:
+ if (var->type->is_array()) {
+ yyerror(& @1, state, "non-array access to array PARAM");
+ YYERROR;
+ }
break;
- case at_attrib:
- set_src_reg(& $$, PROGRAM_INPUT, s->attrib_binding);
- state->prog->InputsRead |= (1U << $$.Base.Index);
+ case ir_var_in:
+ state->prog->InputsRead |= (1U << var->location);
if (!validate_inputs(& @1, state)) {
YYERROR;
}
break;
- default:
+ case ir_var_out:
+ case ir_var_inout:
+ yyerror(& @1, state, "invalid operand variable");
YYERROR;
- break;
}
+
+ $$ = new(state) ir_dereference_variable(var);
}
| attribBinding
{
+#if 0
set_src_reg(& $$, PROGRAM_INPUT, $1);
state->prog->InputsRead |= (1U << $$.Base.Index);
if (!validate_inputs(& @1, state)) {
YYERROR;
}
+#else
+ $$ = NULL;
+#endif
}
| progParamArray '[' progParamArrayMem ']'
{
- if (! $3.Base.RelAddr
- && ((unsigned) $3.Base.Index >= $1->param_binding_length)) {
+ ir_constant *c = $3->as_constant();
+ if ((c != NULL) && (c->value.u[0] >= $1->type->length)) {
yyerror(& @3, state, "out of bounds array access");
YYERROR;
}
- init_src_reg(& $$);
- $$.Base.File = $1->param_binding_type;
-
- if ($3.Base.RelAddr) {
- state->prog->IndirectRegisterFiles |= (1 << $$.Base.File);
- $1->param_accessed_indirectly = 1;
-
- $$.Base.RelAddr = 1;
- $$.Base.Index = $3.Base.Index;
- $$.Symbol = $1;
- } else {
- $$.Base.Index = $1->param_binding_begin + $3.Base.Index;
- }
+ $$ = new(state) ir_dereference_array($1, $3);
}
| paramSingleItemUse
{
- gl_register_file file = ($1.name != NULL)
- ? $1.param_binding_type
- : PROGRAM_CONSTANT;
- set_src_reg_swz(& $$, file, $1.param_binding_begin,
- $1.param_binding_swizzle);
+ $$ = $1;
}
;
dstReg: resultBinding
{
+#if 0
set_dst_reg(& $$, PROGRAM_OUTPUT, $1);
+#else
+ $$ = NULL;
+#endif
}
| USED_IDENTIFIER /* temporaryReg | vertexResultReg */
{
- struct asm_symbol *const s = (struct asm_symbol *)
+ ir_variable *const var = (ir_variable *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
free($1);
- if (s == NULL) {
+ if (var == NULL) {
yyerror(& @1, state, "invalid operand variable");
YYERROR;
- } else if ((s->type != at_output) && (s->type != at_temp)) {
+ } else if ((var->mode != ir_var_auto)
+ && (var->mode != ir_var_out)
+ && (var->mode != ir_var_inout)
+ && (var->mode != ir_var_temporary)) {
yyerror(& @1, state, "invalid operand variable");
YYERROR;
- }
-
- switch (s->type) {
- case at_temp:
- set_dst_reg(& $$, PROGRAM_TEMPORARY, s->temp_binding);
- break;
- case at_output:
- set_dst_reg(& $$, PROGRAM_OUTPUT, s->output_binding);
- break;
- default:
- set_dst_reg(& $$, s->param_binding_type, s->param_binding_begin);
- break;
+ } else {
+ $$ = var;
}
}
;
progParamArray: USED_IDENTIFIER
{
- struct asm_symbol *const s = (struct asm_symbol *)
+ ir_variable *const var = (ir_variable *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
free($1);
- if (s == NULL) {
+ if (var == NULL) {
yyerror(& @1, state, "invalid operand variable");
YYERROR;
- } else if ((s->type != at_param) || !s->param_is_array) {
+ } else if (!var->type->is_array()) {
yyerror(& @1, state, "array access to non-PARAM variable");
YYERROR;
} else {
- $$ = s;
+ $$ = new(state) ir_dereference_variable(var);
}
}
;
@@ -914,20 +1355,25 @@ progParamArrayMem: progParamArrayAbs | progParamArrayRel;
progParamArrayAbs: INTEGER
{
- init_src_reg(& $$);
- $$.Base.Index = $1;
+ $$ = new(state) ir_constant(int($1));
}
;
progParamArrayRel: addrReg addrComponent addrRegRelOffset
{
- /* FINISHME: Add support for multiple address registers.
- */
/* FINISHME: Add support for 4-component address registers.
*/
- init_src_reg(& $$);
- $$.Base.RelAddr = 1;
- $$.Base.Index = $3;
+ ir_dereference_variable *deref =
+ new(state) ir_dereference_variable($1);
+
+ if ($3 != 0) {
+ ir_constant *c = new(state) ir_constant(int($3));
+
+ $$ = new(state) ir_expression(ir_binop_add, glsl_type::int_type,
+ deref, c);
+ } else {
+ $$ = deref;
+ }
}
;
@@ -966,20 +1412,20 @@ addrRegNegOffset: INTEGER
addrReg: USED_IDENTIFIER
{
- struct asm_symbol *const s = (struct asm_symbol *)
+ ir_variable *const var = (ir_variable *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
free($1);
- if (s == NULL) {
+ if (var == NULL) {
yyerror(& @1, state, "invalid array member");
YYERROR;
- } else if (s->type != at_address) {
+ } else if (!var->type->is_integer()) {
yyerror(& @1, state,
"invalid variable for indexed array access");
YYERROR;
} else {
- $$ = s;
+ $$ = var;
}
}
;
@@ -1105,20 +1551,25 @@ namingStatement: ATTRIB_statement
ATTRIB_statement: ATTRIB IDENTIFIER '=' attribBinding
{
- struct asm_symbol *const s =
- declare_variable(state, $2, at_attrib, & @2);
-
- if (s == NULL) {
- free($2);
+ /* Each attribute location can be bound to at most one user-defined
+ * name. Verify that this run has not been violated.
+ */
+ state->InputsBound |= (1U << $4);
+ if (!validate_inputs(& @4, state)) {
YYERROR;
- } else {
- s->attrib_binding = $4;
- state->InputsBound |= (1U << s->attrib_binding);
+ }
- if (!validate_inputs(& @4, state)) {
- YYERROR;
- }
+ ir_variable *v =
+ new(state) ir_variable(glsl_type::vec4_type, $2, ir_var_in);
+
+ v->explicit_location = true;
+ v->location = $4;
+
+ if (!declare_variable(state, v, at_attrib, & @2)) {
+ YYERROR;
}
+
+ state->ir.push_tail(v);
}
;
@@ -1213,6 +1664,10 @@ PARAM_statement: PARAM_singleStmt | PARAM_multipleStmt;
PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit
{
+#if 0
+ ir_variable *v =
+ new(state) ir_variable(glsl_type::vec4_type, $2, ir_var_uniform);
+
struct asm_symbol *const s =
declare_variable(state, $2, at_param, & @2);
@@ -1226,11 +1681,13 @@ PARAM_singleStmt: PARAM IDENTIFIER paramSingleInit
s->param_binding_swizzle = $3.param_binding_swizzle;
s->param_is_array = 0;
}
+#endif
}
;
PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit
{
+#if 0
if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) {
free($2);
yyerror(& @4, state,
@@ -1251,6 +1708,7 @@ PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit
s->param_is_array = 1;
}
}
+#endif
}
;
@@ -1304,28 +1762,36 @@ paramSingleItemDecl: stateSingleItem
| paramConstDecl
{
memset(& $$, 0, sizeof($$));
+#if 0
$$.param_binding_begin = ~0;
initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
+#endif
}
;
paramSingleItemUse: stateSingleItem
{
+#if 0
memset(& $$, 0, sizeof($$));
$$.param_binding_begin = ~0;
initialize_symbol_from_state(state->prog, & $$, $1);
+#else
+ $$ = NULL;
+#endif
}
| programSingleItem
{
+#if 0
memset(& $$, 0, sizeof($$));
$$.param_binding_begin = ~0;
initialize_symbol_from_param(state->prog, & $$, $1);
+#else
+ $$ = NULL;
+#endif
}
| paramConstUse
{
- memset(& $$, 0, sizeof($$));
- $$.param_binding_begin = ~0;
- initialize_symbol_from_const(state->prog, & $$, & $1, GL_TRUE);
+ $$ = $1;
}
;
@@ -1344,8 +1810,10 @@ paramMultipleItem: stateMultipleItem
| paramConstDecl
{
memset(& $$, 0, sizeof($$));
+#if 0
$$.param_binding_begin = ~0;
initialize_symbol_from_const(state->prog, & $$, & $1, GL_FALSE);
+#endif
}
;
@@ -1852,65 +2320,67 @@ paramConstUse: paramConstScalarUse | paramConstVector;
paramConstScalarDecl: signedFloatConstant
{
- $$.count = 4;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
+ ir_constant_data d = { { 0 } };
+ d.f[0] = $1;
+ d.f[1] = $1;
+ d.f[2] = $1;
+ d.f[3] = $1;
+
+ $$ = new(state) ir_constant(glsl_type::vec4_type, &d);
}
;
paramConstScalarUse: REAL
{
- $$.count = 1;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
+ $$ = new(state) ir_constant(float($1));
}
| INTEGER
{
- $$.count = 1;
- $$.data[0] = (float) $1;
- $$.data[1] = (float) $1;
- $$.data[2] = (float) $1;
- $$.data[3] = (float) $1;
+ $$ = new(state) ir_constant(float($1));
}
;
paramConstVector: '{' signedFloatConstant '}'
{
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = 0.0f;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
+ ir_constant_data d = { { 0 } };
+ d.f[0] = $2;
+ d.f[1] = 0.0f;
+ d.f[2] = 0.0f;
+ d.f[3] = 1.0f;
+
+ $$ = new(state) ir_constant(glsl_type::vec4_type, &d);
}
| '{' signedFloatConstant ',' signedFloatConstant '}'
{
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
+ ir_constant_data d = { { 0 } };
+ d.f[0] = $2;
+ d.f[1] = $4;
+ d.f[2] = 0.0f;
+ d.f[3] = 1.0f;
+
+ $$ = new(state) ir_constant(glsl_type::vec4_type, &d);
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant '}'
{
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = 1.0f;
+ ir_constant_data d = { { 0 } };
+ d.f[0] = $2;
+ d.f[1] = $4;
+ d.f[2] = $6;
+ d.f[3] = 1.0f;
+
+ $$ = new(state) ir_constant(glsl_type::vec4_type, &d);
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant ',' signedFloatConstant '}'
{
- $$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = $8;
+ ir_constant_data d = { { 0 } };
+ d.f[0] = $2;
+ d.f[1] = $4;
+ d.f[2] = $6;
+ d.f[3] = $8;
+
+ $$ = new(state) ir_constant(glsl_type::vec4_type, &d);
}
;
@@ -1924,9 +2394,9 @@ signedFloatConstant: optionalSign REAL
}
;
-optionalSign: '+' { $$ = FALSE; }
- | '-' { $$ = TRUE; }
- | { $$ = FALSE; }
+optionalSign: '+' { $$ = false; }
+ | '-' { $$ = true; }
+ | { $$ = false; }
;
TEMP_statement: optVarSize TEMP { $<integer>$ = $2; } varNameList
@@ -1976,15 +2446,25 @@ ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList
varNameList: varNameList ',' IDENTIFIER
{
- if (!declare_variable(state, $3, (asm_type) $<integer>0, & @3)) {
- free($3);
+ const glsl_type *type = (asm_type($<integer>0) == at_address)
+ ? glsl_type::int_type : glsl_type::vec4_type;
+
+ ir_variable *v = new(state) ir_variable(type, $3, ir_var_auto);
+
+ if (!declare_variable(state, v, (asm_type) $<integer>0, & @3)) {
YYERROR;
}
+
+ state->ir.push_tail(v);
}
| IDENTIFIER
{
- if (!declare_variable(state, $1, (asm_type) $<integer>0, & @1)) {
- free($1);
+ const glsl_type *type = (asm_type($<integer>0) == at_address)
+ ? glsl_type::int_type : glsl_type::vec4_type;
+
+ ir_variable *v = new(state) ir_variable(type, $1, ir_var_auto);
+
+ if (!declare_variable(state, v, (asm_type) $<integer>0, & @1)) {
YYERROR;
}
}
@@ -1992,15 +2472,17 @@ varNameList: varNameList ',' IDENTIFIER
OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding
{
- struct asm_symbol *const s =
- declare_variable(state, $3, at_output, & @3);
+ ir_variable *v =
+ new(state) ir_variable(glsl_type::vec4_type, $3, ir_var_out);
- if (s == NULL) {
- free($3);
+ v->explicit_location = true;
+ v->location = $5;
+
+ if (!declare_variable(state, v, at_output, & @3)) {
YYERROR;
- } else {
- s->output_binding = $5;
}
+
+ state->ir.push_tail(v);
}
;
@@ -2198,163 +2680,154 @@ string: IDENTIFIER
%%
-void
-asm_instruction_set_operands(struct asm_instruction *inst,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
+ir_rvalue *
+saturate_value(void *mem_ctx, unsigned saturate_mode, ir_rvalue *expr)
{
- /* In the core ARB extensions only the KIL instruction doesn't have a
- * destination register.
- */
- if (dst == NULL) {
- init_dst_reg(& inst->Base.DstReg);
- } else {
- inst->Base.DstReg = *dst;
- }
+ switch (saturate_mode) {
+ case SATURATE_OFF:
+ return expr;
- /* The only instruction that doesn't have any source registers is the
- * condition-code based KIL instruction added by NV_fragment_program_option.
- */
- if (src0 != NULL) {
- inst->Base.SrcReg[0] = src0->Base;
- inst->SrcReg[0] = *src0;
- } else {
- init_src_reg(& inst->SrcReg[0]);
- }
+ case SATURATE_ZERO_ONE: {
+ ir_rvalue *zero = ir_constant::zero(mem_ctx, expr->type);
+ ir_expression *min_expr =
+ new(mem_ctx) ir_expression(ir_binop_min, expr->type, expr, zero);
+ ir_constant_data d = { { 0 } };
- if (src1 != NULL) {
- inst->Base.SrcReg[1] = src1->Base;
- inst->SrcReg[1] = *src1;
- } else {
- init_src_reg(& inst->SrcReg[1]);
+ d.f[0] = 1.0F;
+ d.f[1] = 1.0F;
+ d.f[2] = 1.0F;
+ d.f[3] = 1.0F;
+
+ ir_rvalue *one = new(mem_ctx) ir_constant(expr->type, &d);
+
+ ir_expression *max_expr =
+ new(mem_ctx) ir_expression(ir_binop_max, expr->type, min_expr, one);
+
+ return max_expr;
}
- if (src2 != NULL) {
- inst->Base.SrcReg[2] = src2->Base;
- inst->SrcReg[2] = *src2;
- } else {
- init_src_reg(& inst->SrcReg[2]);
+ default:
+ assert(!"Should not get here.");
+ return expr;
}
}
-
-struct asm_instruction *
-asm_instruction_ctor(gl_inst_opcode op,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
+static unsigned
+count_bits(unsigned x)
{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
-
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = op;
-
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ /* Determine how many bits are set in the write mask. A swizzle
+ * must be generated to splat the generated scalar component across
+ * all the enabled write bits.
+ */
+ unsigned bits = 0;
+ for (unsigned i = 0; i < 4; i++) {
+ if ((x & (1U << i)) != 0)
+ bits++;
}
- return inst;
+ return bits;
}
-
-struct asm_instruction *
-asm_instruction_copy_ctor(const struct prog_instruction *base,
- const struct prog_dst_register *dst,
- const struct asm_src_register *src0,
- const struct asm_src_register *src1,
- const struct asm_src_register *src2)
+ir_rvalue *
+generate_rhs_for_write_mask(void *mem_ctx, unsigned write_mask, ir_rvalue *v)
{
- struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+ const unsigned bits = count_bits(write_mask);
+ assert((bits > 0) && (bits <= 4));
+ if (bits != 4)
+ v = new(mem_ctx) ir_swizzle(v, 0, 1, 2, 3, bits);
- if (inst) {
- _mesa_init_instructions(& inst->Base, 1);
- inst->Base.Opcode = base->Opcode;
- inst->Base.CondUpdate = base->CondUpdate;
- inst->Base.CondDst = base->CondDst;
- inst->Base.SaturateMode = base->SaturateMode;
- inst->Base.Precision = base->Precision;
+ return v;
+}
- asm_instruction_set_operands(inst, dst, src0, src1, src2);
- }
+ir_assignment *
+emit_vector_assignment(void *mem_ctx, ir_dereference *dst, unsigned write_mask,
+ unsigned saturate_mode, ir_rvalue *v)
+{
+ ir_rvalue *rhs =
+ saturate_value(mem_ctx, saturate_mode,
+ generate_rhs_for_write_mask(mem_ctx, write_mask, v));
- return inst;
+ return new(mem_ctx) ir_assignment(dst, rhs, NULL, write_mask);
}
-
-void
-init_dst_reg(struct prog_dst_register *r)
+ir_assignment *
+emit_scalar_assignment(void *mem_ctx, ir_dereference *dst, unsigned write_mask,
+ unsigned saturate_mode, ir_rvalue *sc)
{
- memset(r, 0, sizeof(*r));
- r->File = PROGRAM_UNDEFINED;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
+ assert(sc->type->is_scalar());
+ /* Determine how many bits are set in the write mask. A swizzle
+ * must be generated to splat the generated scalar component across
+ * all the enabled write bits.
+ */
+ const unsigned bits = count_bits(write_mask);
+ assert((bits > 0) && (bits <= 4));
+ if (bits > 1)
+ sc = new(mem_ctx) ir_swizzle(sc, 0, 0, 0, 0, bits);
+
+ return new(mem_ctx) ir_assignment(dst,
+ saturate_value(mem_ctx, saturate_mode, sc),
+ NULL, write_mask);
+}
-/** Like init_dst_reg() but set the File and Index fields. */
-void
-set_dst_reg(struct prog_dst_register *r, gl_register_file file, GLint index)
+ir_texture *
+texture_instruction_common(struct asm_parser_state *state,
+ enum ir_texture_opcode opcode, ir_rvalue *tex_coord,
+ unsigned unit, const glsl_type *sampler_type,
+ struct YYLTYPE *sampler_loc)
{
- const GLint maxIndex = 1 << INST_INDEX_BITS;
- const GLint minIndex = 0;
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- ASSERT(file == PROGRAM_TEMPORARY ||
- file == PROGRAM_ADDRESS ||
- file == PROGRAM_OUTPUT);
- memset(r, 0, sizeof(*r));
- r->File = file;
- r->Index = index;
- r->WriteMask = WRITEMASK_XYZW;
- r->CondMask = COND_TR;
- r->CondSwizzle = SWIZZLE_NOOP;
-}
+ char name[16];
+ snprintf(name, sizeof(name), "$sampler-%02d", unit);
+ ir_variable *sampler = (ir_variable *)
+ _mesa_symbol_table_find_symbol(state->st, 0, name);
-void
-init_src_reg(struct asm_src_register *r)
-{
- memset(r, 0, sizeof(*r));
- r->Base.File = PROGRAM_UNDEFINED;
- r->Base.Swizzle = SWIZZLE_NOOP;
- r->Symbol = NULL;
-}
+ if (sampler == NULL) {
+ sampler = new(state) ir_variable(sampler_type, name, ir_var_uniform);
+ state->ir.push_head(sampler);
+ }
+ /* If this texture unit was previously accessed using either a
+ * different texture target or a different shadow mode, generate an
+ * error.
+ */
+ if (sampler->type != sampler_type) {
+ yyerror(sampler_loc, state,
+ "multiple targets used on one texture image unit");
+ return NULL;
+ }
-/** Like init_src_reg() but set the File and Index fields.
- * \return GL_TRUE if a valid src register, GL_FALSE otherwise
- */
-void
-set_src_reg(struct asm_src_register *r, gl_register_file file, GLint index)
-{
- set_src_reg_swz(r, file, index, SWIZZLE_XYZW);
-}
+ ir_texture *const tex = new(state) ir_texture(opcode);
+
+ tex->sampler = new(state) ir_dereference_variable(sampler);
+
+ unsigned count = 0;
+ switch (tex->sampler->type->sampler_dimensionality) {
+ case GLSL_SAMPLER_DIM_1D:
+ count = 1;
+ break;
+ case GLSL_SAMPLER_DIM_2D:
+ case GLSL_SAMPLER_DIM_RECT:
+ count = 2;
+ break;
+ case GLSL_SAMPLER_DIM_3D:
+ case GLSL_SAMPLER_DIM_CUBE:
+ count = 3;
+ break;
+ }
+ if (tex->sampler->type->sampler_array)
+ count++;
-void
-set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
- GLuint swizzle)
-{
- const GLint maxIndex = (1 << INST_INDEX_BITS) - 1;
- const GLint minIndex = -(1 << INST_INDEX_BITS);
- ASSERT(file < PROGRAM_FILE_MAX);
- ASSERT(index >= minIndex);
- (void) minIndex;
- ASSERT(index <= maxIndex);
- (void) maxIndex;
- memset(r, 0, sizeof(*r));
- r->Base.File = file;
- r->Base.Index = index;
- r->Base.Swizzle = swizzle;
- r->Symbol = NULL;
-}
+ tex->coordinate = new(state) ir_swizzle(tex_coord, 0, 1, 2, 3, count);
+ if (tex->sampler->type->sampler_shadow) {
+ tex->shadow_comparitor =
+ new(state) ir_swizzle(tex_coord, 2, 2, 2, 2, 1);
+ }
+
+ return tex;
+}
/**
* Validate the set of inputs used by a program
@@ -2364,7 +2837,7 @@ set_src_reg_swz(struct asm_src_register *r, gl_register_file file, GLint index,
* the \c ATTRIB command.
*
* \return
- * \c TRUE if the combination of inputs used is valid, \c FALSE otherwise.
+ * \c true if the combination of inputs used is valid, \c false otherwise.
*/
int
validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
@@ -2380,43 +2853,30 @@ validate_inputs(struct YYLTYPE *locp, struct asm_parser_state *state)
}
-struct asm_symbol *
-declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
- struct YYLTYPE *locp)
+bool
+declare_variable(struct asm_parser_state *state, ir_variable *var,
+ enum asm_type t, struct YYLTYPE *locp)
{
- struct asm_symbol *s = NULL;
- struct asm_symbol *exist = (struct asm_symbol *)
- _mesa_symbol_table_find_symbol(state->st, 0, name);
-
-
- if (exist != NULL) {
+ if (_mesa_symbol_table_find_symbol(state->st, 0, var->name) != NULL) {
yyerror(locp, state, "redeclared identifier");
+ return false;
} else {
- s = (struct asm_symbol *) calloc(1, sizeof(struct asm_symbol));
- s->name = name;
- s->type = t;
-
switch (t) {
case at_temp:
if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
yyerror(locp, state, "too many temporaries declared");
- free(s);
- return NULL;
+ return false;
}
- s->temp_binding = state->prog->NumTemporaries;
state->prog->NumTemporaries++;
break;
case at_address:
if (state->prog->NumAddressRegs >= state->limits->MaxAddressRegs) {
yyerror(locp, state, "too many address registers declared");
- free(s);
- return NULL;
+ return false;
}
- /* FINISHME: Add support for multiple address registers.
- */
state->prog->NumAddressRegs++;
break;
@@ -2424,12 +2884,10 @@ declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
break;
}
- _mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
- s->next = state->sym;
- state->sym = s;
+ _mesa_symbol_table_add_symbol(state->st, 0, var->name, var);
}
- return s;
+ return true;
}
@@ -2559,40 +3017,6 @@ initialize_symbol_from_param(struct gl_program *prog,
}
-/**
- * Put a float/vector constant/literal into the parameter list.
- * \param param_var returns info about the parameter/constant's location,
- * binding, type, etc.
- * \param vec the vector/constant to add
- * \param allowSwizzle if true, try to consolidate constants which only differ
- * by a swizzle. We don't want to do this when building
- * arrays of constants that may be indexed indirectly.
- * \return index of the constant in the parameter list.
- */
-int
-initialize_symbol_from_const(struct gl_program *prog,
- struct asm_symbol *param_var,
- const struct asm_vector *vec,
- GLboolean allowSwizzle)
-{
- unsigned swizzle;
- const int idx = _mesa_add_unnamed_constant(prog->Parameters,
- vec->data, vec->count,
- allowSwizzle ? &swizzle : NULL);
-
- param_var->type = at_param;
- param_var->param_binding_type = PROGRAM_CONSTANT;
-
- if (param_var->param_binding_begin == ~0U) {
- param_var->param_binding_begin = idx;
- param_var->param_binding_swizzle = allowSwizzle ? swizzle : SWIZZLE_XYZW;
- }
- param_var->param_binding_length++;
-
- return idx;
-}
-
-
char *
make_error_string(const char *fmt, ...)
{
diff --git a/src/mesa/program/program_parse_extra.c b/src/mesa/program/program_parse_extra.c
index ae98b782b70..b4fd1b11003 100644
--- a/src/mesa/program/program_parse_extra.c
+++ b/src/mesa/program/program_parse_extra.c
@@ -36,12 +36,12 @@
int
_mesa_parse_instruction_suffix(const struct asm_parser_state *state,
const char *suffix,
- struct prog_instruction *inst)
+ struct asm_opcode *inst)
{
- inst->CondUpdate = 0;
- inst->CondDst = 0;
- inst->SaturateMode = SATURATE_OFF;
- inst->Precision = FLOAT32;
+ inst->cond_update = 0;
+ inst->cond_dst = 0;
+ inst->saturate_mode = SATURATE_OFF;
+ inst->precision = FLOAT32;
/* The first possible suffix element is the precision specifier from
@@ -50,15 +50,15 @@ _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
if (state->option.NV_fragment) {
switch (suffix[0]) {
case 'H':
- inst->Precision = FLOAT16;
+ inst->precision = FLOAT16;
suffix++;
break;
case 'R':
- inst->Precision = FLOAT32;
+ inst->precision = FLOAT32;
suffix++;
break;
case 'X':
- inst->Precision = FIXED12;
+ inst->precision = FIXED12;
suffix++;
break;
default:
@@ -71,7 +71,7 @@ _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
*/
if (state->option.NV_fragment) {
if (suffix[0] == 'C') {
- inst->CondUpdate = 1;
+ inst->cond_update = 1;
suffix++;
}
}
@@ -82,7 +82,7 @@ _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
*/
if (state->mode == ARB_fragment) {
if (strcmp(suffix, "_SAT") == 0) {
- inst->SaturateMode = SATURATE_ZERO_ONE;
+ inst->saturate_mode = SATURATE_ZERO_ONE;
suffix += 4;
}
}
diff --git a/src/mesa/program/program_parser.h b/src/mesa/program/program_parser.h
index 31871f3253c..36d23d059ee 100644
--- a/src/mesa/program/program_parser.h
+++ b/src/mesa/program/program_parser.h
@@ -22,8 +22,10 @@
*/
#pragma once
+#include <stdbool.h>
#include "main/config.h"
#include "main/mtypes.h"
+#include "list.h"
struct gl_context;
@@ -121,6 +123,60 @@ struct asm_src_register {
};
+struct asm_opcode {
+ /**
+ * This should be 'enum ir_expression_operation', but it can't be. This
+ * file is included in C source, and the enum comes from a C++ header. The
+ * rules for enums in C and C++ are so broken that you can't declare an
+ * enum varaible without having seen the full enum declaration. Even after
+ * seeing it, the compiler is just going to allocate an int, so WTF?
+ */
+ unsigned opcode;
+
+ /**
+ * Indicates that the instruction should update the condition code
+ * register.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ unsigned cond_update:1;
+
+ /**
+ * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the
+ * condition code register that is to be updated.
+ *
+ * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition
+ * code register 0 is available. In GL_NV_vertex_program3 mode, condition
+ * code registers 0 and 1 are available.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+ * NV_vertex_program2_option.
+ */
+ unsigned cond_dst:1;
+
+ /**
+ * Saturate each value of the vectored result to the range [0,1] or the
+ * range [-1,1]. \c SSAT mode (i.e., saturation to the range [-1,1]) is
+ * only available in NV_fragment_program2 mode.
+ * Value is one of the SATURATE_* tokens.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3.
+ */
+ unsigned saturate_mode:2;
+
+ /**
+ * Per-instruction selectable precision: FLOAT32, FLOAT16, FIXED12.
+ *
+ * \since
+ * NV_fragment_program, NV_fragment_program_option.
+ */
+ unsigned precision:3;
+};
+
struct asm_instruction {
struct prog_instruction Base;
struct asm_instruction *next;
@@ -137,6 +193,7 @@ enum asm_program_target {
struct asm_parser_state {
struct gl_context *ctx;
struct gl_program *prog;
+ struct exec_list ir;
/**
* Per-program target limits
@@ -236,6 +293,9 @@ typedef struct YYLTYPE {
#define YYLTYPE_IS_DECLARED 1
#define YYLTYPE_IS_TRIVIAL 1
+#ifdef __cplusplus
+extern "C" {
+#endif
extern GLboolean _mesa_parse_arb_program(struct gl_context *ctx, GLenum target,
const GLubyte *str, GLsizei len, struct asm_parser_state *state);
@@ -284,7 +344,7 @@ extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state,
* Non-zero on success, zero on failure.
*/
extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
- const char *suffix, struct prog_instruction *inst);
+ const char *suffix, struct asm_opcode *inst);
/**
* Parses a condition code name
@@ -299,4 +359,8 @@ extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
*/
extern int _mesa_parse_cc(const char *s);
+#ifdef __cplusplus
+};
+#endif
+
/*@}*/