diff options
-rw-r--r-- | compiler/optimizing/instruction_simplifier_riscv64.cc | 74 | ||||
-rw-r--r-- | test/458-checker-riscv64-shift-add/src/Main.java | 131 |
2 files changed, 178 insertions, 27 deletions
diff --git a/compiler/optimizing/instruction_simplifier_riscv64.cc b/compiler/optimizing/instruction_simplifier_riscv64.cc index 8f47f66d8b..b12941b37d 100644 --- a/compiler/optimizing/instruction_simplifier_riscv64.cc +++ b/compiler/optimizing/instruction_simplifier_riscv64.cc @@ -41,51 +41,60 @@ class InstructionSimplifierRiscv64Visitor final : public HGraphVisitor { } } - bool TryReplaceShiftAddWithOneInstruction(HShl* shl, HAdd* add) { + // Replace Add which has Shl with distance of 1 or 2 or 3 with Riscv64ShiftAdd + bool TryReplaceAddsWithShiftAdds(HShl* shl) { // There is no reason to replace Int32 Shl+Add with ShiftAdd because of // additional sign-extension required. if (shl->GetType() != DataType::Type::kInt64) { return false; } - if (!shl->GetRight()->IsIntConstant()) { + if (!shl->GetRight()->IsConstant()) { return false; } + // The bytecode does not permit the shift distance to come from a wide variable + DCHECK(shl->GetRight()->IsIntConstant()); + const int32_t distance = shl->GetRight()->AsIntConstant()->GetValue(); - if (distance != 1 && distance != 2 && distance != 3) { + if ((distance & ~0x3) != 0) { return false; } - if (!shl->HasOnlyOneNonEnvironmentUse()) { - return false; - } + bool replaced = false; - auto* const add_other_input = add->GetLeft() == shl ? add->GetRight() : add->GetLeft(); - auto* const shift_add = new (GetGraph()->GetAllocator()) - HRiscv64ShiftAdd(shl->GetLeft(), add_other_input, distance); + for (const HUseListNode<HInstruction*>& use : shl->GetUses()) { + HInstruction* user = use.GetUser(); - DCHECK_EQ(add->GetType(), DataType::Type::kInt64) - << "Riscv64ShiftAdd replacement should have the same 64 bit type"; - add->GetBlock()->ReplaceAndRemoveInstructionWith(add, shift_add); - shl->GetBlock()->RemoveInstruction(shl); + if (!user->IsAdd()) { + continue; + } + HAdd* add = user->AsAdd(); + HInstruction* left = add->GetLeft(); + HInstruction* right = add->GetRight(); + DCHECK_EQ(add->GetType(), DataType::Type::kInt64) + << "Replaceable Add must be the same 64 bit type as the input"; + + // If the HAdd to replace has both inputs the same HShl<1|2|3>, then + // don't perform the optimization. The processor will not be able to execute + // these shifts parallel which is the purpose of the replace below. + if (left == right) { + continue; + } - return true; - } + HInstruction* add_other_input = left == shl ? right : left; + HRiscv64ShiftAdd* shift_add = new (GetGraph()->GetAllocator()) + HRiscv64ShiftAdd(shl->GetLeft(), add_other_input, distance); - // Replace code looking like - // SHL tmp, a, 1 or 2 or 3 - // ADD dst, tmp, b - // with - // Riscv64ShiftAdd dst, a, b - void VisitAdd(HAdd* add) override { - auto* const left = add->GetLeft(); - auto* const right = add->GetRight(); - if (left->IsShl() && TryReplaceShiftAddWithOneInstruction(left->AsShl(), add)) { - return; - } else if (right->IsShl() && TryReplaceShiftAddWithOneInstruction(right->AsShl(), add)) { - return; + add->GetBlock()->ReplaceAndRemoveInstructionWith(add, shift_add); + replaced = true; } + + if (!shl->HasUses()) { + shl->GetBlock()->RemoveInstruction(shl); + } + + return replaced; } void VisitAnd(HAnd* inst) override { @@ -100,6 +109,17 @@ class InstructionSimplifierRiscv64Visitor final : public HGraphVisitor { } } + // Replace code looking like + // SHL tmp, a, 1 or 2 or 3 + // ADD dst, tmp, b + // with + // Riscv64ShiftAdd dst, a, b + void VisitShl(HShl* inst) override { + if (TryReplaceAddsWithShiftAdds(inst)) { + RecordSimplification(); + } + } + void VisitSub(HSub* inst) override { if (TryMergeWithAnd(inst)) { RecordSimplification(); diff --git a/test/458-checker-riscv64-shift-add/src/Main.java b/test/458-checker-riscv64-shift-add/src/Main.java index b78b9551b8..f000c0ce4e 100644 --- a/test/458-checker-riscv64-shift-add/src/Main.java +++ b/test/458-checker-riscv64-shift-add/src/Main.java @@ -207,6 +207,20 @@ public class Main { return (a << 1) + (b << 4); } + /// CHECK-START-RISCV64: long Main.$noinline$longShiftTooLittleDistance(long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Riscv64ShiftAdd + + public static long $noinline$longShiftTooLittleDistance(long a, long b) { + return (a << 0) + b; + } + + /// CHECK-START-RISCV64: long Main.$noinline$longShiftTooGreatDistance(long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Riscv64ShiftAdd + + public static long $noinline$longShiftTooGreatDistance(long a, long b) { + return (a << 4) + b; + } + /// CHECK-START-RISCV64: long Main.$noinline$longTwoSimplifications(long, long) instruction_simplifier_riscv64 (before) /// CHECK: <<A:j\d+>> ParameterValue /// CHECK: <<B:j\d+>> ParameterValue @@ -234,6 +248,99 @@ public class Main { return x ^ y; } + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsUseShl(long, long, long) instruction_simplifier_riscv64 (before) + /// CHECK: <<A:j\d+>> ParameterValue + /// CHECK: <<B:j\d+>> ParameterValue + /// CHECK: <<C:j\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant 1 + /// CHECK: <<Shl:j\d+>> Shl [<<A>>,<<One>>] + /// CHECK: <<X:j\d+>> Add [<<B>>,<<Shl>>] + /// CHECK: <<Y:j\d+>> Add [<<C>>,<<Shl>>] + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK: <<A:j\d+>> ParameterValue + /// CHECK: <<B:j\d+>> ParameterValue + /// CHECK: <<C:j\d+>> ParameterValue + /// CHECK-DAG: <<ShAdd1:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:1 + /// CHECK-DAG: <<ShAdd2:j\d+>> Riscv64ShiftAdd [<<A>>,<<C>>] distance:1 + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Shl + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Add + + public static long $noinline$longTwoAddsUseShl(long a, long b, long c) { + long shl = a << 1; + long x = shl + b; + long y = shl + c; + return x ^ y; + } + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsMixedOrderUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-DAG: Riscv64ShiftAdd + /// CHECK-DAG: Riscv64ShiftAdd + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsMixedOrderUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Shl + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoAddsMixedOrderUseShl(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Add + + public static long $noinline$longTwoAddsMixedOrderUseShl(long a, long b, long c) { + long x = (a << 1) + b; + long y = c + (a << 1); + return x ^ y; + } + + /// CHECK-START-RISCV64: long Main.$noinline$longOneAddSharesShlUse(long, long, long) instruction_simplifier_riscv64 (before) + /// CHECK: <<A:j\d+>> ParameterValue + /// CHECK: <<B:j\d+>> ParameterValue + /// CHECK: <<C:j\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant 1 + /// CHECK: <<Shl:j\d+>> Shl [<<A>>,<<One>>] + /// CHECK: <<X:j\d+>> Add [<<B>>,<<Shl>>] + /// CHECK: <<Y:j\d+>> Sub [<<Shl>>,<<C>>] + + /// CHECK-START-RISCV64: long Main.$noinline$longOneAddSharesShlUse(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK: <<A:j\d+>> ParameterValue + /// CHECK: <<B:j\d+>> ParameterValue + /// CHECK: <<C:j\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant 1 + /// CHECK: <<Shl:j\d+>> Shl [<<A>>,<<One>>] + /// CHECK-DAG: <<ShAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:1 + /// CHECK: <<Y:j\d+>> Sub [<<Shl>>,<<C>>] + + /// CHECK-START-RISCV64: long Main.$noinline$longOneAddSharesShlUse(long, long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Add + + public static long $noinline$longOneAddSharesShlUse(long a, long b, long c) { + long shl = a << 1; + long x = shl + b; + long y = shl - c; + return x ^ y; + } + + public static void $noinline$returnVoid(long a) {} + + /// CHECK-START-RISCV64: long Main.$noinline$longOneAddSharesShlEnvironmentUse(long, long) instruction_simplifier_riscv64 (after) + /// CHECK: Shl + /// CHECK-DAG: Riscv64ShiftAdd + + public static long $noinline$longOneAddSharesShlEnvironmentUse(long a, long b) { + long shl = a << 1; + long x = shl + b; + $noinline$returnVoid(shl); + return x; + } + + /// CHECK-START-RISCV64: long Main.$noinline$longTwoTheSameShl(long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Riscv64ShiftAdd + + public static long $noinline$longTwoTheSameShl(long a) { + return (a << 1) + (a << 1); + } + public static void main(String[] args) { assertIntEquals(0, $noinline$intRiscvShift1Add(0, 0)); @@ -270,6 +377,30 @@ public class Main { assertLongEquals(2L, $noinline$longLeftShift(1L, 0L)); assertLongEquals(4L, $noinline$longLeftShift(2L, 0L)); + assertLongEquals(1L, $noinline$longShiftTooLittleDistance(1L, 0L)); + assertLongEquals(2L, $noinline$longShiftTooLittleDistance(2L, 0L)); + + assertLongEquals(17L, $noinline$longShiftTooGreatDistance(1L, 1L)); + assertLongEquals(32L, $noinline$longShiftTooGreatDistance(2L, 0L)); + assertLongEquals(6L, $noinline$longTwoSimplifications(1L, 1L)); + + assertLongEquals(0L, $noinline$longTwoAddsUseShl(1L, 1L, 1L)); + assertLongEquals(1L, $noinline$longTwoAddsUseShl(1L, 0L, 1L)); + assertLongEquals(3L, $noinline$longTwoAddsUseShl(0L, 1L, 2L)); + assertLongEquals(7L, $noinline$longTwoAddsUseShl(1L, 2L, 1L)); + + assertLongEquals(0L, $noinline$longTwoAddsMixedOrderUseShl(1L, 1L, 1L)); + assertLongEquals(1L, $noinline$longTwoAddsMixedOrderUseShl(1L, 0L, 1L)); + assertLongEquals(3L, $noinline$longTwoAddsMixedOrderUseShl(0L, 1L, 2L)); + + assertLongEquals(2L, $noinline$longOneAddSharesShlUse(1L, 1L, 1L)); + assertLongEquals(3L, $noinline$longOneAddSharesShlUse(1L, 0L, 1L)); + assertLongEquals(-1L, $noinline$longOneAddSharesShlUse(0L, 1L, 2L)); + assertLongEquals(5L, $noinline$longOneAddSharesShlUse(1L, 2L, 1L)); + + assertLongEquals(3L, $noinline$longOneAddSharesShlEnvironmentUse(1L, 1L)); + + assertLongEquals(4L, $noinline$longTwoTheSameShl(1L)); } } |