diff --git a/src/mir/Lowering.cpp b/src/mir/Lowering.cpp index b2dc8772..b47e11ec 100644 --- a/src/mir/Lowering.cpp +++ b/src/mir/Lowering.cpp @@ -546,56 +546,54 @@ namespace mir int val = rhs_const->GetValue(); if (val > 0 && (val & (val - 1)) == 0) { - int bias = val - 1; - int biased = function.CreateVReg(VRegClass::Int); - if (bias <= 4095) + // x % 2^n → and + sign fixup: (x & mask) then if x<0 subtract 2^n + int mask = val - 1; + int masked = function.CreateVReg(VRegClass::Int); + if (mask <= 4095) { - block.Append(Opcode::AddRR, - {Operand::VReg(biased, VRegClass::Int), + block.Append(Opcode::AndRR, + {Operand::VReg(masked, VRegClass::Int), Operand::VReg(lhs, VRegClass::Int), - Operand::Imm(bias)}); + Operand::Imm(mask)}); } else { - int bias_reg = function.CreateVReg(VRegClass::Int); + int mask_reg = function.CreateVReg(VRegClass::Int); block.Append(Opcode::MovImm, - {Operand::VReg(bias_reg, VRegClass::Int), - Operand::Imm(bias)}).SetRematerializable(true).SetRematImm(bias); - block.Append(Opcode::AddRR, - {Operand::VReg(biased, VRegClass::Int), + {Operand::VReg(mask_reg, VRegClass::Int), + Operand::Imm(mask)}).SetRematerializable(true).SetRematImm(mask); + block.Append(Opcode::AndRR, + {Operand::VReg(masked, VRegClass::Int), Operand::VReg(lhs, VRegClass::Int), - Operand::VReg(bias_reg, VRegClass::Int)}); - } - int shift = 0; - int tmp = val; - while (tmp > 1) - { - tmp >>= 1; - ++shift; + Operand::VReg(mask_reg, VRegClass::Int)}); } block.Append(Opcode::CmpImm, {Operand::VReg(lhs, VRegClass::Int), Operand::Imm(0)}); - int selected = function.CreateVReg(VRegClass::Int); + int neg_fixup = function.CreateVReg(VRegClass::Int); + if (static_cast(val) <= 4095) + { + block.Append(Opcode::SubRR, + {Operand::VReg(neg_fixup, VRegClass::Int), + Operand::VReg(masked, VRegClass::Int), + Operand::Imm(val)}); + } + else + { + int val_reg = function.CreateVReg(VRegClass::Int); + block.Append(Opcode::MovImm, + {Operand::VReg(val_reg, VRegClass::Int), + Operand::Imm(val)}).SetRematerializable(true).SetRematImm(val); + block.Append(Opcode::SubRR, + {Operand::VReg(neg_fixup, VRegClass::Int), + Operand::VReg(masked, VRegClass::Int), + Operand::VReg(val_reg, VRegClass::Int)}); + } block.Append(Opcode::Csel, - {Operand::VReg(selected, VRegClass::Int), - Operand::VReg(biased, VRegClass::Int), - Operand::VReg(lhs, VRegClass::Int), - Operand::Imm(static_cast(CondCode::LT))}); - int q_dst = function.CreateVReg(VRegClass::Int); - block.Append(Opcode::AsrRR, - {Operand::VReg(q_dst, VRegClass::Int), - Operand::VReg(selected, VRegClass::Int), - Operand::Imm(shift)}); - int d_reg = function.CreateVReg(VRegClass::Int); - block.Append(Opcode::MovImm, - {Operand::VReg(d_reg, VRegClass::Int), - Operand::Imm(val)}).SetRematerializable(true).SetRematImm(val); - block.Append(Opcode::Msub, {Operand::VReg(dst, VRegClass::Int), - Operand::VReg(q_dst, VRegClass::Int), - Operand::VReg(d_reg, VRegClass::Int), - Operand::VReg(lhs, VRegClass::Int)}); + Operand::VReg(neg_fixup, VRegClass::Int), + Operand::VReg(masked, VRegClass::Int), + Operand::Imm(static_cast(CondCode::LT))}); value_vregs[value] = dst; return dst; }