diff options
-rw-r--r-- | compiler/Android.bp | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 35 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_riscv64.cc | 99 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_riscv64.h | 42 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 8 | ||||
-rw-r--r-- | compiler/optimizing/nodes_riscv64.h | 65 | ||||
-rw-r--r-- | compiler/optimizing/optimization.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/optimization.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 1 | ||||
-rw-r--r-- | test/458-checker-riscv64-shift-add/expected-stderr.txt | 0 | ||||
-rw-r--r-- | test/458-checker-riscv64-shift-add/expected-stdout.txt | 0 | ||||
-rw-r--r-- | test/458-checker-riscv64-shift-add/info.txt | 1 | ||||
-rw-r--r-- | test/458-checker-riscv64-shift-add/src/Main.java | 275 |
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)); + } +} |