1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "instruction_simplifier_riscv64.h"
18
19 #include "instruction_simplifier.h"
20
21 namespace art HIDDEN {
22
23 namespace riscv64 {
24
25 class InstructionSimplifierRiscv64Visitor final : public HGraphVisitor {
26 public:
InstructionSimplifierRiscv64Visitor(HGraph * graph,OptimizingCompilerStats * stats)27 InstructionSimplifierRiscv64Visitor(HGraph* graph, OptimizingCompilerStats* stats)
28 : HGraphVisitor(graph), stats_(stats) {}
29
30 private:
RecordSimplification()31 void RecordSimplification() {
32 MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSimplificationsArch);
33 }
34
VisitBasicBlock(HBasicBlock * block)35 void VisitBasicBlock(HBasicBlock* block) override {
36 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
37 HInstruction* instruction = it.Current();
38 if (instruction->IsInBlock()) {
39 instruction->Accept(this);
40 }
41 }
42 }
43
44 // Replace Add which has Shl with distance of 1 or 2 or 3 with Riscv64ShiftAdd
TryReplaceAddsWithShiftAdds(HShl * shl)45 bool TryReplaceAddsWithShiftAdds(HShl* shl) {
46 // There is no reason to replace Int32 Shl+Add with ShiftAdd because of
47 // additional sign-extension required.
48 if (shl->GetType() != DataType::Type::kInt64) {
49 return false;
50 }
51
52 if (!shl->GetRight()->IsConstant()) {
53 return false;
54 }
55
56 // The bytecode does not permit the shift distance to come from a wide variable
57 DCHECK(shl->GetRight()->IsIntConstant());
58
59 const int32_t distance = shl->GetRight()->AsIntConstant()->GetValue();
60 if (distance < 1 || distance > 3) {
61 return false;
62 }
63
64 bool replaced = false;
65
66 for (const HUseListNode<HInstruction*>& use : shl->GetUses()) {
67 HInstruction* user = use.GetUser();
68
69 if (!user->IsAdd()) {
70 continue;
71 }
72 HAdd* add = user->AsAdd();
73 HInstruction* left = add->GetLeft();
74 HInstruction* right = add->GetRight();
75 DCHECK_EQ(add->GetType(), DataType::Type::kInt64)
76 << "Replaceable Add must be the same 64 bit type as the input";
77
78 // If the HAdd to replace has both inputs the same HShl<1|2|3>, then
79 // don't perform the optimization. The processor will not be able to execute
80 // these shifts parallel which is the purpose of the replace below.
81 if (left == right) {
82 continue;
83 }
84
85 HInstruction* add_other_input = left == shl ? right : left;
86 HRiscv64ShiftAdd* shift_add = new (GetGraph()->GetAllocator())
87 HRiscv64ShiftAdd(shl->GetLeft(), add_other_input, distance);
88
89 add->GetBlock()->ReplaceAndRemoveInstructionWith(add, shift_add);
90 replaced = true;
91 }
92
93 if (!shl->HasUses()) {
94 shl->GetBlock()->RemoveInstruction(shl);
95 }
96
97 return replaced;
98 }
99
VisitAnd(HAnd * inst)100 void VisitAnd(HAnd* inst) override {
101 if (TryMergeNegatedInput(inst)) {
102 RecordSimplification();
103 }
104 }
105
VisitOr(HOr * inst)106 void VisitOr(HOr* inst) override {
107 if (TryMergeNegatedInput(inst)) {
108 RecordSimplification();
109 }
110 }
111
112 // Replace code looking like
113 // SHL tmp, a, 1 or 2 or 3
114 // ADD dst, tmp, b
115 // with
116 // Riscv64ShiftAdd dst, a, b
VisitShl(HShl * inst)117 void VisitShl(HShl* inst) override {
118 if (TryReplaceAddsWithShiftAdds(inst)) {
119 RecordSimplification();
120 }
121 }
122
VisitSub(HSub * inst)123 void VisitSub(HSub* inst) override {
124 if (TryMergeWithAnd(inst)) {
125 RecordSimplification();
126 }
127 }
128
VisitXor(HXor * inst)129 void VisitXor(HXor* inst) override {
130 if (TryMergeNegatedInput(inst)) {
131 RecordSimplification();
132 }
133 }
134
135 OptimizingCompilerStats* stats_ = nullptr;
136 };
137
Run()138 bool InstructionSimplifierRiscv64::Run() {
139 auto visitor = InstructionSimplifierRiscv64Visitor(graph_, stats_);
140 visitor.VisitReversePostOrder();
141 return true;
142 }
143
144 } // namespace riscv64
145 } // namespace art
146