1 | //===- ARCInstrInfo.cpp - ARC Instruction Information -----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains the ARC implementation of the TargetInstrInfo class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "ARCInstrInfo.h" |
14 | #include "ARC.h" |
15 | #include "ARCMachineFunctionInfo.h" |
16 | #include "ARCSubtarget.h" |
17 | #include "MCTargetDesc/ARCInfo.h" |
18 | #include "llvm/CodeGen/MachineFrameInfo.h" |
19 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
20 | #include "llvm/CodeGen/MachineMemOperand.h" |
21 | #include "llvm/MC/TargetRegistry.h" |
22 | #include "llvm/Support/Debug.h" |
23 | |
24 | using namespace llvm; |
25 | |
26 | #define GET_INSTRINFO_CTOR_DTOR |
27 | #include "ARCGenInstrInfo.inc" |
28 | |
29 | #define DEBUG_TYPE "arc-inst-info" |
30 | |
31 | enum AddrIncType { |
32 | NoAddInc = 0, |
33 | PreInc = 1, |
34 | PostInc = 2, |
35 | Scaled = 3 |
36 | }; |
37 | |
38 | enum TSFlagsConstants { |
39 | TSF_AddrModeOff = 0, |
40 | TSF_AddModeMask = 3 |
41 | }; |
42 | |
43 | // Pin the vtable to this file. |
44 | void ARCInstrInfo::anchor() {} |
45 | |
46 | ARCInstrInfo::ARCInstrInfo(const ARCSubtarget &ST) |
47 | : ARCGenInstrInfo(ARC::ADJCALLSTACKDOWN, ARC::ADJCALLSTACKUP), RI(ST) {} |
48 | |
49 | static bool isZeroImm(const MachineOperand &Op) { |
50 | return Op.isImm() && Op.getImm() == 0; |
51 | } |
52 | |
53 | static bool isLoad(int Opcode) { |
54 | return Opcode == ARC::LD_rs9 || Opcode == ARC::LDH_rs9 || |
55 | Opcode == ARC::LDB_rs9; |
56 | } |
57 | |
58 | static bool isStore(int Opcode) { |
59 | return Opcode == ARC::ST_rs9 || Opcode == ARC::STH_rs9 || |
60 | Opcode == ARC::STB_rs9; |
61 | } |
62 | |
63 | /// If the specified machine instruction is a direct |
64 | /// load from a stack slot, return the virtual or physical register number of |
65 | /// the destination along with the FrameIndex of the loaded stack slot. If |
66 | /// not, return 0. This predicate must return 0 if the instruction has |
67 | /// any side effects other than loading from the stack slot. |
68 | Register ARCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, |
69 | int &FrameIndex) const { |
70 | int Opcode = MI.getOpcode(); |
71 | if (isLoad(Opcode)) { |
72 | if ((MI.getOperand(i: 1).isFI()) && // is a stack slot |
73 | (MI.getOperand(i: 2).isImm()) && // the imm is zero |
74 | (isZeroImm(Op: MI.getOperand(i: 2)))) { |
75 | FrameIndex = MI.getOperand(i: 1).getIndex(); |
76 | return MI.getOperand(i: 0).getReg(); |
77 | } |
78 | } |
79 | return 0; |
80 | } |
81 | |
82 | /// If the specified machine instruction is a direct |
83 | /// store to a stack slot, return the virtual or physical register number of |
84 | /// the source reg along with the FrameIndex of the loaded stack slot. If |
85 | /// not, return 0. This predicate must return 0 if the instruction has |
86 | /// any side effects other than storing to the stack slot. |
87 | Register ARCInstrInfo::isStoreToStackSlot(const MachineInstr &MI, |
88 | int &FrameIndex) const { |
89 | int Opcode = MI.getOpcode(); |
90 | if (isStore(Opcode)) { |
91 | if ((MI.getOperand(i: 1).isFI()) && // is a stack slot |
92 | (MI.getOperand(i: 2).isImm()) && // the imm is zero |
93 | (isZeroImm(Op: MI.getOperand(i: 2)))) { |
94 | FrameIndex = MI.getOperand(i: 1).getIndex(); |
95 | return MI.getOperand(i: 0).getReg(); |
96 | } |
97 | } |
98 | return 0; |
99 | } |
100 | |
101 | /// Return the inverse of passed condition, i.e. turning COND_E to COND_NE. |
102 | static ARCCC::CondCode getOppositeBranchCondition(ARCCC::CondCode CC) { |
103 | switch (CC) { |
104 | default: |
105 | llvm_unreachable("Illegal condition code!" ); |
106 | case ARCCC::EQ: |
107 | return ARCCC::NE; |
108 | case ARCCC::NE: |
109 | return ARCCC::EQ; |
110 | case ARCCC::LO: |
111 | return ARCCC::HS; |
112 | case ARCCC::HS: |
113 | return ARCCC::LO; |
114 | case ARCCC::GT: |
115 | return ARCCC::LE; |
116 | case ARCCC::GE: |
117 | return ARCCC::LT; |
118 | case ARCCC::VS: |
119 | return ARCCC::VC; |
120 | case ARCCC::VC: |
121 | return ARCCC::VS; |
122 | case ARCCC::LT: |
123 | return ARCCC::GE; |
124 | case ARCCC::LE: |
125 | return ARCCC::GT; |
126 | case ARCCC::HI: |
127 | return ARCCC::LS; |
128 | case ARCCC::LS: |
129 | return ARCCC::HI; |
130 | case ARCCC::NZ: |
131 | return ARCCC::Z; |
132 | case ARCCC::Z: |
133 | return ARCCC::NZ; |
134 | } |
135 | } |
136 | |
137 | static bool isUncondBranchOpcode(int Opc) { return Opc == ARC::BR; } |
138 | |
139 | static bool isCondBranchOpcode(int Opc) { |
140 | return Opc == ARC::BRcc_rr_p || Opc == ARC::BRcc_ru6_p; |
141 | } |
142 | |
143 | static bool isJumpOpcode(int Opc) { return Opc == ARC::J; } |
144 | |
145 | /// Analyze the branching code at the end of MBB, returning |
146 | /// true if it cannot be understood (e.g. it's a switch dispatch or isn't |
147 | /// implemented for a target). Upon success, this returns false and returns |
148 | /// with the following information in various cases: |
149 | /// |
150 | /// 1. If this block ends with no branches (it just falls through to its succ) |
151 | /// just return false, leaving TBB/FBB null. |
152 | /// 2. If this block ends with only an unconditional branch, it sets TBB to be |
153 | /// the destination block. |
154 | /// 3. If this block ends with a conditional branch and it falls through to a |
155 | /// successor block, it sets TBB to be the branch destination block and a |
156 | /// list of operands that evaluate the condition. These operands can be |
157 | /// passed to other TargetInstrInfo methods to create new branches. |
158 | /// 4. If this block ends with a conditional branch followed by an |
159 | /// unconditional branch, it returns the 'true' destination in TBB, the |
160 | /// 'false' destination in FBB, and a list of operands that evaluate the |
161 | /// condition. These operands can be passed to other TargetInstrInfo |
162 | /// methods to create new branches. |
163 | /// |
164 | /// Note that RemoveBranch and insertBranch must be implemented to support |
165 | /// cases where this method returns success. |
166 | /// |
167 | /// If AllowModify is true, then this routine is allowed to modify the basic |
168 | /// block (e.g. delete instructions after the unconditional branch). |
169 | |
170 | bool ARCInstrInfo::analyzeBranch(MachineBasicBlock &MBB, |
171 | MachineBasicBlock *&TBB, |
172 | MachineBasicBlock *&FBB, |
173 | SmallVectorImpl<MachineOperand> &Cond, |
174 | bool AllowModify) const { |
175 | TBB = FBB = nullptr; |
176 | MachineBasicBlock::iterator I = MBB.end(); |
177 | if (I == MBB.begin()) |
178 | return false; |
179 | --I; |
180 | |
181 | while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) { |
182 | // Flag to be raised on unanalyzeable instructions. This is useful in cases |
183 | // where we want to clean up on the end of the basic block before we bail |
184 | // out. |
185 | bool CantAnalyze = false; |
186 | |
187 | // Skip over DEBUG values and predicated nonterminators. |
188 | while (I->isDebugInstr() || !I->isTerminator()) { |
189 | if (I == MBB.begin()) |
190 | return false; |
191 | --I; |
192 | } |
193 | |
194 | if (isJumpOpcode(Opc: I->getOpcode())) { |
195 | // Indirect branches and jump tables can't be analyzed, but we still want |
196 | // to clean up any instructions at the tail of the basic block. |
197 | CantAnalyze = true; |
198 | } else if (isUncondBranchOpcode(Opc: I->getOpcode())) { |
199 | TBB = I->getOperand(i: 0).getMBB(); |
200 | } else if (isCondBranchOpcode(Opc: I->getOpcode())) { |
201 | // Bail out if we encounter multiple conditional branches. |
202 | if (!Cond.empty()) |
203 | return true; |
204 | |
205 | assert(!FBB && "FBB should have been null." ); |
206 | FBB = TBB; |
207 | TBB = I->getOperand(i: 0).getMBB(); |
208 | Cond.push_back(Elt: I->getOperand(i: 1)); |
209 | Cond.push_back(Elt: I->getOperand(i: 2)); |
210 | Cond.push_back(Elt: I->getOperand(i: 3)); |
211 | } else if (I->isReturn()) { |
212 | // Returns can't be analyzed, but we should run cleanup. |
213 | CantAnalyze = !isPredicated(*I); |
214 | } else { |
215 | // We encountered other unrecognized terminator. Bail out immediately. |
216 | return true; |
217 | } |
218 | |
219 | // Cleanup code - to be run for unpredicated unconditional branches and |
220 | // returns. |
221 | if (!isPredicated(*I) && (isUncondBranchOpcode(Opc: I->getOpcode()) || |
222 | isJumpOpcode(Opc: I->getOpcode()) || I->isReturn())) { |
223 | // Forget any previous condition branch information - it no longer |
224 | // applies. |
225 | Cond.clear(); |
226 | FBB = nullptr; |
227 | |
228 | // If we can modify the function, delete everything below this |
229 | // unconditional branch. |
230 | if (AllowModify) { |
231 | MachineBasicBlock::iterator DI = std::next(x: I); |
232 | while (DI != MBB.end()) { |
233 | MachineInstr &InstToDelete = *DI; |
234 | ++DI; |
235 | InstToDelete.eraseFromParent(); |
236 | } |
237 | } |
238 | } |
239 | |
240 | if (CantAnalyze) |
241 | return true; |
242 | |
243 | if (I == MBB.begin()) |
244 | return false; |
245 | |
246 | --I; |
247 | } |
248 | |
249 | // We made it past the terminators without bailing out - we must have |
250 | // analyzed this branch successfully. |
251 | return false; |
252 | } |
253 | |
254 | unsigned ARCInstrInfo::removeBranch(MachineBasicBlock &MBB, |
255 | int *BytesRemoved) const { |
256 | assert(!BytesRemoved && "Code size not handled" ); |
257 | MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); |
258 | if (I == MBB.end()) |
259 | return 0; |
260 | |
261 | if (!isUncondBranchOpcode(Opc: I->getOpcode()) && |
262 | !isCondBranchOpcode(Opc: I->getOpcode())) |
263 | return 0; |
264 | |
265 | // Remove the branch. |
266 | I->eraseFromParent(); |
267 | |
268 | I = MBB.end(); |
269 | |
270 | if (I == MBB.begin()) |
271 | return 1; |
272 | --I; |
273 | if (!isCondBranchOpcode(Opc: I->getOpcode())) |
274 | return 1; |
275 | |
276 | // Remove the branch. |
277 | I->eraseFromParent(); |
278 | return 2; |
279 | } |
280 | |
281 | void ARCInstrInfo::copyPhysReg(MachineBasicBlock &MBB, |
282 | MachineBasicBlock::iterator I, |
283 | const DebugLoc &DL, MCRegister DestReg, |
284 | MCRegister SrcReg, bool KillSrc) const { |
285 | assert(ARC::GPR32RegClass.contains(SrcReg) && |
286 | "Only GPR32 src copy supported." ); |
287 | assert(ARC::GPR32RegClass.contains(DestReg) && |
288 | "Only GPR32 dest copy supported." ); |
289 | BuildMI(MBB, I, DL, get(ARC::MOV_rr), DestReg) |
290 | .addReg(SrcReg, getKillRegState(KillSrc)); |
291 | } |
292 | |
293 | void ARCInstrInfo::storeRegToStackSlot( |
294 | MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg, |
295 | bool IsKill, int FrameIndex, const TargetRegisterClass *RC, |
296 | const TargetRegisterInfo *TRI, Register VReg) const { |
297 | DebugLoc DL = MBB.findDebugLoc(MBBI: I); |
298 | MachineFunction &MF = *MBB.getParent(); |
299 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
300 | |
301 | MachineMemOperand *MMO = MF.getMachineMemOperand( |
302 | PtrInfo: MachinePointerInfo::getFixedStack(MF, FI: FrameIndex), |
303 | F: MachineMemOperand::MOStore, Size: MFI.getObjectSize(ObjectIdx: FrameIndex), |
304 | BaseAlignment: MFI.getObjectAlign(ObjectIdx: FrameIndex)); |
305 | |
306 | assert(MMO && "Couldn't get MachineMemOperand for store to stack." ); |
307 | assert(TRI->getSpillSize(*RC) == 4 && |
308 | "Only support 4-byte stores to stack now." ); |
309 | assert(ARC::GPR32RegClass.hasSubClassEq(RC) && |
310 | "Only support GPR32 stores to stack now." ); |
311 | LLVM_DEBUG(dbgs() << "Created store reg=" << printReg(SrcReg, TRI) |
312 | << " to FrameIndex=" << FrameIndex << "\n" ); |
313 | BuildMI(MBB, I, DL, get(ARC::ST_rs9)) |
314 | .addReg(SrcReg, getKillRegState(IsKill)) |
315 | .addFrameIndex(FrameIndex) |
316 | .addImm(0) |
317 | .addMemOperand(MMO); |
318 | } |
319 | |
320 | void ARCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, |
321 | MachineBasicBlock::iterator I, |
322 | Register DestReg, int FrameIndex, |
323 | const TargetRegisterClass *RC, |
324 | const TargetRegisterInfo *TRI, |
325 | Register VReg) const { |
326 | DebugLoc DL = MBB.findDebugLoc(MBBI: I); |
327 | MachineFunction &MF = *MBB.getParent(); |
328 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
329 | MachineMemOperand *MMO = MF.getMachineMemOperand( |
330 | PtrInfo: MachinePointerInfo::getFixedStack(MF, FI: FrameIndex), |
331 | F: MachineMemOperand::MOLoad, Size: MFI.getObjectSize(ObjectIdx: FrameIndex), |
332 | BaseAlignment: MFI.getObjectAlign(ObjectIdx: FrameIndex)); |
333 | |
334 | assert(MMO && "Couldn't get MachineMemOperand for store to stack." ); |
335 | assert(TRI->getSpillSize(*RC) == 4 && |
336 | "Only support 4-byte loads from stack now." ); |
337 | assert(ARC::GPR32RegClass.hasSubClassEq(RC) && |
338 | "Only support GPR32 stores to stack now." ); |
339 | LLVM_DEBUG(dbgs() << "Created load reg=" << printReg(DestReg, TRI) |
340 | << " from FrameIndex=" << FrameIndex << "\n" ); |
341 | BuildMI(MBB, I, DL, get(ARC::LD_rs9)) |
342 | .addReg(DestReg, RegState::Define) |
343 | .addFrameIndex(FrameIndex) |
344 | .addImm(0) |
345 | .addMemOperand(MMO); |
346 | } |
347 | |
348 | /// Return the inverse opcode of the specified Branch instruction. |
349 | bool ARCInstrInfo::reverseBranchCondition( |
350 | SmallVectorImpl<MachineOperand> &Cond) const { |
351 | assert((Cond.size() == 3) && "Invalid ARC branch condition!" ); |
352 | Cond[2].setImm(getOppositeBranchCondition(CC: (ARCCC::CondCode)Cond[2].getImm())); |
353 | return false; |
354 | } |
355 | |
356 | MachineBasicBlock::iterator |
357 | ARCInstrInfo::loadImmediate(MachineBasicBlock &MBB, |
358 | MachineBasicBlock::iterator MI, unsigned Reg, |
359 | uint64_t Value) const { |
360 | DebugLoc DL = MBB.findDebugLoc(MBBI: MI); |
361 | if (isInt<12>(x: Value)) { |
362 | return BuildMI(MBB, MI, DL, get(ARC::MOV_rs12), Reg) |
363 | .addImm(Value) |
364 | .getInstr(); |
365 | } |
366 | llvm_unreachable("Need Arc long immediate instructions." ); |
367 | } |
368 | |
369 | unsigned ARCInstrInfo::insertBranch(MachineBasicBlock &MBB, |
370 | MachineBasicBlock *TBB, |
371 | MachineBasicBlock *FBB, |
372 | ArrayRef<MachineOperand> Cond, |
373 | const DebugLoc &DL, int *BytesAdded) const { |
374 | assert(!BytesAdded && "Code size not handled." ); |
375 | |
376 | // Shouldn't be a fall through. |
377 | assert(TBB && "insertBranch must not be told to insert a fallthrough" ); |
378 | assert((Cond.size() == 3 || Cond.size() == 0) && |
379 | "ARC branch conditions have two components!" ); |
380 | |
381 | if (Cond.empty()) { |
382 | BuildMI(&MBB, DL, get(ARC::BR)).addMBB(TBB); |
383 | return 1; |
384 | } |
385 | int BccOpc = Cond[1].isImm() ? ARC::BRcc_ru6_p : ARC::BRcc_rr_p; |
386 | MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(BccOpc)); |
387 | MIB.addMBB(MBB: TBB); |
388 | for (unsigned i = 0; i < 3; i++) { |
389 | MIB.add(MO: Cond[i]); |
390 | } |
391 | |
392 | // One-way conditional branch. |
393 | if (!FBB) { |
394 | return 1; |
395 | } |
396 | |
397 | // Two-way conditional branch. |
398 | BuildMI(&MBB, DL, get(ARC::BR)).addMBB(FBB); |
399 | return 2; |
400 | } |
401 | |
402 | unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { |
403 | if (MI.isInlineAsm()) { |
404 | const MachineFunction *MF = MI.getParent()->getParent(); |
405 | const char *AsmStr = MI.getOperand(i: 0).getSymbolName(); |
406 | return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); |
407 | } |
408 | return MI.getDesc().getSize(); |
409 | } |
410 | |
411 | bool ARCInstrInfo::isPostIncrement(const MachineInstr &MI) const { |
412 | const MCInstrDesc &MID = MI.getDesc(); |
413 | const uint64_t F = MID.TSFlags; |
414 | return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PostInc; |
415 | } |
416 | |
417 | bool ARCInstrInfo::isPreIncrement(const MachineInstr &MI) const { |
418 | const MCInstrDesc &MID = MI.getDesc(); |
419 | const uint64_t F = MID.TSFlags; |
420 | return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PreInc; |
421 | } |
422 | |
423 | bool ARCInstrInfo::getBaseAndOffsetPosition(const MachineInstr &MI, |
424 | unsigned &BasePos, |
425 | unsigned &OffsetPos) const { |
426 | if (!MI.mayLoad() && !MI.mayStore()) |
427 | return false; |
428 | |
429 | BasePos = 1; |
430 | OffsetPos = 2; |
431 | |
432 | if (isPostIncrement(MI) || isPreIncrement(MI)) { |
433 | BasePos++; |
434 | OffsetPos++; |
435 | } |
436 | |
437 | if (!MI.getOperand(i: BasePos).isReg() || !MI.getOperand(i: OffsetPos).isImm()) |
438 | return false; |
439 | |
440 | return true; |
441 | } |
442 | |