summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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