From 8248999c5d3254c20333ff7a69cb3bc754944626 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Oct 2018 15:18:09 -0400 Subject: [PATCH] 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. --- src/ir_opt/constant_propagation_pass.cpp | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index 40d2b90a..f02ba264 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -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(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);