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 
TryReplaceShiftAddWithOneInstruction(HShl * shl,HAdd * add)44   bool TryReplaceShiftAddWithOneInstruction(HShl* shl, HAdd* add) {
45     // There is no reason to replace Int32 Shl+Add with ShiftAdd because of
46     // additional sign-extension required.
47     if (shl->GetType() != DataType::Type::kInt64) {
48       return false;
49     }
50 
51     if (!shl->GetRight()->IsIntConstant()) {
52       return false;
53     }
54 
55     const int32_t distance = shl->GetRight()->AsIntConstant()->GetValue();
56     if (distance != 1 && distance != 2 && distance != 3) {
57       return false;
58     }
59 
60     if (!shl->HasOnlyOneNonEnvironmentUse()) {
61       return false;
62     }
63 
64     auto* const add_other_input = add->GetLeft() == shl ? add->GetRight() : add->GetLeft();
65     auto* const shift_add = new (GetGraph()->GetAllocator())
66         HRiscv64ShiftAdd(shl->GetLeft(), add_other_input, distance);
67 
68     DCHECK_EQ(add->GetType(), DataType::Type::kInt64)
69         << "Riscv64ShiftAdd replacement should have the same 64 bit type";
70     add->GetBlock()->ReplaceAndRemoveInstructionWith(add, shift_add);
71     shl->GetBlock()->RemoveInstruction(shl);
72 
73     return true;
74   }
75 
76   // Replace code looking like
77   //    SHL tmp, a, 1 or 2 or 3
78   //    ADD dst, tmp, b
79   // with
80   //    Riscv64ShiftAdd dst, a, b
VisitAdd(HAdd * add)81   void VisitAdd(HAdd* add) override {
82     auto* const left = add->GetLeft();
83     auto* const right = add->GetRight();
84     if (left->IsShl() && TryReplaceShiftAddWithOneInstruction(left->AsShl(), add)) {
85       return;
86     } else if (right->IsShl() && TryReplaceShiftAddWithOneInstruction(right->AsShl(), add)) {
87       return;
88     }
89   }
90 
VisitAnd(HAnd * inst)91   void VisitAnd(HAnd* inst) override {
92     if (TryMergeNegatedInput(inst)) {
93       RecordSimplification();
94     }
95   }
96 
VisitOr(HOr * inst)97   void VisitOr(HOr* inst) override {
98     if (TryMergeNegatedInput(inst)) {
99       RecordSimplification();
100     }
101   }
102 
VisitSub(HSub * inst)103   void VisitSub(HSub* inst) override {
104     if (TryMergeWithAnd(inst)) {
105       RecordSimplification();
106     }
107   }
108 
VisitXor(HXor * inst)109   void VisitXor(HXor* inst) override {
110     if (TryMergeNegatedInput(inst)) {
111       RecordSimplification();
112     }
113   }
114 
115   OptimizingCompilerStats* stats_ = nullptr;
116 };
117 
Run()118 bool InstructionSimplifierRiscv64::Run() {
119   auto visitor = InstructionSimplifierRiscv64Visitor(graph_, stats_);
120   visitor.VisitReversePostOrder();
121   return true;
122 }
123 
124 }  // namespace riscv64
125 }  // namespace art
126