constant_propagation_pass: Fold division operations where applicable

We can fold division operations if:

1. The divisor is zero, then we can replace the result with zero (as this is how
ARM platforms expect it).
2. Both values are known, in which case we can just do the operation and
store the result
3. The divisor is 1, in which case just return the other operand.
This commit is contained in:
Lioncash 2018-10-09 15:18:09 -04:00
parent c3a1558dfc
commit b55b7a5c7f
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -50,6 +50,34 @@ void FoldAND(IR::Inst& inst, bool is_32_bit) {
}
}
// Folds division operations based on the following:
//
// 1. x / 0 -> 0 (NOTE: This is an ARM-specific behavior defined in the architecture reference manual)
// 2. imm_x / imm_y -> result
// 3. x / 1 -> x
//
void FoldDivide(IR::Inst& inst, bool is_32_bit, bool is_signed) {
const auto rhs = inst.GetArg(1);
if (rhs.IsZero()) {
ReplaceUsesWith(inst, is_32_bit, 0);
return;
}
const auto lhs = inst.GetArg(0);
if (lhs.IsImmediate() && rhs.IsImmediate()) {
if (is_signed) {
const s64 result = lhs.GetImmediateAsS64() / rhs.GetImmediateAsS64();
ReplaceUsesWith(inst, is_32_bit, static_cast<u64>(result));
} else {
const u64 result = lhs.GetImmediateAsU64() / rhs.GetImmediateAsU64();
ReplaceUsesWith(inst, is_32_bit, result);
}
} else if (rhs.IsUnsignedImmediate(1)) {
inst.ReplaceUsesWith(IR::Value{lhs});
}
}
// Folds EOR operations based on the following:
//
// 1. imm_x ^ imm_y -> result
@ -190,6 +218,14 @@ void ConstantPropagation(IR::Block& block) {
case IR::Opcode::Mul64:
FoldMultiply(inst, opcode == IR::Opcode::Mul32);
break;
case IR::Opcode::SignedDiv32:
case IR::Opcode::SignedDiv64:
FoldDivide(inst, opcode == IR::Opcode::SignedDiv32, true);
break;
case IR::Opcode::UnsignedDiv32:
case IR::Opcode::UnsignedDiv64:
FoldDivide(inst, opcode == IR::Opcode::UnsignedDiv32, false);
break;
case IR::Opcode::And32:
case IR::Opcode::And64:
FoldAND(inst, opcode == IR::Opcode::And32);