LLVM 24.0.0git
NVPTXInstrInfo.cpp
Go to the documentation of this file.
1//===- NVPTXInstrInfo.cpp - NVPTX Instruction Information -----------------===//
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 NVPTX implementation of the TargetInstrInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "NVPTXInstrInfo.h"
14#include "NVPTX.h"
15#include "NVPTXSubtarget.h"
20
21using namespace llvm;
22
23#define GET_INSTRINFO_CTOR_DTOR
24#include "NVPTXGenInstrInfo.inc"
25
26// Pin the vtable to this file.
27void NVPTXInstrInfo::anchor() {}
28
30 : NVPTXGenInstrInfo(STI, RegInfo), RegInfo() {}
31
34 const DebugLoc &DL, Register DestReg,
35 Register SrcReg, bool KillSrc,
36 bool RenamableDest, bool RenamableSrc) const {
37 const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
38 const TargetRegisterClass *DestRC = MRI.getRegClass(DestReg);
39 const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
40
41 if (DestRC != SrcRC)
42 report_fatal_error("Copy one register into another with a different width");
43
44 unsigned Op;
45 if (DestRC == &NVPTX::B1RegClass)
46 Op = NVPTX::MOV_B1_r;
47 else if (DestRC == &NVPTX::B16RegClass)
48 Op = NVPTX::MOV_B16_r;
49 else if (DestRC == &NVPTX::B32RegClass)
50 Op = NVPTX::MOV_B32_r;
51 else if (DestRC == &NVPTX::B64RegClass)
52 Op = NVPTX::MOV_B64_r;
53 else if (DestRC == &NVPTX::B128RegClass)
54 Op = NVPTX::MOV_B128_r;
55 else
56 llvm_unreachable("Bad register copy");
57
58 BuildMI(MBB, I, DL, get(Op), DestReg)
59 .addReg(SrcReg, getKillRegState(KillSrc));
60}
61
62/// analyzeBranch - Analyze the branching code at the end of MBB, returning
63/// true if it cannot be understood (e.g. it's a switch dispatch or isn't
64/// implemented for a target). Upon success, this returns false and returns
65/// with the following information in various cases:
66///
67/// 1. If this block ends with no branches (it just falls through to its succ)
68/// just return false, leaving TBB/FBB null.
69/// 2. If this block ends with only an unconditional branch, it sets TBB to be
70/// the destination block.
71/// 3. If this block ends with an conditional branch and it falls through to
72/// an successor block, it sets TBB to be the branch destination block and a
73/// list of operands that evaluate the condition. These
74/// operands can be passed to other TargetInstrInfo methods to create new
75/// branches.
76/// 4. If this block ends with an conditional branch and an unconditional
77/// block, it returns the 'true' destination in TBB, the 'false' destination
78/// in FBB, and a list of operands that evaluate the condition. These
79/// operands can be passed to other TargetInstrInfo methods to create new
80/// branches.
81///
82/// Note that removeBranch and insertBranch must be implemented to support
83/// cases where this method returns success.
84///
89 bool AllowModify) const {
90 // If the block has no terminators, it just falls into the block after it.
92 if (I == MBB.begin() || !isUnpredicatedTerminator(*--I))
93 return false;
94
95 // Get the last instruction in the block.
96 MachineInstr &LastInst = *I;
97
98 // If there is only one terminator instruction, process it.
99 if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
100 if (LastInst.getOpcode() == NVPTX::GOTO) {
101 TBB = LastInst.getOperand(0).getMBB();
102 return false;
103 } else if (LastInst.getOpcode() == NVPTX::CBranch) {
104 // Block ends with fall-through condbranch.
105 TBB = LastInst.getOperand(1).getMBB();
106 Cond.push_back(LastInst.getOperand(0));
107 Cond.push_back(LastInst.getOperand(2));
108 return false;
109 }
110 // Otherwise, don't know what this is.
111 return true;
112 }
113
114 // Get the instruction before it if it's a terminator.
115 MachineInstr &SecondLastInst = *I;
116
117 // If there are three terminators, we don't know what sort of block this is.
118 if (I != MBB.begin() && isUnpredicatedTerminator(*--I))
119 return true;
120
121 // If the block ends with NVPTX::GOTO and NVPTX:CBranch, handle it.
122 if (SecondLastInst.getOpcode() == NVPTX::CBranch &&
123 LastInst.getOpcode() == NVPTX::GOTO) {
124 TBB = SecondLastInst.getOperand(1).getMBB();
125 Cond.push_back(SecondLastInst.getOperand(0));
126 Cond.push_back(SecondLastInst.getOperand(2));
127 FBB = LastInst.getOperand(0).getMBB();
128 return false;
129 }
130
131 // If the block ends with two NVPTX:GOTOs, handle it. The second one is not
132 // executed, so remove it.
133 if (SecondLastInst.getOpcode() == NVPTX::GOTO &&
134 LastInst.getOpcode() == NVPTX::GOTO) {
135 TBB = SecondLastInst.getOperand(0).getMBB();
136 I = LastInst;
137 if (AllowModify)
138 I->eraseFromParent();
139 return false;
140 }
141
142 // Otherwise, can't handle this.
143 return true;
144}
145
147 int *BytesRemoved) const {
148 assert(!BytesRemoved && "code size not handled");
150 if (I == MBB.begin())
151 return 0;
152 --I;
153 if (I->getOpcode() != NVPTX::GOTO && I->getOpcode() != NVPTX::CBranch)
154 return 0;
155
156 // Remove the branch.
157 I->eraseFromParent();
158
159 I = MBB.end();
160
161 if (I == MBB.begin())
162 return 1;
163 --I;
164 if (I->getOpcode() != NVPTX::CBranch)
165 return 1;
166
167 // Remove the branch.
168 I->eraseFromParent();
169 return 2;
170}
171
176 const DebugLoc &DL,
177 int *BytesAdded) const {
178 assert(!BytesAdded && "code size not handled");
179
180 // Shouldn't be a fall through.
181 assert(TBB && "insertBranch must not be told to insert a fallthrough");
182 assert((Cond.size() == 2 || Cond.size() == 0) &&
183 "NVPTX branch conditions have two components!");
184
185 // One-way branch.
186 if (!FBB) {
187 if (Cond.empty()) // Unconditional branch
188 BuildMI(&MBB, DL, get(NVPTX::GOTO)).addMBB(TBB);
189 else // Conditional branch
190 BuildMI(&MBB, DL, get(NVPTX::CBranch))
191 .add(Cond[0])
192 .addMBB(TBB)
193 .add(Cond[1]);
194 return 1;
195 }
196
197 // Two-way Conditional Branch.
198 BuildMI(&MBB, DL, get(NVPTX::CBranch)).add(Cond[0]).addMBB(TBB).add(Cond[1]);
199 BuildMI(&MBB, DL, get(NVPTX::GOTO)).addMBB(FBB);
200 return 2;
201}
202
205 assert(Cond.size() == 2 && "Invalid NVPTX branch condition!");
206 Cond[1].setImm(!Cond[1].getImm());
207 return false;
208}
209
210bool NVPTXInstrInfo::invertPredicateBranchInstr(MachineBasicBlock &MBB) const {
211 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
213 if (analyzeBranch(MBB, TBB, FBB, Cond, /*AllowModify=*/false))
214 return false;
215 if (Cond.empty())
216 return false;
218 return false;
219 DebugLoc DL = MBB.findBranchDebugLoc();
221 insertBranch(MBB, TBB, FBB, Cond, DL);
222 return true;
223}
224
225static bool isIntegerSetp(const MachineInstr &MI) {
226 switch (MI.getOpcode()) {
227 case NVPTX::SETP_i16rr:
228 case NVPTX::SETP_i16ri:
229 case NVPTX::SETP_i16ir:
230 case NVPTX::SETP_i32rr:
231 case NVPTX::SETP_i32ri:
232 case NVPTX::SETP_i32ir:
233 case NVPTX::SETP_i64rr:
234 case NVPTX::SETP_i64ri:
235 case NVPTX::SETP_i64ir:
236 return true;
237 default:
238 return false;
239 }
240}
241
242static bool isScalarFloatSetp(const MachineInstr &MI) {
243 switch (MI.getOpcode()) {
244 case NVPTX::SETP_bf16rr:
245 case NVPTX::SETP_f16rr:
246 case NVPTX::SETP_f32rr:
247 case NVPTX::SETP_f32ri:
248 case NVPTX::SETP_f32ir:
249 case NVPTX::SETP_f64rr:
250 case NVPTX::SETP_f64ri:
251 case NVPTX::SETP_f64ir:
252 return true;
253 default:
254 return false;
255 }
256}
257
258static int64_t invertIntegerCmpMode(int64_t Mode) {
259 switch (Mode) {
280 default:
281 llvm_unreachable("Invalid integer comparison mode");
282 }
283}
284
285static int64_t invertScalarFloatCmpMode(int64_t Mode) {
286 switch (Mode) {
315 default:
316 llvm_unreachable("Invalid scalar float comparison mode");
317 }
318}
319
321 MachineOperand &ModeOp = MI.getOperand(3);
322
323 if (isIntegerSetp(MI))
324 ModeOp.setImm(invertIntegerCmpMode(ModeOp.getImm()));
325 else if (isScalarFloatSetp(MI))
326 ModeOp.setImm(invertScalarFloatCmpMode(ModeOp.getImm()));
327 else
328 llvm_unreachable("Invalid SETP instruction");
329}
330
331static unsigned getInvertedSelpOpcode(unsigned Opcode) {
332 switch (Opcode) {
333 case NVPTX::SELP_b16ri:
334 return NVPTX::SELP_b16ir;
335 case NVPTX::SELP_b16ir:
336 return NVPTX::SELP_b16ri;
337 case NVPTX::SELP_b32ri:
338 return NVPTX::SELP_b32ir;
339 case NVPTX::SELP_b32ir:
340 return NVPTX::SELP_b32ri;
341 case NVPTX::SELP_b64ri:
342 return NVPTX::SELP_b64ir;
343 case NVPTX::SELP_b64ir:
344 return NVPTX::SELP_b64ri;
345 case NVPTX::SELP_f16ri:
346 return NVPTX::SELP_f16ir;
347 case NVPTX::SELP_f16ir:
348 return NVPTX::SELP_f16ri;
349 case NVPTX::SELP_f32ri:
350 return NVPTX::SELP_f32ir;
351 case NVPTX::SELP_f32ir:
352 return NVPTX::SELP_f32ri;
353 case NVPTX::SELP_f64ri:
354 return NVPTX::SELP_f64ir;
355 case NVPTX::SELP_f64ir:
356 return NVPTX::SELP_f64ri;
357 case NVPTX::SELP_bf16ri:
358 return NVPTX::SELP_bf16ir;
359 case NVPTX::SELP_bf16ir:
360 return NVPTX::SELP_bf16ri;
361 case NVPTX::SELP_b16rr:
362 case NVPTX::SELP_b16ii:
363 case NVPTX::SELP_b32rr:
364 case NVPTX::SELP_b32ii:
365 case NVPTX::SELP_b64rr:
366 case NVPTX::SELP_b64ii:
367 case NVPTX::SELP_f16rr:
368 case NVPTX::SELP_f16ii:
369 case NVPTX::SELP_f32rr:
370 case NVPTX::SELP_f32ii:
371 case NVPTX::SELP_f64rr:
372 case NVPTX::SELP_f64ii:
373 case NVPTX::SELP_bf16rr:
374 case NVPTX::SELP_bf16ii:
375 return Opcode;
376 default:
377 llvm_unreachable("Unexpected select instruction");
378 }
379}
380
382 MI.setDesc(TII.get(getInvertedSelpOpcode(MI.getOpcode())));
383 MachineOperand Src0 = MI.getOperand(1);
384 MI.removeOperand(1);
385 MI.insert(MI.operands_begin() + 2, {Src0});
386}
387
389 unsigned &SrcOpIdx1,
390 unsigned &SrcOpIdx2) const {
392 return fixCommutedOpIndices(SrcOpIdx1, SrcOpIdx2, 1, 2);
393 return TargetInstrInfo::findCommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2);
394}
395
397 bool NewMI,
398 unsigned OpIdx1,
399 unsigned OpIdx2) const {
400 assert(!NewMI && "this should never be used");
401
403 return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
404
405 // For now all users must be invertible conditional branches or selects.
406 // TODO: Support other invertible predicate users.
407 MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
410 for (MachineInstr &UseMI :
411 MRI.use_nodbg_instructions(MI.getOperand(0).getReg())) {
412 if (UseMI.isConditionalBranch())
413 BranchMBBs.push_back(UseMI.getParent());
414 else if (UseMI.isSelect())
415 SelectInstrs.push_back(&UseMI);
416 else
417 return nullptr;
418 }
419
421
422 auto *Failed = llvm::find_if(BranchMBBs, [this](MachineBasicBlock *MBB) {
423 return !invertPredicateBranchInstr(*MBB);
424 });
425
426 if (Failed != BranchMBBs.end()) {
427 // Couldn't invert one of the branches. Roll back the prefix we
428 // already inverted and the compare-mode flip.
429 for (MachineBasicBlock *MBB : llvm::make_range(BranchMBBs.begin(), Failed))
430 invertPredicateBranchInstr(*MBB);
432 return nullptr;
433 }
434
435 for (MachineInstr *SelectMI : SelectInstrs)
436 invertSelpInstr(*SelectMI, *this);
437
438 return &MI;
439}
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
static bool isIntegerSetp(const MachineInstr &MI)
static int64_t invertScalarFloatCmpMode(int64_t Mode)
static void invertSelpInstr(MachineInstr &MI, const NVPTXInstrInfo &TII)
static void invertScalarCompareInstr(MachineInstr &MI)
static bool isScalarFloatSetp(const MachineInstr &MI)
static unsigned getInvertedSelpOpcode(unsigned Opcode)
static int64_t invertIntegerCmpMode(int64_t Mode)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
A debug info location.
Definition DebugLoc.h:126
MachineInstrBundleIterator< MachineInstr > iterator
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
int64_t getImm() const
MachineBasicBlock * getMBB() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const override
NVPTXInstrInfo(const NVPTXSubtarget &STI)
bool reverseBranchCondition(SmallVectorImpl< MachineOperand > &Cond) const override
bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const override
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
analyzeBranch - Analyze the branching code at the end of MBB, returning true if it cannot be understo...
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, Register DestReg, Register SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const override
MachineInstr * commuteInstructionImpl(MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const override
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const
Returns true iff the routine could find two commutable operands in the given machine instruction.
virtual MachineInstr * commuteInstructionImpl(MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const
This method commutes the operands of the given machine instruction MI.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
testing::Matcher< const detail::ErrorHolder & > Failed()
Definition Error.h:198
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
DWARFExpression::Operation Op
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58