r300/compiler: Add support for inline literals
[mesa.git] / src / gallium / drivers / r300 / compiler / radeon_inline_literals.c
1
2 #include "radeon_compiler.h"
3 #include "radeon_compiler_util.h"
4 #include "radeon_dataflow.h"
5 #include "radeon_program.h"
6 #include "radeon_program_constants.h"
7 #include <stdio.h>
8
9 #define VERBOSE 0
10
11 #define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
12
13 /* IEEE-754:
14 * 22:0 mantissa
15 * 30:23 exponent
16 * 31 sign
17 *
18 * R300:
19 * 0:2 mantissa
20 * 3:6 exponent (bias 7)
21 */
22 static int ieee_754_to_r300_float(float f, unsigned char *r300_float_out)
23 {
24 unsigned float_bits = *((unsigned *)&f);
25 /* XXX: Handle big-endian */
26 unsigned mantissa = float_bits & 0x007fffff;
27 unsigned biased_exponent = (float_bits & 0x7f800000) >> 23;
28 unsigned negate = !!(float_bits & 0x80000000);
29 int exponent = biased_exponent - 127;
30 unsigned mantissa_mask = 0xff8fffff;
31 unsigned r300_exponent, r300_mantissa;
32
33 DBG("Converting %f (0x%x) to 7-bit:\n", f, float_bits);
34 DBG("Raw exponent = %d\n", exponent);
35
36 if (exponent < -7 || exponent > 8) {
37 DBG("Failed exponent out of range\n\n");
38 return 0;
39 }
40
41 if (mantissa & mantissa_mask) {
42 DBG("Failed mantisa has too many bits:\n"
43 "manitssa=0x%x mantissa_mask=0x%x, and=0x%x\n\n",
44 mantissa, mantissa_mask,
45 mantissa & mantissa_mask);
46 return 0;
47 }
48
49 r300_exponent = exponent + 7;
50 r300_mantissa = (mantissa & ~mantissa_mask) >> 20;
51 *r300_float_out = r300_mantissa | (r300_exponent << 3);
52
53 DBG("Success! r300_float = 0x%x\n\n", *r300_float_out);
54
55 if (negate)
56 return -1;
57 else
58 return 1;
59 }
60
61 void rc_inline_literals(struct radeon_compiler *c, void *user)
62 {
63 struct rc_instruction * inst;
64
65 for(inst = c->Program.Instructions.Next;
66 inst != &c->Program.Instructions;
67 inst = inst->Next) {
68 const struct rc_opcode_info * info =
69 rc_get_opcode_info(inst->U.I.Opcode);
70
71 unsigned src_idx;
72 struct rc_constant * constant;
73 float float_value;
74 unsigned char r300_float;
75 int ret;
76
77 /* XXX: Handle presub */
78
79 /* We aren't using rc_for_all_reads_src here, because presub
80 * sources need to be handled differently. */
81 for (src_idx = 0; src_idx < info->NumSrcRegs; src_idx++) {
82 unsigned new_swizzle;
83 unsigned use_literal = 0;
84 unsigned negate_mask = 0;
85 unsigned swz, chan;
86 struct rc_src_register * src_reg =
87 &inst->U.I.SrcReg[src_idx];
88 swz = RC_SWIZZLE_UNUSED;
89 if (src_reg->File != RC_FILE_CONSTANT) {
90 continue;
91 }
92 constant =
93 &c->Program.Constants.Constants[src_reg->Index];
94 if (constant->Type != RC_CONSTANT_IMMEDIATE) {
95 continue;
96 }
97 new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
98 for (chan = 0; chan < 4; chan++) {
99 unsigned char r300_float_tmp;
100 swz = GET_SWZ(src_reg->Swizzle, chan);
101 if (swz == RC_SWIZZLE_UNUSED) {
102 continue;
103 }
104 float_value = constant->u.Immediate[swz];
105 ret = ieee_754_to_r300_float(float_value,
106 &r300_float_tmp);
107 if (!ret || (use_literal &&
108 r300_float != r300_float_tmp)) {
109 use_literal = 0;
110 break;
111 }
112
113 if (ret == -1 && src_reg->Abs) {
114 use_literal = 0;
115 break;
116 }
117
118 if (!use_literal) {
119 r300_float = r300_float_tmp;
120 use_literal = 1;
121 }
122
123 /* Use RC_SWIZZLE_W for the inline constant, so
124 * it will become one of the alpha sources. */
125 SET_SWZ(new_swizzle, chan, RC_SWIZZLE_W);
126 if (ret == -1) {
127 negate_mask |= (1 << chan);
128 }
129 }
130
131 if (!use_literal) {
132 continue;
133 }
134 src_reg->File = RC_FILE_INLINE;
135 src_reg->Index = r300_float;
136 src_reg->Swizzle = new_swizzle;
137 src_reg->Negate = src_reg->Negate ^ negate_mask;
138 }
139 }
140 }