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