2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Emit program instructions (PI code) from IR trees.
36 #include "prog_instruction.h"
37 #include "prog_parameter.h"
38 #include "prog_statevars.h"
39 #include "slang_emit.h"
43 * Assembly and IR info
47 slang_ir_opcode IrOpcode
;
49 gl_inst_opcode InstOpcode
;
50 GLuint ResultSize
, NumParams
;
55 static slang_ir_info IrInfo
[] = {
57 { IR_ADD
, "IR_ADD", OPCODE_ADD
, 4, 2 },
58 { IR_SUB
, "IR_SUB", OPCODE_SUB
, 4, 2 },
59 { IR_MUL
, "IR_MUL", OPCODE_MUL
, 4, 2 },
60 { IR_DIV
, "IR_DIV", OPCODE_NOP
, 0, 2 }, /* XXX broke */
61 { IR_DOT4
, "IR_DOT_4", OPCODE_DP4
, 1, 2 },
62 { IR_DOT3
, "IR_DOT_3", OPCODE_DP3
, 1, 2 },
63 { IR_CROSS
, "IR_CROSS", OPCODE_XPD
, 3, 2 },
64 { IR_MIN
, "IR_MIN", OPCODE_MIN
, 4, 2 },
65 { IR_MAX
, "IR_MAX", OPCODE_MAX
, 4, 2 },
66 { IR_SEQUAL
, "IR_SEQUAL", OPCODE_SEQ
, 4, 2 },
67 { IR_SNEQUAL
, "IR_SNEQUAL", OPCODE_SNE
, 4, 2 },
68 { IR_SGE
, "IR_SGE", OPCODE_SGE
, 4, 2 },
69 { IR_SGT
, "IR_SGT", OPCODE_SGT
, 4, 2 },
70 { IR_POW
, "IR_POW", OPCODE_POW
, 1, 2 },
72 { IR_I_TO_F
, "IR_I_TO_F", OPCODE_NOP
, 1, 1 },
73 { IR_EXP
, "IR_EXP", OPCODE_EXP
, 1, 1 },
74 { IR_EXP2
, "IR_EXP2", OPCODE_EX2
, 1, 1 },
75 { IR_LOG2
, "IR_LOG2", OPCODE_LG2
, 1, 1 },
76 { IR_RSQ
, "IR_RSQ", OPCODE_RSQ
, 1, 1 },
77 { IR_RCP
, "IR_RCP", OPCODE_RCP
, 1, 1 },
78 { IR_FLOOR
, "IR_FLOOR", OPCODE_FLR
, 4, 1 },
79 { IR_FRAC
, "IR_FRAC", OPCODE_FRC
, 4, 1 },
80 { IR_ABS
, "IR_ABS", OPCODE_ABS
, 4, 1 },
81 { IR_SIN
, "IR_SIN", OPCODE_SIN
, 1, 1 },
82 { IR_COS
, "IR_COS", OPCODE_COS
, 1, 1 },
84 { IR_SEQ
, "IR_SEQ", 0, 0, 0 },
85 { IR_LABEL
, "IR_LABEL", 0, 0, 0 },
86 { IR_JUMP
, "IR_JUMP", 0, 0, 0 },
87 { IR_CJUMP
, "IR_CJUMP", 0, 0, 0 },
88 { IR_CALL
, "IR_CALL", 0, 0, 0 },
89 { IR_MOVE
, "IR_MOVE", 0, 0, 1 },
90 { IR_LESS
, "IR_LESS", 0, 1, 2 },
91 { IR_NOT
, "IR_NOT", 0, 1, 1 },
92 { IR_VAR
, "IR_VAR", 0, 0, 0 },
93 { IR_VAR_DECL
, "IR_VAR_DECL", 0, 0, 0 },
94 { IR_FLOAT
, "IR_FLOAT", 0, 0, 0 },
95 { IR_FIELD
, "IR_FIELD", 0, 0, 0 },
96 { IR_NOP
, NULL
, OPCODE_NOP
, 0, 0 }
100 static slang_ir_info
*
101 slang_find_ir_info(slang_ir_opcode opcode
)
104 for (i
= 0; IrInfo
[i
].IrName
; i
++) {
105 if (IrInfo
[i
].IrOpcode
== opcode
) {
113 slang_ir_name(slang_ir_opcode opcode
)
115 return slang_find_ir_info(opcode
)->IrName
;
120 _slang_new_ir_storage(enum register_file file
, GLint index
, GLint size
)
122 slang_ir_storage
*st
;
123 st
= (slang_ir_storage
*) _mesa_calloc(sizeof(slang_ir_storage
));
134 _slang_clone_ir_storage(slang_ir_storage
*store
)
136 slang_ir_storage
*clone
137 = _slang_new_ir_storage(store
->File
, store
->Index
, store
->Size
);
143 swizzle_string(GLuint swizzle
)
148 for (i
= 1; i
< 5; i
++) {
149 s
[i
] = "xyzw"[GET_SWZ(swizzle
, i
-1)];
156 writemask_string(GLuint writemask
)
161 for (i
= 0; i
< 4; i
++) {
162 if (writemask
& (1 << i
))
170 storage_string(const slang_ir_storage
*st
)
172 static const char *files
[] = {
189 sprintf(s
, "%s[%d]", files
[st
->File
], st
->Index
);
191 sprintf(s
, "%s[%d..%d]", files
[st
->File
], st
->Index
,
192 st
->Index
+ st
->Size
- 1);
194 sprintf(s
, "%s", files
[st
->File
]);
200 sizeof_struct(const slang_struct
*s
)
207 _slang_sizeof_type_specifier(const slang_type_specifier
*spec
)
209 switch (spec
->type
) {
210 case slang_spec_void
:
213 case slang_spec_bool
:
215 case slang_spec_bvec2
:
217 case slang_spec_bvec3
:
219 case slang_spec_bvec4
:
223 case slang_spec_ivec2
:
225 case slang_spec_ivec3
:
227 case slang_spec_ivec4
:
229 case slang_spec_float
:
231 case slang_spec_vec2
:
233 case slang_spec_vec3
:
235 case slang_spec_vec4
:
237 case slang_spec_mat2
:
239 case slang_spec_mat3
:
241 case slang_spec_mat4
:
243 case slang_spec_sampler1D
:
244 case slang_spec_sampler2D
:
245 case slang_spec_sampler3D
:
246 case slang_spec_samplerCube
:
247 case slang_spec_sampler1DShadow
:
248 case slang_spec_sampler2DShadow
:
251 case slang_spec_struct
:
252 return sizeof_struct(spec
->_struct
);
253 case slang_spec_array
:
265 sizeof_type(const slang_fully_specified_type
*t
)
267 return _slang_sizeof_type_specifier(&t
->specifier
);
273 slang_print_ir(const slang_ir_node
*n
, int indent
)
279 if (n
->Opcode
!= IR_SEQ
)
281 printf("%3d:", indent
);
283 for (i
= 0; i
< indent
; i
++)
289 printf("SEQ at %p\n", (void*) n
);
291 assert(n
->Children
[0]);
292 assert(n
->Children
[1]);
293 slang_print_ir(n
->Children
[0], indent
+ IND
);
294 slang_print_ir(n
->Children
[1], indent
+ IND
);
297 printf("MOVE (writemask = %s)\n", writemask_string(n
->Writemask
));
298 slang_print_ir(n
->Children
[0], indent
+3);
299 slang_print_ir(n
->Children
[1], indent
+3);
302 printf("LABEL: %s\n", n
->Target
);
305 printf("JUMP %s\n", n
->Target
);
308 printf("CJUMP %s\n", n
->Target
);
309 slang_print_ir(n
->Children
[0], indent
+3);
312 printf("VAR %s%s at %s store %p\n",
313 (char *) n
->Var
->a_name
, swizzle_string(n
->Swizzle
),
314 storage_string(n
->Store
), (void*) n
->Store
);
317 printf("VAR_DECL %s (%p) at %s store %p\n",
318 (char *) n
->Var
->a_name
, (void*) n
->Var
, storage_string(n
->Store
),
322 printf("FIELD %s of\n", n
->Target
);
323 slang_print_ir(n
->Children
[0], indent
+3);
326 printf("ASMCALL %s(%d args)\n", n
->Target
, n
->Swizzle
);
329 printf("FLOAT %f %f %f %f\n",
330 n
->Value
[0], n
->Value
[1], n
->Value
[2], n
->Value
[3]);
333 printf("INT_TO_FLOAT %d\n", (int) n
->Value
[0]);
336 printf("%s (%p, %p)\n", slang_ir_name(n
->Opcode
),
337 (void*) n
->Children
[0], (void*) n
->Children
[1]);
338 slang_print_ir(n
->Children
[0], indent
+3);
339 slang_print_ir(n
->Children
[1], indent
+3);
345 alloc_temporary(slang_gen_context
*gc
, GLint size
)
347 const GLuint sz4
= (size
+ 3) / 4;
349 ASSERT(size
> 0); /* number of floats */
350 for (i
= 0; i
< MAX_PROGRAM_TEMPS
; i
++) {
352 for (j
= 0; j
< sz4
; j
++) {
353 if (!gc
->TempUsed
[i
+ j
]) {
358 /* found block of size/4 free regs */
359 for (j
= 0; j
< sz4
; j
++)
360 gc
->TempUsed
[i
+ j
] = GL_TRUE
;
369 is_temporary(const slang_gen_context
*gc
, const slang_ir_storage
*st
)
371 if (st
->File
== PROGRAM_TEMPORARY
&& gc
->TempUsed
[st
->Index
])
372 return gc
->TempUsed
[st
->Index
];
379 free_temporary(slang_gen_context
*gc
, GLuint r
, GLint size
)
381 const GLuint sz4
= (size
+ 3) / 4;
383 for (i
= 0; i
< sz4
; i
++) {
384 if (gc
->TempUsed
[r
+ i
])
385 gc
->TempUsed
[r
+ i
] = GL_FALSE
;
392 slang_find_input(GLenum target
, const char *name
, GLint index
)
398 static const struct input_info vertInputs
[] = {
399 { "gl_Vertex", VERT_ATTRIB_POS
},
400 { "gl_Normal", VERT_ATTRIB_NORMAL
},
401 { "gl_Color", VERT_ATTRIB_COLOR0
},
402 { "gl_SecondaryColor", VERT_ATTRIB_COLOR1
},
405 static const struct input_info fragInputs
[] = {
408 const struct input_info
*inputs
;
411 if (target
== GL_VERTEX_PROGRAM_ARB
) {
415 assert(target
== GL_FRAGMENT_PROGRAM_ARB
);
419 for (i
= 0; inputs
[i
].Name
; i
++) {
420 if (strcmp(inputs
[i
].Name
, name
) == 0) {
422 return inputs
[i
].Attrib
;
430 slang_find_output(GLenum target
, const char *name
, GLint index
)
436 static const struct output_info vertOutputs
[] = {
437 { "gl_Position", VERT_RESULT_HPOS
},
438 { "gl_FrontColor", VERT_RESULT_COL0
},
439 { "gl_BackColor", VERT_RESULT_BFC0
},
440 { "gl_FrontSecondaryColor", VERT_RESULT_COL1
},
441 { "gl_BackSecondaryColor", VERT_RESULT_BFC1
},
442 { "gl_TexCoord", VERT_RESULT_TEX0
}, /* XXX indexed */
443 { "gl_FogFragCoord", VERT_RESULT_FOGC
},
446 static const struct output_info fragOutputs
[] = {
447 { "gl_FragColor", FRAG_RESULT_COLR
},
450 const struct output_info
*outputs
;
453 if (target
== GL_VERTEX_PROGRAM_ARB
) {
454 outputs
= vertOutputs
;
457 assert(target
== GL_FRAGMENT_PROGRAM_ARB
);
458 outputs
= fragOutputs
;
461 for (i
= 0; outputs
[i
].Name
; i
++) {
462 if (strcmp(outputs
[i
].Name
, name
) == 0) {
464 return outputs
[i
].Attrib
;
472 * Lookup a named constant and allocate storage for the parameter in
473 * the given parameter list.
474 * \return position of the constant in the paramList.
477 slang_lookup_constant(const char *name
, GLint index
,
478 struct gl_program_parameter_list
*paramList
)
480 struct constant_info
{
484 static const struct constant_info info
[] = {
485 { "gl_MaxLights", GL_MAX_LIGHTS
},
486 { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES
},
487 { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS
},
488 { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS
},
489 { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS
},
490 { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS
},
491 { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS
},
492 { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
},
493 { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS
},
494 { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
},
495 { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
},
499 GLuint swizzle
; /* XXX use this */
501 for (i
= 0; info
[i
].Name
; i
++) {
502 if (strcmp(info
[i
].Name
, name
) == 0) {
504 GLfloat value
= -1.0;
506 _mesa_GetFloatv(info
[i
].Token
, &value
);
507 ASSERT(value
>= 0.0); /* sanity check that glGetFloatv worked */
508 pos
= _mesa_add_unnamed_constant(paramList
, &value
, 1, &swizzle
);
517 * Determine if 'name' is a state variable. If so, create a new program
518 * parameter for it, and return the param's index. Else, return -1.
521 slang_lookup_statevar(const char *name
, GLint index
,
522 struct gl_program_parameter_list
*paramList
)
526 const GLuint NumRows
; /** for matrices */
527 const GLuint Swizzle
;
528 const GLint Indexes
[6];
530 static const struct state_info state
[] = {
531 { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP
,
532 { STATE_MATRIX
, STATE_MODELVIEW
, 0, 0, 0, STATE_MATRIX_TRANSPOSE
} },
533 { "gl_NormalMatrix", 3, SWIZZLE_NOOP
,
534 { STATE_MATRIX
, STATE_MODELVIEW
, 0, 0, 0, STATE_MATRIX_INVTRANS
} },
535 { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP
,
536 { STATE_MATRIX
, STATE_PROJECTION
, 0, 0, 0, STATE_MATRIX_TRANSPOSE
} },
537 { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP
,
538 { STATE_MATRIX
, STATE_MVP
, 0, 0, 0, STATE_MATRIX_TRANSPOSE
} },
539 { "gl_TextureMatrix", 4, SWIZZLE_NOOP
,
540 { STATE_MATRIX
, STATE_TEXTURE
, 0, 0, 0, STATE_MATRIX_TRANSPOSE
} },
541 { NULL
, 0, 0, {0, 0, 0, 0, 0, 0} }
545 for (i
= 0; state
[i
].Name
; i
++) {
546 if (strcmp(state
[i
].Name
, name
) == 0) {
549 if (state
[i
].NumRows
> 1) {
552 GLint pos
[4], indexesCopy
[6];
553 /* make copy of state tokens */
554 for (j
= 0; j
< 6; j
++)
555 indexesCopy
[j
] = state
[i
].Indexes
[j
];
557 for (j
= 0; j
< state
[i
].NumRows
; j
++) {
558 indexesCopy
[3] = indexesCopy
[4] = j
; /* jth row of matrix */
559 pos
[j
] = _mesa_add_state_reference(paramList
, indexesCopy
);
565 /* non-matrix state */
567 = _mesa_add_state_reference(paramList
, state
[i
].Indexes
);
579 slang_alloc_uniform(struct gl_program
*prog
, const char *name
)
581 GLint i
= _mesa_add_uniform(prog
->Parameters
, name
, 4);
587 slang_alloc_varying(struct gl_program
*prog
, const char *name
)
589 GLint i
= _mesa_add_varying(prog
->Varying
, name
, 4); /* XXX fix size */
591 if (prog
->Target
== GL_VERTEX_PROGRAM_ARB
) {
593 i
+= VERT_RESULT_VAR0
;
594 prog
->OutputsWritten
|= (1 << i
);
596 prog
->OutputsWritten
|= (1 << (i
+ VERT_RESULT_VAR0
));
601 i
+= FRAG_ATTRIB_VAR0
;
602 prog
->InputsRead
|= (1 << i
);
604 prog
->InputsRead
|= (1 << (i
+ FRAG_ATTRIB_VAR0
));
613 * Allocate temporary storage for an intermediate result (such as for
614 * a multiply or add, etc.
617 slang_alloc_temp_storage(slang_gen_context
*gc
, slang_ir_node
*n
, GLint size
)
623 indx
= alloc_temporary(gc
, size
);
624 n
->Store
= _slang_new_ir_storage(PROGRAM_TEMPORARY
, indx
, size
);
629 * Allocate storage info for an IR node (n->Store).
630 * We may do any of the following:
631 * 1. Compute Store->File/Index for program inputs/outputs/uniforms/etc.
632 * 2. Allocate storage for user-declared variables.
633 * 3. Allocate intermediate/unnamed storage for complex expressions.
636 * If gc or prog is NULL, we may only be able to determine the Store->File
637 * but not an Index (register).
640 slang_resolve_storage(slang_gen_context
*gc
, slang_ir_node
*n
,
641 struct gl_program
*prog
)
648 /* allocate storage info for this node */
649 if (n
->Var
&& n
->Var
->aux
) {
650 /* node storage info = var storage info */
651 n
->Store
= (slang_ir_storage
*) n
->Var
->aux
;
654 /* alloc new storage info */
655 n
->Store
= _slang_new_ir_storage(PROGRAM_UNDEFINED
, -1, -5);
657 n
->Var
->aux
= n
->Store
;
661 if (n
->Opcode
== IR_VAR_DECL
) {
662 /* storage declaration */
664 if (n
->Store
->Index
< 0) { /* XXX assert this? */
666 n
->Store
->File
= PROGRAM_TEMPORARY
;
667 n
->Store
->Size
= sizeof_type(&n
->Var
->type
);
668 n
->Store
->Index
= alloc_temporary(gc
, n
->Store
->Size
);
669 printf("alloc var %s storage at %d (size %d)\n",
670 (char *) n
->Var
->a_name
,
673 assert(n
->Store
->Size
> 0);
674 n
->Var
->declared
= GL_TRUE
;
676 assert(n
->Store
->Size
> 0);
680 if (n
->Opcode
== IR_VAR
&& n
->Store
->File
== PROGRAM_UNDEFINED
) {
681 /* try to determine the storage for this variable */
686 if (n
->Store
->Size
< 0) {
687 /* determine var/storage size now */
688 n
->Store
->Size
= sizeof_type(&n
->Var
->type
);
689 assert(n
->Store
->Size
> 0);
693 assert(n
->Var
->declared
||
694 n
->Var
->type
.qualifier
== slang_qual_uniform
||
695 n
->Var
->type
.qualifier
== slang_qual_varying
||
696 n
->Var
->type
.qualifier
== slang_qual_fixedoutput
||
697 n
->Var
->type
.qualifier
== slang_qual_attribute
||
698 n
->Var
->type
.qualifier
== slang_qual_out
||
699 n
->Var
->type
.qualifier
== slang_qual_const
);
702 i
= slang_find_input(prog
->Target
, (char *) n
->Var
->a_name
, 0);
704 n
->Store
->File
= PROGRAM_INPUT
;
706 assert(n
->Store
->Size
> 0);
707 prog
->InputsRead
|= (1 << i
);
711 i
= slang_find_output(prog
->Target
, (char *) n
->Var
->a_name
, 0);
713 n
->Store
->File
= PROGRAM_OUTPUT
;
715 prog
->OutputsWritten
|= (1 << i
);
719 i
= slang_lookup_statevar((char *) n
->Var
->a_name
, 0, prog
->Parameters
);
721 n
->Store
->File
= PROGRAM_STATE_VAR
;
726 i
= slang_lookup_constant((char *) n
->Var
->a_name
, 0, prog
->Parameters
);
728 n
->Store
->File
= PROGRAM_CONSTANT
;
733 /* probably a uniform or varying */
734 if (n
->Var
->type
.qualifier
== slang_qual_uniform
) {
735 i
= slang_alloc_uniform(prog
, (char *) n
->Var
->a_name
);
737 n
->Store
->File
= PROGRAM_UNIFORM
;
742 else if (n
->Var
->type
.qualifier
== slang_qual_varying
) {
743 i
= slang_alloc_varying(prog
, (char *) n
->Var
->a_name
);
746 if (prog
->Target
== GL_VERTEX_PROGRAM_ARB
)
747 n
->Store
->File
= PROGRAM_OUTPUT
;
749 n
->Store
->File
= PROGRAM_INPUT
;
751 n
->Store
->File
= PROGRAM_VARYING
;
758 if (n
->Store
->File
== PROGRAM_UNDEFINED
&& n
->Store
->Index
< 0) {
759 /* ordinary local var */
760 assert(n
->Store
->Size
> 0);
761 n
->Store
->File
= PROGRAM_TEMPORARY
;
762 n
->Store
->Index
= alloc_temporary(gc
, n
->Store
->Size
);
768 static slang_ir_storage
*
769 alloc_constant(const GLfloat v
[], GLuint size
, struct gl_program
*prog
)
772 GLint ind
= _mesa_add_unnamed_constant(prog
->Parameters
, v
, size
, &swizzle
);
773 slang_ir_storage
*st
= _slang_new_ir_storage(PROGRAM_CONSTANT
, ind
, size
);
783 swizzle_compose(GLuint swz1
, GLuint swz2
)
786 for (i
= 0; i
< 4; i
++) {
787 GLuint c
= GET_SWZ(swz1
, i
);
788 s
[i
] = GET_SWZ(swz2
, c
);
790 swz
= MAKE_SWIZZLE4(s
[0], s
[1], s
[2], s
[3]);
797 * Convert IR storage to an instruction dst register.
800 storage_to_dst_reg(struct prog_dst_register
*dst
, const slang_ir_storage
*st
,
803 static const GLuint defaultWritemask
[4] = {
805 WRITEMASK_X
| WRITEMASK_Y
,
806 WRITEMASK_X
| WRITEMASK_Y
| WRITEMASK_Z
,
807 WRITEMASK_X
| WRITEMASK_Y
| WRITEMASK_Z
| WRITEMASK_W
809 dst
->File
= st
->File
;
810 dst
->Index
= st
->Index
;
811 assert(st
->File
!= PROGRAM_UNDEFINED
);
812 assert(st
->Size
>= 1);
813 assert(st
->Size
<= 4);
814 dst
->WriteMask
= defaultWritemask
[st
->Size
- 1] & writemask
;
819 * Convert IR storage to an instruction src register.
822 storage_to_src_reg(struct prog_src_register
*src
, const slang_ir_storage
*st
,
825 static const GLuint defaultSwizzle
[4] = {
826 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
),
827 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
828 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
829 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
)
832 src
->File
= st
->File
;
833 src
->Index
= st
->Index
;
834 assert(st
->File
!= PROGRAM_UNDEFINED
);
835 assert(st
->Size
>= 1);
836 assert(st
->Size
<= 4);
837 /* XXX swizzling logic here may need some work */
838 /*src->Swizzle = swizzle_compose(swizzle, defaultSwizzle[st->Size - 1]);*/
839 if (swizzle
!= SWIZZLE_NOOP
)
840 src
->Swizzle
= swizzle
;
842 src
->Swizzle
= defaultSwizzle
[st
->Size
- 1];
848 * Add new instruction at end of given program.
849 * \param prog the program to append instruction onto
850 * \param opcode opcode for the new instruction
851 * \return pointer to the new instruction
853 static struct prog_instruction
*
854 new_instruction(struct gl_program
*prog
, gl_inst_opcode opcode
)
856 struct prog_instruction
*inst
;
857 prog
->Instructions
= _mesa_realloc_instructions(prog
->Instructions
,
858 prog
->NumInstructions
,
859 prog
->NumInstructions
+ 1);
860 inst
= prog
->Instructions
+ prog
->NumInstructions
;
861 prog
->NumInstructions
++;
862 _mesa_init_instructions(inst
, 1);
863 inst
->Opcode
= opcode
;
868 static struct prog_instruction
*
869 gen(slang_gen_context
*gc
, slang_ir_node
*n
, struct gl_program
*prog
);
873 * Generate code for a simple binary-op instruction.
875 static struct prog_instruction
*
876 gen_binop(slang_gen_context
*gc
, slang_ir_node
*n
, struct gl_program
*prog
)
878 struct prog_instruction
*inst
;
879 const slang_ir_info
*info
= slang_find_ir_info(n
->Opcode
);
882 gen(gc
, n
->Children
[0], prog
);
883 gen(gc
, n
->Children
[1], prog
);
884 inst
= new_instruction(prog
, info
->InstOpcode
);
885 /* alloc temp storage for the result: */
886 if (!n
->Store
|| n
->Store
->File
== PROGRAM_UNDEFINED
) {
888 slang_alloc_temp_storage(gc
, n
, info
->ResultSize
);
890 slang_resolve_storage(gc
, n
, prog
);
893 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
894 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
,
895 n
->Children
[0]->Swizzle
);
896 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[1]->Store
,
897 n
->Children
[1]->Swizzle
);
898 inst
->Comment
= n
->Comment
;
903 static struct prog_instruction
*
904 gen_unop(slang_gen_context
*gc
, slang_ir_node
*n
, struct gl_program
*prog
)
906 struct prog_instruction
*inst
;
907 const slang_ir_info
*info
= slang_find_ir_info(n
->Opcode
);
910 assert(info
->NumParams
== 1);
912 gen(gc
, n
->Children
[0], prog
);
914 inst
= new_instruction(prog
, info
->InstOpcode
);
915 /*slang_resolve_storage(gc, n, prog);*/
918 slang_alloc_temp_storage(gc
, n
, info
->ResultSize
);
920 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
922 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
,
923 n
->Children
[0]->Swizzle
);
925 inst
->Comment
= n
->Comment
;
931 static struct prog_instruction
*
932 gen(slang_gen_context
*gc
, slang_ir_node
*n
, struct gl_program
*prog
)
934 struct prog_instruction
*inst
;
940 assert(n
->Children
[0]);
941 assert(n
->Children
[1]);
942 gen(gc
, n
->Children
[0], prog
);
943 inst
= gen(gc
, n
->Children
[1], prog
);
944 n
->Store
= n
->Children
[1]->Store
;
948 slang_resolve_storage(gc
, n
, prog
);
949 assert(n
->Store
->Index
>= 0);
950 assert(n
->Store
->Size
> 0);
953 /*printf("Gen: var ref\n");*/
955 int b
= !n
->Store
|| n
->Store
->Index
< 0;
957 slang_resolve_storage(gc
, n
, prog
);
958 /*assert(n->Store->Index >= 0);*/
959 assert(n
->Store
->Size
> 0);
964 assert(n
->Children
[1]);
965 inst
= gen(gc
, n
->Children
[1], prog
);
967 gen(gc
, n
->Children
[0], prog
);
970 if (inst
&& is_temporary(gc
, n
->Children
[1]->Store
)) {
971 /* Peephole optimization:
972 * Just modify the RHS to put its result into the dest of this
973 * MOVE operation. Then, this MOVE is a no-op.
975 free_temporary(gc
, n
->Children
[1]->Store
->Index
,
976 n
->Children
[1]->Store
->Size
);
977 *n
->Children
[1]->Store
= *n
->Children
[0]->Store
;
978 /* fixup the prev (RHS) instruction */
979 storage_to_dst_reg(&inst
->DstReg
, n
->Children
[0]->Store
, n
->Writemask
);
985 if (n
->Children
[0]->Store
->Size
> 4) {
986 /* move matrix/struct etc */
987 slang_ir_storage dstStore
= *n
->Children
[0]->Store
;
988 slang_ir_storage srcStore
= *n
->Children
[1]->Store
;
989 GLint size
= srcStore
.Size
;
990 ASSERT(n
->Children
[0]->Writemask
== WRITEMASK_XYZW
);
991 ASSERT(n
->Children
[1]->Swizzle
== SWIZZLE_NOOP
);
995 inst
= new_instruction(prog
, OPCODE_MOV
);
996 inst
->Comment
= _mesa_strdup("IR_MOVE block");
997 storage_to_dst_reg(&inst
->DstReg
, &dstStore
, n
->Writemask
);
998 storage_to_src_reg(&inst
->SrcReg
[0], &srcStore
,
999 n
->Children
[1]->Swizzle
);
1006 inst
= new_instruction(prog
, OPCODE_MOV
);
1007 storage_to_dst_reg(&inst
->DstReg
, n
->Children
[0]->Store
, n
->Writemask
);
1008 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[1]->Store
,
1009 n
->Children
[1]->Swizzle
);
1011 if (n
->Children
[1]->Store
->File
== PROGRAM_TEMPORARY
) {
1012 free_temporary(gc
, n
->Children
[1]->Store
->Index
,
1013 n
->Children
[1]->Store
->Size
);
1015 /*inst->Comment = _mesa_strdup("IR_MOVE");*/
1016 n
->Store
= n
->Children
[0]->Store
; /*XXX new */
1035 return gen_binop(gc
, n
, prog
);
1044 return gen_unop(gc
, n
, prog
);
1047 /*printf("LAB: %s\n", n->Target);*/
1051 inst
= new_instruction(prog
, OPCODE_BRA
);
1052 inst
->Comment
= _mesa_strdup(n
->Target
);
1056 n
->Store
= alloc_constant(n
->Value
, 4, prog
); /*XXX fix size */
1067 _slang_new_codegen_context(void)
1069 slang_gen_context
*gc
= (slang_gen_context
*) _mesa_calloc(sizeof(*gc
));
1076 _slang_emit_code(slang_ir_node
*n
, slang_gen_context
*gc
,
1077 struct gl_program
*prog
)
1079 /*GET_CURRENT_CONTEXT(ctx);*/
1082 gc = _slang_new_codegen_context();
1085 printf("************ Begin generate code\n");
1090 struct prog_instruction
*inst
;
1091 inst
= new_instruction(prog
, OPCODE_END
);
1094 printf("************ End generate code (%u inst):\n", prog
->NumInstructions
);
1097 _mesa_print_program(prog
);
1098 _mesa_print_program_parameters(ctx
,prog
);