summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Paul <brian.paul@tungstengraphics.com>2008-09-13 15:32:46 -0600
committerBrian Paul <brian.paul@tungstengraphics.com>2008-09-13 15:33:07 -0600
commit777aca8fc99986dacf043cc3c25911df4252cb42 (patch)
treeb44b69d17b83962005c089903dde2a94a2252874
parent870afb831921a5c38f22817d9e64d6be7fab235c (diff)
cell: implement negation, absolute value and set-sign for src regs in code gen
-rw-r--r--src/gallium/drivers/cell/ppu/cell_gen_fp.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/src/gallium/drivers/cell/ppu/cell_gen_fp.c b/src/gallium/drivers/cell/ppu/cell_gen_fp.c
index 0712d05b40b..8d8c095a7e2 100644
--- a/src/gallium/drivers/cell/ppu/cell_gen_fp.c
+++ b/src/gallium/drivers/cell/ppu/cell_gen_fp.c
@@ -178,6 +178,8 @@ get_src_reg(struct codegen *gen,
{
int reg = -1;
int swizzle = tgsi_util_get_full_src_register_extswizzle(src, channel);
+ boolean reg_is_itemp = FALSE;
+ uint sign_op;
assert(swizzle >= 0);
assert(swizzle <= 3);
@@ -193,6 +195,7 @@ get_src_reg(struct codegen *gen,
/* offset is measured in quadwords, not bytes */
int offset = src->SrcRegister.Index * 4 + channel;
reg = get_itemp(gen);
+ reg_is_itemp = TRUE;
/* Load: reg = memory[(machine_reg) + offset] */
spe_lqd(gen->f, reg, gen->inputs_reg, offset);
}
@@ -206,6 +209,43 @@ get_src_reg(struct codegen *gen,
assert(0);
}
+ /*
+ * Handle absolute value, negate or set-negative of src register.
+ */
+ sign_op = tgsi_util_get_full_src_register_sign_mode(src, channel);
+ if (sign_op != TGSI_UTIL_SIGN_KEEP) {
+ /*
+ * All sign ops are done by manipulating bit 31, the IEEE float sign bit.
+ */
+ const int bit31mask_reg = get_itemp(gen);
+ int result_reg;
+
+ if (reg_is_itemp) {
+ /* re-use 'reg' for the result */
+ result_reg = reg;
+ }
+ else {
+ /* alloc a new reg for the result */
+ result_reg = get_itemp(gen);
+ }
+
+ /* mask with bit 31 set, the rest cleared */
+ spe_load_int(gen->f, bit31mask_reg, (1 << 31));
+
+ if (sign_op == TGSI_UTIL_SIGN_CLEAR) {
+ spe_andc(gen->f, result_reg, reg, bit31mask_reg);
+ }
+ else if (sign_op == TGSI_UTIL_SIGN_SET) {
+ spe_and(gen->f, result_reg, reg, bit31mask_reg);
+ }
+ else {
+ assert(sign_op == TGSI_UTIL_SIGN_TOGGLE);
+ spe_xor(gen->f, result_reg, reg, bit31mask_reg);
+ }
+
+ reg = result_reg;
+ }
+
return reg;
}
@@ -416,7 +456,7 @@ emit_IF(struct codegen *gen, const struct tgsi_full_instruction *inst)
spe_comment(gen->f, -4, "IF:");
/* update execution mask with the predicate register */
- int tmp_reg = spe_allocate_available_register(gen->f);
+ int tmp_reg = get_itemp(gen);
int s1_reg = get_src_reg(gen, channel, &inst->FullSrcRegisters[0]);
/* tmp = (s1_reg == 0) */
@@ -428,7 +468,7 @@ emit_IF(struct codegen *gen, const struct tgsi_full_instruction *inst)
gen->if_nesting++;
- spe_release_register(gen->f, tmp_reg);
+ free_itemps(gen);
return true;
}