1/*
2 * Copyright 2012 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Author: Tom Stellard <thomas.stellard@amd.com>
24 */
25
26#include "radeon_compiler.h"
27#include "radeon_compiler_util.h"
28#include "radeon_dataflow.h"
29#include "radeon_program.h"
30#include "radeon_program_constants.h"
31#include "util/u_bitcast.h"
32#include <stdio.h>
33
34#define VERBOSE 0
35
36#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
37
38/* IEEE-754:
39 * 22:0 mantissa
40 * 30:23 exponent
41 * 31 sign
42 *
43 * R300:
44 * 0:2 mantissa
45 * 3:6 exponent (bias 7)
46 */
47static int ieee_754_to_r300_float(float f, unsigned char *r300_float_out)
48{
49	unsigned float_bits = u_bitcast_f2u(f);
50	/* XXX: Handle big-endian */
51	unsigned mantissa = float_bits &         0x007fffff;
52	unsigned biased_exponent = (float_bits & 0x7f800000) >> 23;
53	unsigned negate = !!(float_bits &         0x80000000);
54	int exponent = biased_exponent - 127;
55	unsigned mantissa_mask = 0xff8fffff;
56	unsigned r300_exponent, r300_mantissa;
57
58	DBG("Converting %f (0x%x) to 7-bit:\n", f, float_bits);
59	DBG("Raw exponent = %d\n", exponent);
60
61	if (exponent < -7 || exponent > 8) {
62		DBG("Failed exponent out of range\n\n");
63		return 0;
64	}
65
66	if (mantissa & mantissa_mask) {
67		DBG("Failed mantissa has too many bits:\n"
68			"mantissa=0x%x mantissa_mask=0x%x, and=0x%x\n\n",
69			mantissa, mantissa_mask,
70			mantissa & mantissa_mask);
71		return 0;
72	}
73
74	r300_exponent = exponent + 7;
75	r300_mantissa = (mantissa & ~mantissa_mask) >> 20;
76	*r300_float_out = r300_mantissa | (r300_exponent << 3);
77
78	DBG("Success! r300_float = 0x%x\n\n", *r300_float_out);
79
80	if (negate)
81		return -1;
82	else
83		return 1;
84}
85
86void rc_inline_literals(struct radeon_compiler *c, void *user)
87{
88	struct rc_instruction * inst;
89
90	for(inst = c->Program.Instructions.Next;
91					inst != &c->Program.Instructions;
92					inst = inst->Next) {
93		const struct rc_opcode_info * info =
94					rc_get_opcode_info(inst->U.I.Opcode);
95
96		unsigned src_idx;
97		struct rc_constant * constant;
98		float float_value;
99		unsigned char r300_float = 0;
100		int ret;
101
102		/* XXX: Handle presub */
103
104		/* We aren't using rc_for_all_reads_src here, because presub
105		 * sources need to be handled differently. */
106		for (src_idx = 0; src_idx < info->NumSrcRegs; src_idx++) {
107			unsigned new_swizzle;
108			unsigned use_literal = 0;
109			unsigned negate_mask = 0;
110			unsigned swz, chan;
111			struct rc_src_register * src_reg =
112						&inst->U.I.SrcReg[src_idx];
113			swz = RC_SWIZZLE_UNUSED;
114			if (src_reg->File != RC_FILE_CONSTANT) {
115				continue;
116			}
117			constant =
118				&c->Program.Constants.Constants[src_reg->Index];
119			if (constant->Type != RC_CONSTANT_IMMEDIATE) {
120				continue;
121			}
122			new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
123			for (chan = 0; chan < 4; chan++) {
124				unsigned char r300_float_tmp;
125				swz = GET_SWZ(src_reg->Swizzle, chan);
126				if (swz == RC_SWIZZLE_UNUSED) {
127					continue;
128				}
129				float_value = constant->u.Immediate[swz];
130				ret = ieee_754_to_r300_float(float_value,
131								&r300_float_tmp);
132				if (!ret || (use_literal &&
133						r300_float != r300_float_tmp)) {
134					use_literal = 0;
135					break;
136				}
137
138				if (ret == -1 && src_reg->Abs) {
139					use_literal = 0;
140					break;
141				}
142
143				if (!use_literal) {
144					r300_float = r300_float_tmp;
145					use_literal = 1;
146				}
147
148				/* Use RC_SWIZZLE_W for the inline constant, so
149				 * it will become one of the alpha sources. */
150				SET_SWZ(new_swizzle, chan, RC_SWIZZLE_W);
151				if (ret == -1) {
152					negate_mask |= (1 << chan);
153				}
154			}
155
156			if (!use_literal) {
157				continue;
158			}
159			src_reg->File = RC_FILE_INLINE;
160			src_reg->Index = r300_float;
161			src_reg->Swizzle = new_swizzle;
162			src_reg->Negate = src_reg->Negate ^ negate_mask;
163		}
164	}
165}
166