• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "aarch64_optimize_common.h"
17 #include "aarch64_cg.h"
18 #include "aarch64_cgfunc.h"
19 #include "cgbb.h"
20 
21 namespace maplebe {
ModifyJumpTarget(Operand & targetOperand,BB & bb)22 void AArch64InsnVisitor::ModifyJumpTarget(Operand &targetOperand, BB &bb)
23 {
24     if (bb.GetKind() == BB::kBBIgoto) {
25         bool modified = false;
26         for (Insn *insn = bb.GetLastInsn(); insn != nullptr; insn = insn->GetPrev()) {
27             if (insn->GetMachineOpcode() == MOP_adrp_label) {
28                 LabelIdx labIdx = static_cast<LabelOperand &>(targetOperand).GetLabelIndex();
29                 ImmOperand &immOpnd =
30                     static_cast<AArch64CGFunc *>(GetCGFunc())->CreateImmOperand(labIdx, k8BitSize, false);
31                 insn->SetOperand(1, immOpnd);
32                 modified = true;
33             }
34         }
35         CHECK_FATAL(modified, "ModifyJumpTarget: Could not change jump target");
36         return;
37     } else if (bb.GetKind() == BB::kBBGoto) {
38         for (Insn *insn = bb.GetLastInsn(); insn != nullptr; insn = insn->GetPrev()) {
39             if (insn->GetMachineOpcode() == MOP_adrp_label) {
40                 maple::LabelIdx labidx = static_cast<LabelOperand &>(targetOperand).GetLabelIndex();
41                 LabelOperand &label = static_cast<AArch64CGFunc *>(GetCGFunc())->GetOrCreateLabelOperand(labidx);
42                 insn->SetOperand(1, label);
43                 break;
44             }
45         }
46         // fallthru below to patch the branch insn
47     }
48     CHECK_NULL_FATAL(bb.GetLastMachineInsn());
49     bb.GetLastMachineInsn()->SetOperand(AArch64isa::GetJumpTargetIdx(*bb.GetLastMachineInsn()), targetOperand);
50 }
51 
ModifyJumpTarget(maple::LabelIdx targetLabel,BB & bb)52 void AArch64InsnVisitor::ModifyJumpTarget(maple::LabelIdx targetLabel, BB &bb)
53 {
54     ModifyJumpTarget(static_cast<AArch64CGFunc *>(GetCGFunc())->GetOrCreateLabelOperand(targetLabel), bb);
55 }
56 
ModifyJumpTarget(BB & newTarget,BB & bb)57 void AArch64InsnVisitor::ModifyJumpTarget(BB &newTarget, BB &bb)
58 {
59     if (newTarget.GetLastMachineInsn() != nullptr) {
60         ModifyJumpTarget(newTarget.GetLastInsn()->GetOperand(AArch64isa::GetJumpTargetIdx(*newTarget.GetLastInsn())),
61                          bb);
62     }
63 }
64 
CloneInsn(Insn & originalInsn)65 Insn *AArch64InsnVisitor::CloneInsn(Insn &originalInsn)
66 {
67     // Use custom deep copy
68     MapleAllocator *allocator = GetCGFunc()->GetFuncScopeAllocator();
69     MemPool *memPool = const_cast<MemPool *>(CG::GetCurCGFunc()->GetMemoryPool());
70     if (originalInsn.IsTargetInsn() || originalInsn.IsComment()) {
71         if (originalInsn.IsVectorOp()) {
72             auto *insn = memPool->Clone<VectorInsn>(*static_cast<VectorInsn *>(&originalInsn));
73             insn->SetRegSpecList(static_cast<VectorInsn &>(originalInsn).GetRegSpecList());
74             return insn;
75         }
76         return originalInsn.CloneTree(*allocator);
77     } else if (originalInsn.IsCfiInsn()) {
78         return static_cast<cfi::CfiInsn &>(originalInsn).CloneTree(*allocator);
79     } else if (originalInsn.IsDbgInsn()) {
80         return static_cast<mpldbg::DbgInsn &>(originalInsn).CloneTree(*allocator);
81     }
82     CHECK_FATAL(false, "Cannot clone");
83     return nullptr;
84 }
85 
86 /*
87  * Precondition: The given insn is a jump instruction.
88  * Get the jump target label from the given instruction.
89  * Note: MOP_xbr is a branching instruction, but the target is unknown at compile time,
90  * because a register instead of label. So we don't take it as a branching instruction.
91  */
GetJumpLabel(const Insn & insn) const92 LabelIdx AArch64InsnVisitor::GetJumpLabel(const Insn &insn) const
93 {
94     uint32 operandIdx = AArch64isa::GetJumpTargetIdx(insn);
95     if (insn.GetOperand(operandIdx).IsLabelOpnd()) {
96         return static_cast<LabelOperand &>(insn.GetOperand(operandIdx)).GetLabelIndex();
97     }
98     DEBUG_ASSERT(false, "Operand is not label");
99     return 0;
100 }
101 
IsCompareInsn(const Insn & insn) const102 bool AArch64InsnVisitor::IsCompareInsn(const Insn &insn) const
103 {
104     switch (insn.GetMachineOpcode()) {
105         case MOP_wcmpri:
106         case MOP_wcmprr:
107         case MOP_wcmprrs:
108         case MOP_xcmpri:
109         case MOP_xcmprr:
110         case MOP_xcmprrs:
111         case MOP_hcmperi:
112         case MOP_hcmperr:
113         case MOP_scmperi:
114         case MOP_scmperr:
115         case MOP_dcmperi:
116         case MOP_dcmperr:
117         case MOP_hcmpqri:
118         case MOP_hcmpqrr:
119         case MOP_scmpqri:
120         case MOP_scmpqrr:
121         case MOP_dcmpqri:
122         case MOP_dcmpqrr:
123         case MOP_wcmnri:
124         case MOP_wcmnrr:
125         case MOP_xcmnri:
126         case MOP_xcmnrr:
127         case MOP_wwcmprre:
128         case MOP_xwcmprre:
129         case MOP_wccmpriic:
130         case MOP_wccmprric:
131         case MOP_xccmpriic:
132         case MOP_xccmprric:
133             return true;
134         default:
135             return false;
136     }
137 }
138 
IsCompareAndBranchInsn(const Insn & insn) const139 bool AArch64InsnVisitor::IsCompareAndBranchInsn(const Insn &insn) const
140 {
141     switch (insn.GetMachineOpcode()) {
142         case MOP_wcbnz:
143         case MOP_xcbnz:
144         case MOP_wcbz:
145         case MOP_xcbz:
146             return true;
147         default:
148             return false;
149     }
150 }
151 
IsTestAndSetCCInsn(const Insn & insn) const152 bool AArch64InsnVisitor::IsTestAndSetCCInsn(const Insn &insn) const
153 {
154     switch (insn.GetMachineOpcode()) {
155         case MOP_wtstri32:
156         case MOP_xtstri64:
157         case MOP_wtstrr:
158         case MOP_xtstrr:
159             return true;
160         default:
161             return false;
162     }
163 }
164 
IsTestAndBranchInsn(const Insn & insn) const165 bool AArch64InsnVisitor::IsTestAndBranchInsn(const Insn &insn) const
166 {
167     switch (insn.GetMachineOpcode()) {
168         case MOP_xtbz:
169         case MOP_wtbz:
170         case MOP_xtbnz:
171         case MOP_wtbnz:
172             return true;
173         default:
174             return false;
175     }
176 }
177 
IsAddOrSubInsn(const Insn & insn) const178 bool AArch64InsnVisitor::IsAddOrSubInsn(const Insn &insn) const
179 {
180     switch (insn.GetMachineOpcode()) {
181         case MOP_xaddrrr:
182         case MOP_xaddrri12:
183         case MOP_waddrrr:
184         case MOP_waddrri12:
185         case MOP_xsubrrr:
186         case MOP_xsubrri12:
187         case MOP_wsubrrr:
188         case MOP_wsubrri12:
189             return true;
190         default:
191             return false;
192     }
193 }
194 
IsSimpleJumpInsn(const Insn & insn) const195 bool AArch64InsnVisitor::IsSimpleJumpInsn(const Insn &insn) const
196 {
197     return (insn.GetMachineOpcode() == MOP_xuncond);
198 }
199 
CreateVregFromReg(const RegOperand & pReg)200 RegOperand *AArch64InsnVisitor::CreateVregFromReg(const RegOperand &pReg)
201 {
202     return &static_cast<AArch64CGFunc *>(GetCGFunc())
203                 ->CreateRegisterOperandOfType(pReg.GetRegisterType(), pReg.GetSize() / k8BitSize);
204 }
205 
ReTargetSuccBB(BB & bb,LabelIdx newTarget) const206 void AArch64InsnVisitor::ReTargetSuccBB(BB &bb, LabelIdx newTarget) const
207 {
208     Insn *lastInsn = bb.GetLastMachineInsn();
209     if (lastInsn && (lastInsn->IsBranch() || lastInsn->IsCondBranch() || lastInsn->IsUnCondBranch())) {
210         CHECK_FATAL(false, "check last insn of a ft BB");
211     }
212     LabelOperand &targetOpnd = GetCGFunc()->GetOrCreateLabelOperand(newTarget);
213     Insn &newInsn = GetCGFunc()->GetInsnBuilder()->BuildInsn(MOP_xuncond, targetOpnd);
214     bb.AppendInsn(newInsn);
215 }
216 
FlipIfBB(BB & bb,LabelIdx ftLabel) const217 void AArch64InsnVisitor::FlipIfBB(BB &bb, LabelIdx ftLabel) const
218 {
219     Insn *lastInsn = bb.GetLastMachineInsn();
220     CHECK_FATAL(lastInsn && lastInsn->IsCondBranch(), "must be ? of a if BB");
221     uint32 targetIdx = AArch64isa::GetJumpTargetIdx(*lastInsn);
222     MOperator mOp = AArch64isa::FlipConditionOp(lastInsn->GetMachineOpcode());
223     if (mOp == 0 || mOp > MOP_nop) {
224         CHECK_FATAL(false, "get flip op failed");
225     }
226     lastInsn->SetMOP(AArch64CG::kMd[mOp]);
227     LabelOperand &targetOpnd = GetCGFunc()->GetOrCreateLabelOperand(ftLabel);
228     lastInsn->SetOperand(targetIdx, targetOpnd);
229 }
230 
CreateGotoBBAfterCondBB(BB & bb,BB & fallthru,bool isTargetFallthru) const231 BB *AArch64InsnVisitor::CreateGotoBBAfterCondBB(BB &bb, BB &fallthru, bool isTargetFallthru) const
232 {
233     BB *newBB = GetCGFunc()->CreateNewBB();
234     newBB->SetKind(BB::kBBGoto);
235     LabelIdx fallthruLabel = fallthru.GetLabIdx();
236     if (fallthruLabel == MIRLabelTable::GetDummyLabel()) {
237         fallthruLabel = GetCGFunc()->CreateLabel();
238         fallthru.SetLabIdx(fallthruLabel);
239     }
240     LabelOperand &targetOpnd = GetCGFunc()->GetOrCreateLabelOperand(fallthruLabel);
241     Insn &gotoInsn = GetCGFunc()->GetInsnBuilder()->BuildInsn(MOP_xuncond, targetOpnd);
242     newBB->AppendInsn(gotoInsn);
243 
244     // maintain pred and succ
245     if (!isTargetFallthru) {
246         fallthru.RemovePreds(bb);
247     }
248     fallthru.PushBackPreds(*newBB);
249     if (!isTargetFallthru) {
250         bb.RemoveSuccs(fallthru);
251     }
252     bb.PushBackSuccs(*newBB);
253     newBB->PushBackSuccs(fallthru);
254     newBB->PushBackPreds(bb);
255     return newBB;
256 }
257 
ModifyFathruBBToGotoBB(BB & bb,LabelIdx labelIdx) const258 void AArch64InsnVisitor::ModifyFathruBBToGotoBB(BB &bb, LabelIdx labelIdx) const
259 {
260     CHECK_FATAL(bb.GetKind() == BB::kBBFallthru, "invalid kind of bb");
261     CGFunc *cgFunc = GetCGFunc();
262     LabelOperand &labelOpnd = cgFunc->GetOrCreateLabelOperand(labelIdx);
263     Insn &jumpInsn = cgFunc->GetInsnBuilder()->BuildInsn(MOP_xuncond, labelOpnd);
264     bb.AppendInsn(jumpInsn);
265     bb.SetKind(BB::kBBGoto);
266 }
267 } /* namespace maplebe */
268