summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/Android.bp1
-rw-r--r--compiler/optimizing/code_generator_riscv64.cc35
-rw-r--r--compiler/optimizing/graph_visualizer.cc6
-rw-r--r--compiler/optimizing/instruction_simplifier_riscv64.cc99
-rw-r--r--compiler/optimizing/instruction_simplifier_riscv64.h42
-rw-r--r--compiler/optimizing/nodes.h8
-rw-r--r--compiler/optimizing/nodes_riscv64.h65
-rw-r--r--compiler/optimizing/optimization.cc8
-rw-r--r--compiler/optimizing/optimization.h1
-rw-r--r--compiler/optimizing/optimizing_compiler.cc1
-rw-r--r--test/458-checker-riscv64-shift-add/expected-stderr.txt0
-rw-r--r--test/458-checker-riscv64-shift-add/expected-stdout.txt0
-rw-r--r--test/458-checker-riscv64-shift-add/info.txt1
-rw-r--r--test/458-checker-riscv64-shift-add/src/Main.java275
14 files changed, 542 insertions, 0 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp
index e0c1744ce3..993b8970da 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -236,6 +236,7 @@ art_cc_defaults {
"jni/quick/riscv64/calling_convention_riscv64.cc",
"optimizing/code_generator_riscv64.cc",
"optimizing/critical_native_abi_fixup_riscv64.cc",
+ "optimizing/instruction_simplifier_riscv64.cc",
"optimizing/intrinsics_riscv64.cc",
"utils/riscv64/assembler_riscv64.cc",
"utils/riscv64/jni_macro_assembler_riscv64.cc",
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc
index 22017ed0e9..4a96623cda 100644
--- a/compiler/optimizing/code_generator_riscv64.cc
+++ b/compiler/optimizing/code_generator_riscv64.cc
@@ -5348,6 +5348,41 @@ void InstructionCodeGeneratorRISCV64::VisitXor(HXor* instruction) {
HandleBinaryOp(instruction);
}
+void LocationsBuilderRISCV64::VisitRiscv64ShiftAdd(HRiscv64ShiftAdd* instruction) {
+ DCHECK(codegen_->GetInstructionSetFeatures().HasZba());
+ DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64)
+ << "Unexpected ShiftAdd type: " << instruction->GetType();
+
+ LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorRISCV64::VisitRiscv64ShiftAdd(HRiscv64ShiftAdd* instruction) {
+ DCHECK_EQ(instruction->GetType(), DataType::Type::kInt64)
+ << "Unexpected ShiftAdd type: " << instruction->GetType();
+ LocationSummary* locations = instruction->GetLocations();
+ XRegister first = locations->InAt(0).AsRegister<XRegister>();
+ XRegister second = locations->InAt(1).AsRegister<XRegister>();
+ XRegister dest = locations->Out().AsRegister<XRegister>();
+
+ switch (instruction->GetDistance()) {
+ case 1:
+ __ Sh1Add(dest, first, second);
+ break;
+ case 2:
+ __ Sh2Add(dest, first, second);
+ break;
+ case 3:
+ __ Sh3Add(dest, first, second);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected distance of ShiftAdd: " << instruction->GetDistance();
+ UNREACHABLE();
+ }
+}
+
void LocationsBuilderRISCV64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
UNUSED(instruction);
LOG(FATAL) << "Unimplemented";
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 1e4f71f9a2..5db251cbd3 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -644,6 +644,12 @@ class HGraphVisualizerPrinter final : public HGraphDelegateVisitor {
}
#endif
+#if defined(ART_ENABLE_CODEGEN_riscv64)
+ void VisitRiscv64ShiftAdd(HRiscv64ShiftAdd* instruction) override {
+ StartAttributeStream("distance") << instruction->GetDistance();
+ }
+#endif
+
bool IsPass(const char* name) {
return strcmp(pass_name_, name) == 0;
}
diff --git a/compiler/optimizing/instruction_simplifier_riscv64.cc b/compiler/optimizing/instruction_simplifier_riscv64.cc
new file mode 100644
index 0000000000..0b9f8c58b1
--- /dev/null
+++ b/compiler/optimizing/instruction_simplifier_riscv64.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_simplifier_riscv64.h"
+
+namespace art HIDDEN {
+
+namespace riscv64 {
+
+class InstructionSimplifierRiscv64Visitor final : public HGraphVisitor {
+ public:
+ InstructionSimplifierRiscv64Visitor(HGraph* graph, OptimizingCompilerStats* stats)
+ : HGraphVisitor(graph), stats_(stats) {}
+
+ private:
+ void RecordSimplification() {
+ MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch);
+ }
+
+ void VisitBasicBlock(HBasicBlock* block) override {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ if (instruction->IsInBlock()) {
+ instruction->Accept(this);
+ }
+ }
+ }
+
+ bool TryReplaceShiftAddWithOneInstruction(HShl* shl, HAdd* add) {
+ // 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()) {
+ return false;
+ }
+
+ const int32_t distance = shl->GetRight()->AsIntConstant()->GetValue();
+ if (distance != 1 && distance != 2 && distance != 3) {
+ return false;
+ }
+
+ if (!shl->HasOnlyOneNonEnvironmentUse()) {
+ return 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);
+
+ 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);
+
+ return true;
+ }
+
+ // 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;
+ }
+ }
+
+ OptimizingCompilerStats* stats_ = nullptr;
+};
+
+bool InstructionSimplifierRiscv64::Run() {
+ auto visitor = InstructionSimplifierRiscv64Visitor(graph_, stats_);
+ visitor.VisitReversePostOrder();
+ return true;
+}
+
+} // namespace riscv64
+} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_riscv64.h b/compiler/optimizing/instruction_simplifier_riscv64.h
new file mode 100644
index 0000000000..2fbfedddf4
--- /dev/null
+++ b/compiler/optimizing/instruction_simplifier_riscv64.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_RISCV64_H_
+#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_RISCV64_H_
+
+#include "base/macros.h"
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art HIDDEN {
+
+namespace riscv64 {
+
+class InstructionSimplifierRiscv64 : public HOptimization {
+ public:
+ InstructionSimplifierRiscv64(HGraph* graph, OptimizingCompilerStats* stats)
+ : HOptimization(graph, kInstructionSimplifierRiscv64PassName, stats) {}
+
+ static constexpr const char* kInstructionSimplifierRiscv64PassName =
+ "instruction_simplifier_riscv64";
+
+ bool Run() override;
+};
+
+} // namespace riscv64
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_RISCV64_H_
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 12a96acaa4..37d17478ff 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1665,7 +1665,11 @@ class HLoopInformationOutwardIterator : public ValueObject {
#define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)
+#if defined(ART_ENABLE_CODEGEN_riscv64)
+#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M) M(Riscv64ShiftAdd, Instruction)
+#else
#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M)
+#endif
#ifndef ART_ENABLE_CODEGEN_x86
#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)
@@ -1692,6 +1696,7 @@ class HLoopInformationOutwardIterator : public ValueObject {
FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \
FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) \
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \
+ FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(M)
@@ -8420,6 +8425,9 @@ class HIntermediateAddress final : public HExpression<2> {
#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
#include "nodes_x86.h"
#endif
+#if defined(ART_ENABLE_CODEGEN_riscv64)
+#include "nodes_riscv64.h"
+#endif
namespace art HIDDEN {
diff --git a/compiler/optimizing/nodes_riscv64.h b/compiler/optimizing/nodes_riscv64.h
new file mode 100644
index 0000000000..4916e57944
--- /dev/null
+++ b/compiler/optimizing/nodes_riscv64.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_NODES_RISCV64_H_
+#define ART_COMPILER_OPTIMIZING_NODES_RISCV64_H_
+
+namespace art HIDDEN {
+
+class HRiscv64ShiftAdd final : public HBinaryOperation {
+ public:
+ HRiscv64ShiftAdd(HInstruction* left,
+ HInstruction* right,
+ uint32_t distance,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(
+ kRiscv64ShiftAdd, DataType::Type::kInt64, left, right, SideEffects::None(), dex_pc) {
+ DCHECK_GE(distance, 1u);
+ DCHECK_LE(distance, 3u);
+
+ SetPackedField<DistanceField>(distance);
+ }
+
+ uint32_t GetDistance() const { return GetPackedField<DistanceField>(); }
+
+ bool IsCommutative() const override { return false; }
+ bool InstructionDataEquals(const HInstruction* other) const override {
+ return GetPackedFields() == other->AsRiscv64ShiftAdd()->GetPackedFields();
+ }
+
+ HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
+ const int64_t value = y->GetValue() + (x->GetValue() << GetDistance());
+ return GetBlock()->GetGraph()->GetLongConstant(value, GetDexPc());
+ }
+
+ DECLARE_INSTRUCTION(Riscv64ShiftAdd);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(Riscv64ShiftAdd);
+
+ private:
+ static constexpr size_t kFieldDistance = kNumberOfGenericPackedBits;
+ static constexpr size_t kFieldDistanceSize = MinimumBitsToStore(3u);
+ static constexpr size_t kNumberOfRiscv64ShiftAddPackedBits =
+ kFieldDistance + kFieldDistanceSize;
+ static_assert(kNumberOfRiscv64ShiftAddPackedBits <= kMaxNumberOfPackedBits,
+ "Too many packed fields.");
+ using DistanceField = BitField<uint32_t, kFieldDistance, kFieldDistanceSize>;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_NODES_RISCV64_H_
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index dd57100d88..ef1f36ab08 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -25,6 +25,7 @@
#endif
#ifdef ART_ENABLE_CODEGEN_riscv64
#include "critical_native_abi_fixup_riscv64.h"
+#include "instruction_simplifier_riscv64.h"
#endif
#ifdef ART_ENABLE_CODEGEN_x86
#include "pc_relative_fixups_x86.h"
@@ -114,6 +115,8 @@ const char* OptimizationPassName(OptimizationPass pass) {
#ifdef ART_ENABLE_CODEGEN_riscv64
case OptimizationPass::kCriticalNativeAbiFixupRiscv64:
return riscv64::CriticalNativeAbiFixupRiscv64::kCriticalNativeAbiFixupRiscv64PassName;
+ case OptimizationPass::kInstructionSimplifierRiscv64:
+ return riscv64::InstructionSimplifierRiscv64::kInstructionSimplifierRiscv64PassName;
#endif
#ifdef ART_ENABLE_CODEGEN_x86
case OptimizationPass::kPcRelativeFixupsX86:
@@ -163,6 +166,7 @@ OptimizationPass OptimizationPassByName(const std::string& pass_name) {
#endif
#ifdef ART_ENABLE_CODEGEN_riscv64
X(OptimizationPass::kCriticalNativeAbiFixupRiscv64);
+ X(OptimizationPass::kInstructionSimplifierRiscv64);
#endif
#ifdef ART_ENABLE_CODEGEN_x86
X(OptimizationPass::kPcRelativeFixupsX86);
@@ -314,6 +318,10 @@ ArenaVector<HOptimization*> ConstructOptimizations(
DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
opt = new (allocator) riscv64::CriticalNativeAbiFixupRiscv64(graph, stats);
break;
+ case OptimizationPass::kInstructionSimplifierRiscv64:
+ DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name";
+ opt = new (allocator) riscv64::InstructionSimplifierRiscv64(graph, stats);
+ break;
#endif
#ifdef ART_ENABLE_CODEGEN_x86
case OptimizationPass::kPcRelativeFixupsX86:
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 55aa8f914b..8bc9da49fc 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -94,6 +94,7 @@ enum class OptimizationPass {
#endif
#ifdef ART_ENABLE_CODEGEN_riscv64
kCriticalNativeAbiFixupRiscv64,
+ kInstructionSimplifierRiscv64,
#endif
#ifdef ART_ENABLE_CODEGEN_x86
kPcRelativeFixupsX86,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f532681527..763dc88e8a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -535,6 +535,7 @@ bool OptimizingCompiler::RunArchOptimizations(HGraph* graph,
#if defined(ART_ENABLE_CODEGEN_riscv64)
case InstructionSet::kRiscv64: {
OptimizationDef riscv64_optimizations[] = {
+ OptDef(OptimizationPass::kInstructionSimplifierRiscv64),
OptDef(OptimizationPass::kSideEffectsAnalysis),
OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
OptDef(OptimizationPass::kCriticalNativeAbiFixupRiscv64)
diff --git a/test/458-checker-riscv64-shift-add/expected-stderr.txt b/test/458-checker-riscv64-shift-add/expected-stderr.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/458-checker-riscv64-shift-add/expected-stderr.txt
diff --git a/test/458-checker-riscv64-shift-add/expected-stdout.txt b/test/458-checker-riscv64-shift-add/expected-stdout.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/458-checker-riscv64-shift-add/expected-stdout.txt
diff --git a/test/458-checker-riscv64-shift-add/info.txt b/test/458-checker-riscv64-shift-add/info.txt
new file mode 100644
index 0000000000..bfe80c016e
--- /dev/null
+++ b/test/458-checker-riscv64-shift-add/info.txt
@@ -0,0 +1 @@
+Tests for InstructionSimplifierRiscv64
diff --git a/test/458-checker-riscv64-shift-add/src/Main.java b/test/458-checker-riscv64-shift-add/src/Main.java
new file mode 100644
index 0000000000..b78b9551b8
--- /dev/null
+++ b/test/458-checker-riscv64-shift-add/src/Main.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void assertIntEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertLongEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ /// CHECK-START-RISCV64: int Main.$noinline$intRiscvShift1Add(int, int) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:i\d+>> ParameterValue
+ /// CHECK: <<B:i\d+>> ParameterValue
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Shift:i\d+>> Shl [<<A>>,<<One>>]
+ /// CHECK: <<Add:i\d+>> Add [<<B>>,<<Shift>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: int Main.$noinline$intRiscvShift1Add(int, int) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Riscv64ShiftAdd
+
+ public static int $noinline$intRiscvShift1Add(int a, int b) {
+ return (a << 1) + b;
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longIntRiscvShift1Add(long, int) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:i\d+>> ParameterValue
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Shift:j\d+>> Shl [<<A>>,<<One>>]
+ /// CHECK: <<Convert:j\d+>> TypeConversion [<<B>>]
+ /// CHECK: <<Add:j\d+>> Add [<<Shift>>,<<Convert>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longIntRiscvShift1Add(long, int) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:i\d+>> ParameterValue
+ /// CHECK: <<Convert:j\d+>> TypeConversion [<<B>>]
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<Convert>>] distance:1
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longIntRiscvShift1Add(long, int) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longIntRiscvShift1Add(long, int) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longIntRiscvShift1Add(long a, int b) {
+ return (a << 1) + b;
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift1Add(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Shift:j\d+>> Shl [<<A>>,<<One>>]
+ /// CHECK: <<Add:j\d+>> Add [<<B>>,<<Shift>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift1Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:1
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift1Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift1Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longRiscvShift1Add(long a, long b) {
+ return (a << 1) + b;
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift2Add(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Two:i\d+>> IntConstant 2
+ /// CHECK: <<Shift:j\d+>> Shl [<<A>>,<<Two>>]
+ /// CHECK: <<Add:j\d+>> Add [<<B>>,<<Shift>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift2Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:2
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift2Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift2Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longRiscvShift2Add(long a, long b) {
+ return (a << 2) + b;
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift3Add(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Three:i\d+>> IntConstant 3
+ /// CHECK: <<Shift:j\d+>> Shl [<<A>>,<<Three>>]
+ /// CHECK: <<Add:j\d+>> Add [<<B>>,<<Shift>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:3
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longRiscvShift3Add(long a, long b) {
+ return (a << 3) + b;
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longReverseRiscvShift3Add(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Three:i\d+>> IntConstant 3
+ /// CHECK: <<Shift:j\d+>> Shl [<<A>>,<<Three>>]
+ /// CHECK: <<Add:j\d+>> Add [<<B>>,<<Shift>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longReverseRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<B>>] distance:3
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longReverseRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longReverseRiscvShift3Add(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longReverseRiscvShift3Add(long a, long b) {
+ return b + (a << 3);
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRightShift(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Four:i\d+>> IntConstant 4
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Shift1:j\d+>> Shl [<<A>>,<<Four>>]
+ /// CHECK: <<Shift2:j\d+>> Shl [<<B>>,<<One>>]
+ /// CHECK: <<Add:j\d+>> Add [<<Shift1>>,<<Shift2>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRightShift(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Four:i\d+>> IntConstant 4
+ /// CHECK: <<Shift1:j\d+>> Shl [<<A>>,<<Four>>]
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<B>>,<<Shift1>>] distance:1
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longRightShift(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longRightShift(long a, long b) {
+ return (a << 4) + (b << 1);
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longLeftShift(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Four:i\d+>> IntConstant 4
+ /// CHECK: <<Shift1:j\d+>> Shl [<<A>>,<<One>>]
+ /// CHECK: <<Shift2:j\d+>> Shl [<<B>>,<<Four>>]
+ /// CHECK: <<Add:j\d+>> Add [<<Shift1>>,<<Shift2>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longLeftShift(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<Four:i\d+>> IntConstant 4
+ /// CHECK: <<Shift2:j\d+>> Shl [<<B>>,<<Four>>]
+ /// CHECK-DAG: <<ShiftAdd:j\d+>> Riscv64ShiftAdd [<<A>>,<<Shift2>>] distance:1
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longLeftShift(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longLeftShift(long a, long b) {
+ return (a << 1) + (b << 4);
+ }
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longTwoSimplifications(long, long) instruction_simplifier_riscv64 (before)
+ /// CHECK: <<A:j\d+>> ParameterValue
+ /// CHECK: <<B:j\d+>> ParameterValue
+ /// CHECK: <<One:i\d+>> IntConstant 1
+ /// CHECK: <<Two:i\d+>> IntConstant 2
+ /// CHECK: <<Shift1:j\d+>> Shl [<<A>>,<<One>>]
+ /// CHECK: <<Add1:j\d+>> Add [<<B>>,<<Shift1>>]
+ /// CHECK: <<Shift2:j\d+>> Shl [<<B>>,<<Two>>]
+ /// CHECK: <<Add2:j\d+>> Add [<<A>>,<<Shift2>>]
+ /// CHECK: <<Xor:j\d+>> Xor [<<Add1>>,<<Add2>>]
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longTwoSimplifications(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-DAG: <<ShiftAdd1:j\d+>> Riscv64ShiftAdd distance:1
+ /// CHECK-DAG: <<ShiftAdd2:j\d+>> Riscv64ShiftAdd distance:2
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longTwoSimplifications(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START-RISCV64: long Main.$noinline$longTwoSimplifications(long, long) instruction_simplifier_riscv64 (after)
+ /// CHECK-NOT: Add
+
+ public static long $noinline$longTwoSimplifications(long a, long b) {
+ long x = b + (a << 1);
+ long y = a + (b << 2);
+ return x ^ y;
+ }
+
+ public static void main(String[] args) {
+ assertIntEquals(0, $noinline$intRiscvShift1Add(0, 0));
+
+ assertLongEquals(-3L, $noinline$longIntRiscvShift1Add(-1L, -1));
+ assertLongEquals(3L, $noinline$longIntRiscvShift1Add(1L, 1));
+
+ assertLongEquals(-3L, $noinline$longRiscvShift1Add(-1L, -1L));
+ assertLongEquals(-1L, $noinline$longRiscvShift1Add(0L, -1L));
+ assertLongEquals(-2L, $noinline$longRiscvShift1Add(-1L, 0L));
+ assertLongEquals(0L, $noinline$longRiscvShift1Add(0L, 0L));
+ assertLongEquals(1L, $noinline$longRiscvShift1Add(0L, 1L));
+ assertLongEquals(2L, $noinline$longRiscvShift1Add(1L, 0L));
+ assertLongEquals(3L, $noinline$longRiscvShift1Add(1L, 1L));
+
+ assertLongEquals(-1L, $noinline$longRiscvShift1Add(Long.MAX_VALUE, 1L));
+
+ assertLongEquals(0L, $noinline$longRiscvShift2Add(0L, 0L));
+ assertLongEquals(1L, $noinline$longRiscvShift2Add(0L, 1L));
+ assertLongEquals(4L, $noinline$longRiscvShift2Add(1L, 0L));
+ assertLongEquals(5L, $noinline$longRiscvShift2Add(1L, 1L));
+
+ assertLongEquals(0L, $noinline$longRiscvShift3Add(0L, 0L));
+ assertLongEquals(0L, $noinline$longReverseRiscvShift3Add(0L, 0L));
+ assertLongEquals(1L, $noinline$longRiscvShift3Add(0L, 1L));
+ assertLongEquals(1L, $noinline$longReverseRiscvShift3Add(0L, 1L));
+ assertLongEquals(8L, $noinline$longRiscvShift3Add(1L, 0L));
+ assertLongEquals(8L, $noinline$longReverseRiscvShift3Add(1L, 0L));
+ assertLongEquals(9L, $noinline$longRiscvShift3Add(1L, 1L));
+ assertLongEquals(9L, $noinline$longReverseRiscvShift3Add(1L, 1L));
+
+ assertLongEquals(2L, $noinline$longRightShift(0L, 1L));
+ assertLongEquals(4L, $noinline$longRightShift(0L, 2L));
+
+ assertLongEquals(2L, $noinline$longLeftShift(1L, 0L));
+ assertLongEquals(4L, $noinline$longLeftShift(2L, 0L));
+
+ assertLongEquals(6L, $noinline$longTwoSimplifications(1L, 1L));
+ }
+}