Home | History | Annotate | Download | only in compiler
      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 = 0;
     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 }
    141