Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARC/ARCInstrInfo.cpp
35266 views
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(1).isFI()) && // is a stack slot
73
(MI.getOperand(2).isImm()) && // the imm is zero
74
(isZeroImm(MI.getOperand(2)))) {
75
FrameIndex = MI.getOperand(1).getIndex();
76
return MI.getOperand(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(1).isFI()) && // is a stack slot
92
(MI.getOperand(2).isImm()) && // the imm is zero
93
(isZeroImm(MI.getOperand(2)))) {
94
FrameIndex = MI.getOperand(1).getIndex();
95
return MI.getOperand(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(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(I->getOpcode())) {
199
TBB = I->getOperand(0).getMBB();
200
} else if (isCondBranchOpcode(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(0).getMBB();
208
Cond.push_back(I->getOperand(1));
209
Cond.push_back(I->getOperand(2));
210
Cond.push_back(I->getOperand(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(I->getOpcode()) ||
222
isJumpOpcode(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(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(I->getOpcode()) &&
262
!isCondBranchOpcode(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(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(I);
298
MachineFunction &MF = *MBB.getParent();
299
MachineFrameInfo &MFI = MF.getFrameInfo();
300
301
MachineMemOperand *MMO = MF.getMachineMemOperand(
302
MachinePointerInfo::getFixedStack(MF, FrameIndex),
303
MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex),
304
MFI.getObjectAlign(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(I);
327
MachineFunction &MF = *MBB.getParent();
328
MachineFrameInfo &MFI = MF.getFrameInfo();
329
MachineMemOperand *MMO = MF.getMachineMemOperand(
330
MachinePointerInfo::getFixedStack(MF, FrameIndex),
331
MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex),
332
MFI.getObjectAlign(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((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(MI);
361
if (isInt<12>(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(TBB);
388
for (unsigned i = 0; i < 3; i++) {
389
MIB.add(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(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(BasePos).isReg() || !MI.getOperand(OffsetPos).isImm())
438
return false;
439
440
return true;
441
}
442
443