aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Girlin <[email protected]>2013-05-05 06:03:14 +0400
committerVadim Girlin <[email protected]>2013-05-07 04:40:26 +0400
commitc9cf83b587fbc679df5ed445bfa12f3227f68a6f (patch)
tree8fddfeeef7ec05fbf69ca5b825da288f786ab727
parent46dfad8b36dda80982613a9d29b9a7e99db3abfb (diff)
r600g/sb: optimize some cases for CNDxx instructions
We can replace CNDxx with MOV (and possibly eliminate after propagation) in following cases: If src1 is equal to src2 in CNDxx instruction then the result doesn't depend on condition and we can replace the instruction with "MOV dst, src1". If src0 is const then we can evaluate the condition at compile time and also replace it with MOV. Signed-off-by: Vadim Girlin <[email protected]>
-rw-r--r--src/gallium/drivers/r600/sb/sb_expr.cpp84
-rw-r--r--src/gallium/drivers/r600/sb/sb_expr.h2
2 files changed, 81 insertions, 5 deletions
diff --git a/src/gallium/drivers/r600/sb/sb_expr.cpp b/src/gallium/drivers/r600/sb/sb_expr.cpp
index e3c7858c3e9..8582c8e8e0b 100644
--- a/src/gallium/drivers/r600/sb/sb_expr.cpp
+++ b/src/gallium/drivers/r600/sb/sb_expr.cpp
@@ -432,13 +432,63 @@ bool expr_handler::fold_alu_op2(alu_node& n) {
return true;
}
+bool expr_handler::evaluate_condition(unsigned alu_cnd_flags,
+ literal s1, literal s2) {
+
+ unsigned cmp_type = alu_cnd_flags & AF_CMP_TYPE_MASK;
+ unsigned cc = alu_cnd_flags & AF_CC_MASK;
+
+ switch (cmp_type) {
+ case AF_FLOAT_CMP: {
+ switch (cc) {
+ case AF_CC_E : return s1.f == s2.f;
+ case AF_CC_GT: return s1.f > s2.f;
+ case AF_CC_GE: return s1.f >= s2.f;
+ case AF_CC_NE: return s1.f != s2.f;
+ case AF_CC_LT: return s1.f < s2.f;
+ case AF_CC_LE: return s1.f <= s2.f;
+ default:
+ assert(!"invalid condition code");
+ return false;
+ }
+ }
+ case AF_INT_CMP: {
+ switch (cc) {
+ case AF_CC_E : return s1.i == s2.i;
+ case AF_CC_GT: return s1.i > s2.i;
+ case AF_CC_GE: return s1.i >= s2.i;
+ case AF_CC_NE: return s1.i != s2.i;
+ case AF_CC_LT: return s1.i < s2.i;
+ case AF_CC_LE: return s1.i <= s2.i;
+ default:
+ assert(!"invalid condition code");
+ return false;
+ }
+ }
+ case AF_UINT_CMP: {
+ switch (cc) {
+ case AF_CC_E : return s1.u == s2.u;
+ case AF_CC_GT: return s1.u > s2.u;
+ case AF_CC_GE: return s1.u >= s2.u;
+ case AF_CC_NE: return s1.u != s2.u;
+ case AF_CC_LT: return s1.u < s2.u;
+ case AF_CC_LE: return s1.u <= s2.u;
+ default:
+ assert(!"invalid condition code");
+ return false;
+ }
+ }
+ default:
+ assert(!"invalid cmp_type");
+ return false;
+ }
+}
+
bool expr_handler::fold_alu_op3(alu_node& n) {
if (n.src.size() < 3)
return false;
- // TODO handle CNDxx by some common path
-
value* v0 = n.src[0];
value* v1 = n.src[1];
value* v2 = n.src[2];
@@ -449,9 +499,6 @@ bool expr_handler::fold_alu_op3(alu_node& n) {
bool isc1 = v1->is_const();
bool isc2 = v2->is_const();
- if (!isc0 && !isc1 && !isc2)
- return false;
-
literal dv, cv0, cv1, cv2;
if (isc0) {
@@ -469,6 +516,33 @@ bool expr_handler::fold_alu_op3(alu_node& n) {
apply_alu_src_mod(n.bc, 2, cv2);
}
+ if (n.bc.op_ptr->flags & AF_CMOV) {
+ int src = 0;
+
+ if (v1->gvalue() == v2->gvalue() &&
+ n.bc.src[1].neg == n.bc.src[2].neg) {
+ // result doesn't depend on condition, convert to MOV
+ src = 1;
+ } else if (isc0) {
+ // src0 is const, condition can be evaluated, convert to MOV
+ bool cond = evaluate_condition(n.bc.op_ptr->flags & (AF_CC_MASK |
+ AF_CMP_TYPE_MASK), cv0, literal(0));
+ src = cond ? 1 : 2;
+ }
+
+ if (src) {
+ // if src is selected, convert to MOV
+ n.bc.src[0] = n.bc.src[src];
+ n.src[0] = n.src[src];
+ n.src.resize(1);
+ n.bc.set_op(ALU_OP1_MOV);
+ return fold_alu_op1(n);
+ }
+ }
+
+ if (!isc0 && !isc1 && !isc2)
+ return false;
+
if (isc0 && isc1 && isc2) {
switch (n.bc.op) {
case ALU_OP3_MULADD: dv = cv0.f * cv1.f + cv2.f; break;
diff --git a/src/gallium/drivers/r600/sb/sb_expr.h b/src/gallium/drivers/r600/sb/sb_expr.h
index 7f3bd15ba37..c7f7dbfe447 100644
--- a/src/gallium/drivers/r600/sb/sb_expr.h
+++ b/src/gallium/drivers/r600/sb/sb_expr.h
@@ -76,6 +76,8 @@ public:
void apply_alu_dst_mod(const bc_alu &bc, literal &v);
void assign_source(value *dst, value *src);
+
+ bool evaluate_condition(unsigned alu_cnd_flags, literal s1, literal s2);
};
} // namespace r600_sb