LLVM 24.0.0git
NVPTXAsmPrinter.cpp
Go to the documentation of this file.
1//===-- NVPTXAsmPrinter.cpp - NVPTX LLVM assembly writer ------------------===//
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 a printer that converts from our internal representation
10// of machine-dependent LLVM code to NVPTX assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "NVPTXAsmPrinter.h"
18#include "NVPTX.h"
19#include "NVPTXDwarfDebug.h"
20#include "NVPTXMCExpr.h"
22#include "NVPTXRegisterInfo.h"
23#include "NVPTXSubtarget.h"
24#include "NVPTXTargetMachine.h"
25#include "NVPTXUtilities.h"
26#include "NVVMProperties.h"
28#include "cl_common_defines.h"
29#include "llvm/ADT/APFloat.h"
30#include "llvm/ADT/APInt.h"
31#include "llvm/ADT/ArrayRef.h"
32#include "llvm/ADT/DenseMap.h"
33#include "llvm/ADT/DenseSet.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/Sequence.h"
41#include "llvm/ADT/StringRef.h"
42#include "llvm/ADT/Twine.h"
60#include "llvm/IR/Argument.h"
61#include "llvm/IR/Attributes.h"
62#include "llvm/IR/BasicBlock.h"
63#include "llvm/IR/Constant.h"
64#include "llvm/IR/Constants.h"
65#include "llvm/IR/DataLayout.h"
66#include "llvm/IR/DebugInfo.h"
68#include "llvm/IR/DebugLoc.h"
70#include "llvm/IR/Function.h"
71#include "llvm/IR/GlobalAlias.h"
72#include "llvm/IR/GlobalValue.h"
74#include "llvm/IR/InstrTypes.h"
75#include "llvm/IR/Instruction.h"
76#include "llvm/IR/LLVMContext.h"
77#include "llvm/IR/Module.h"
78#include "llvm/IR/Operator.h"
79#include "llvm/IR/Type.h"
80#include "llvm/IR/User.h"
81#include "llvm/IR/Value.h"
82#include "llvm/MC/MCExpr.h"
83#include "llvm/MC/MCInst.h"
84#include "llvm/MC/MCInstrDesc.h"
85#include "llvm/MC/MCStreamer.h"
86#include "llvm/MC/MCSymbol.h"
88#include "llvm/Pass.h"
92#include "llvm/Support/Endian.h"
99#include <algorithm>
100#include <cassert>
101#include <cstdint>
102#include <cstring>
103#include <map>
104#include <memory>
105#include <set>
106#include <string>
107#include <vector>
108
109using namespace llvm;
110
111#define DEPOTNAME "__local_depot"
112
113// The ptx syntax and format is very different from that usually seem in a .s
114// file,
115// therefore we are not able to use the MCAsmStreamer interface here.
116//
117// We are handcrafting the output method here.
118//
119// A better approach is to clone the MCAsmStreamer to a MCPTXAsmStreamer
120// (subclass of MCStreamer).
121
122namespace {
123
124class NVPTXAsmPrinter : public AsmPrinter {
125
126 class AggBuffer {
127 // Used to buffer the emitted string for initializing global aggregates.
128 //
129 // Normally an aggregate (array, vector, or structure) is emitted as a u8[].
130 // However, if either element/field of the aggregate is a non-NULL address,
131 // and all such addresses are properly aligned, then the aggregate is
132 // emitted as u32[] or u64[]. In the case of unaligned addresses, the
133 // aggregate is emitted as u8[], and the mask() operator is used for all
134 // pointers.
135 //
136 // We first layout the aggregate in 'buffer' in bytes, except for those
137 // symbol addresses. For the i-th symbol address in the aggregate, its
138 // corresponding 4-byte or 8-byte elements in 'buffer' are filled with 0s.
139 // symbolPosInBuffer[i-1] records its position in 'buffer', and Symbols[i-1]
140 // records the Value*.
141 //
142 // Once we have this AggBuffer setup, we can choose how to print it out.
143 public:
144 // number of symbol addresses
145 unsigned numSymbols() const { return Symbols.size(); }
146
147 bool allSymbolsAligned(unsigned ptrSize) const {
148 return llvm::all_of(symbolPosInBuffer,
149 [=](unsigned pos) { return pos % ptrSize == 0; });
150 }
151
152 private:
153 const unsigned Size; // size of the buffer in bytes
154 std::vector<unsigned char> buffer; // the buffer
155 SmallVector<unsigned, 4> symbolPosInBuffer;
157 // SymbolsBeforeStripping[i] is the original form of Symbols[i] before
158 // stripping pointer casts, i.e.,
159 // Symbols[i] == SymbolsBeforeStripping[i]->stripPointerCasts().
160 //
161 // We need to keep these values because AggBuffer::print decides whether to
162 // emit a "generic()" cast for Symbols[i] depending on the address space of
163 // SymbolsBeforeStripping[i].
164 SmallVector<const Value *, 4> SymbolsBeforeStripping;
165 unsigned curpos;
166 const NVPTXAsmPrinter &AP;
167 const bool EmitGeneric;
168
169 public:
170 AggBuffer(unsigned Size, const NVPTXAsmPrinter &AP)
171 : Size(Size), buffer(Size), curpos(0), AP(AP),
172 EmitGeneric(AP.EmitGeneric) {}
173
174 unsigned getBufferSize() const { return Size; }
175
176 // Number of bytes written so far.
177 unsigned getCurpos() const { return curpos; }
178
179 // Copy Num bytes from Ptr.
180 // if Bytes > Num, zero fill up to Bytes.
181 void addBytes(const unsigned char *Ptr, unsigned Num, unsigned Bytes) {
182 for (unsigned I : llvm::seq(Num))
183 addByte(Ptr[I]);
184 if (Bytes > Num)
185 addZeros(Bytes - Num);
186 }
187
188 void addByte(uint8_t Byte) {
189 assert(curpos < Size);
190 buffer[curpos] = Byte;
191 curpos++;
192 }
193
194 void addZeros(unsigned Num) {
195 for ([[maybe_unused]] unsigned _ : llvm::seq(Num)) {
196 addByte(0);
197 }
198 }
199
200 void addSymbol(const Value *GVar, const Value *GVarBeforeStripping) {
201 symbolPosInBuffer.push_back(curpos);
202 Symbols.push_back(GVar);
203 SymbolsBeforeStripping.push_back(GVarBeforeStripping);
204 }
205
206 void printBytes(raw_ostream &os);
207 void printWords(raw_ostream &os);
208
209 private:
210 void printSymbol(unsigned nSym, raw_ostream &os);
211 };
212
213 friend class AggBuffer;
214
215public:
216 static char ID;
217
218 StringRef getPassName() const override { return "NVPTX Assembly Printer"; }
219
220private:
221 const Function *F;
222
223 NVPTXTargetStreamer *getTargetStreamer() const;
224
225 void emitStartOfAsmFile(Module &M) override;
226 void emitBasicBlockStart(const MachineBasicBlock &MBB) override;
227 void emitFunctionEntryLabel() override;
228 void emitFunctionBodyStart() override;
229 void emitFunctionBodyEnd() override;
230 void emitImplicitDef(const MachineInstr *MI) const override;
231
232 void emitInstruction(const MachineInstr *) override;
233 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
234 MCOperand lowerOperand(const MachineOperand &MO);
235 MCOperand GetSymbolRef(const MCSymbol *Symbol);
236 MCRegister encodeVirtualRegister(Register Reg);
237
238 /// The number \p Reg was assigned within its register class, as declared by
239 /// this function's .reg directives.
240 unsigned getVirtualRegisterNumber(Register Reg) const;
241
242 void printMemOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O,
243 const char *Modifier = nullptr);
244 void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O,
245 bool processDemoted, const NVPTXSubtarget &STI);
246 // PTX permits these directives only between a .func directive and its body,
247 // so the caller must not use this for a kernel.
248 template <typename T>
249 void printFunctionDirectives(const T &V, raw_ostream &O) const;
250
251 void emitGlobals(const Module &M);
252 void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
253 void emitHeader(Module &M, const NVPTXSubtarget &STI);
254 void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const;
255 void emitFunctionParamList(const Function *, raw_ostream &O);
256 void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF);
257 void encodeDebugInfoRegisterNumbers(const MachineFunction &MF);
258 void emitCallPrototype(const CallBase &CB, MCSymbol *PrototypeSymbol) const;
259 void emitJumpTable(const MachineJumpTableEntry &MJT, unsigned MJTI) const;
260
261 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
262 const char *ExtraCode, raw_ostream &) override;
263 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
264 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
265 const char *ExtraCode, raw_ostream &) override;
266
267 const MCExpr *lowerConstantForGV(const Constant *CV,
268 bool ProcessingGeneric) const;
269 void printMCExpr(const MCExpr &Expr, raw_ostream &OS) const;
270 /// Emit a blob of inline asm to the output streamer.
271 void emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
272 const MCTargetOptions &MCOptions, const MDNode *LocMDNode,
273 InlineAsm::AsmDialect Dialect,
274 const MachineInstr *MI) override;
275
276protected:
277 bool doInitialization(Module &M) override;
278 bool doFinalization(Module &M) override;
279
280 /// Create NVPTX-specific DwarfDebug handler.
281 DwarfDebug *createDwarfDebug() override;
282
283private:
284 bool GlobalsEmitted;
285
286 // This is specific per MachineFunction.
288
289 // The number assigned to each virtual register within its class, populated
290 // by setAndEmitFunctionVirtualRegisters and cleared between functions.
291 using VRegMap = DenseMap<Register, unsigned>;
293 VRegRCMap VRegMapping;
294
295 // List of variables demoted to a function scope.
296 std::map<const Function *, std::vector<const GlobalVariable *>> localDecls;
297
298 /// Print the state space, alignment, type, name, and — when
299 /// \p EmitInitializer is set — the initializer of \p GVar. Passing false
300 /// prints a declaration whose type still matches the definition, as an
301 /// `.extern` forward declaration requires.
302 void emitPTXGlobalVariableDefinition(const GlobalVariable *GVar,
303 raw_ostream &O,
304 const NVPTXSubtarget &STI,
305 bool EmitInitializer);
306 void emitPTXAddressSpace(unsigned int AddressSpace, raw_ostream &O) const;
307 std::string getPTXFundamentalTypeStr(Type *Ty) const;
308 void printScalarConstant(const Constant *CPV, raw_ostream &O);
309 void printFPConstant(const ConstantFP *Fp, raw_ostream &O) const;
310 void bufferLEByte(const Constant *CPV, int Bytes, AggBuffer *aggBuffer);
311 void bufferAggregateConstant(const Constant *CV, AggBuffer *aggBuffer);
312 void bufferAggregateConstVec(const ConstantVector *CV, AggBuffer *aggBuffer);
313
314 void emitLinkageDirective(const GlobalValue *V, raw_ostream &O);
315 void emitDeclarations(const Module &, raw_ostream &O);
316 void emitDeclaration(const Function *, raw_ostream &O);
317 void emitAliasDeclaration(const GlobalAlias *, raw_ostream &O);
318 void emitDeclarationWithName(const Function *, MCSymbol *, raw_ostream &O);
319 void emitDemotedVars(const Function *, raw_ostream &);
320
321 bool isLoopHeaderOfNoUnroll(const MachineBasicBlock &MBB) const;
322
323 // Used to control the need to emit .generic() in the initializer of
324 // module scope variables.
325 // Although ptx supports the hybrid mode like the following,
326 // .global .u32 a;
327 // .global .u32 b;
328 // .global .u32 addr[] = {a, generic(b)}
329 // we have difficulty representing the difference in the NVVM IR.
330 //
331 // Since the address value should always be generic in CUDA C and always
332 // be specific in OpenCL, we use this simple control here.
333 //
334 const bool EmitGeneric;
335
336public:
337 NVPTXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
338 : AsmPrinter(TM, std::move(Streamer), ID),
339 EmitGeneric(static_cast<NVPTXTargetMachine &>(TM).getDrvInterface() ==
340 NVPTX::CUDA) {}
341
342 bool runOnMachineFunction(MachineFunction &F) override;
343
344 void getAnalysisUsage(AnalysisUsage &AU) const override {
347 }
348
349 std::string getVirtualRegisterName(Register Reg) const;
350
351 const MCSymbol *getFunctionFrameSymbol() const override;
352
353 // Make emitGlobalVariable() no-op for NVPTX.
354 // Global variables have been already emitted by the time the base AsmPrinter
355 // attempts to do so in doFinalization() (see NVPTXAsmPrinter::emitGlobals()).
356 void emitGlobalVariable(const GlobalVariable *GV) override {}
357};
358
359} // end anonymous namespace
360
361/// Emits initial debug location directive.
363 DwarfDebug *DD,
364 MCStreamer &OutStreamer) {
365 if (!DD)
366 return;
367
368 assert(OutStreamer.hasRawTextSupport() && "Expected assembly output mode.");
369 // This is NVPTX specific and it's unclear why.
370 // PR51079: If we have code without debug information we need to give up.
371 const DISubprogram *SP = MF.getFunction().getSubprogram();
372 if (!SP)
373 return;
374 assert(SP->getUnit());
375 // NoDebug and DebugDirectivesOnly do not require emitting the initial loc
376 // directive. NoDebug does not require any debug directives and the initial
377 // loc directive is not needed for DebugDirectivesOnly as it is redundant
378 // assuming this is a non-empty function.
379 if (SP->getUnit()->isDebugDirectivesOnly() || SP->getUnit()->isNoDebug())
380 return;
381
382 (void)DD->emitInitialLocDirective(MF, /*CUID=*/0);
383}
384
385namespace {
386
387/// Return a list of GlobalVariables on which \p V depends.
388static void
389discoverDependentGlobals(const Value *V,
390 SmallVectorImpl<const GlobalVariable *> &Globals,
391 SmallPtrSetImpl<const GlobalVariable *> &Seen) {
392 if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
393 if (Seen.insert(GV).second)
394 Globals.push_back(GV);
395 return;
396 }
397
398 // Global values are emitted as symbols. Their operands do not contribute to
399 // the initializer expression that refers to that symbol.
400 if (isa<GlobalValue>(V))
401 return;
402
403 // lowerConstantForGV emits a GEP as its base symbol plus a constant byte
404 // offset. Symbols used to compute an index are not part of that expression.
405 if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
406 discoverDependentGlobals(GEP->getPointerOperand(), Globals, Seen);
407 return;
408 }
409
410 if (const User *U = dyn_cast<User>(V))
411 for (const auto &O : U->operands())
412 discoverDependentGlobals(O, Globals, Seen);
413}
414
415struct GlobalVariableDependencyNode {
416 const GlobalVariable *GV = nullptr;
417 unsigned ModuleOrder = 0;
419};
420
421class GlobalVariableDependencyGraph {
422 // scc_iterator needs a single entry node. Global initializer dependencies
423 // may be disconnected, so use a synthetic root with an edge to every global.
424 GlobalVariableDependencyNode SyntheticRoot;
425 // Edges store pointers into Nodes, so node addresses must remain stable while
426 // the graph is constructed.
427 std::map<const GlobalVariable *, GlobalVariableDependencyNode> Nodes;
428
429public:
430 explicit GlobalVariableDependencyGraph(const Module &M) {
431 unsigned ModuleOrder = 0;
432 for (const GlobalVariable &GV : M.globals()) {
433 GlobalVariableDependencyNode &Node = Nodes.try_emplace(&GV).first->second;
434 Node.GV = &GV;
435 Node.ModuleOrder = ModuleOrder++;
436 SyntheticRoot.Dependencies.push_back(&Node);
437 }
438
439 for (auto &[GV, Node] : Nodes) {
441 SmallPtrSet<const GlobalVariable *, 4> Seen;
442 for (const Use &Operand : GV->operands())
443 discoverDependentGlobals(Operand, Dependencies, Seen);
444
445 for (const GlobalVariable *Dependency : Dependencies) {
446 auto It = Nodes.find(Dependency);
447 if (It != Nodes.end())
448 Node.Dependencies.push_back(&It->second);
449 }
450 }
451 }
452
453 const GlobalVariableDependencyNode *getEntryNode() const {
454 return &SyntheticRoot;
455 }
456};
457
458struct GlobalVariableDependencyGraphTraits {
459 using NodeRef = const GlobalVariableDependencyNode *;
460 using ChildIteratorType =
462
463 static NodeRef getEntryNode(NodeRef Node) { return Node; }
464 static ChildIteratorType child_begin(NodeRef Node) {
465 return Node->Dependencies.begin();
466 }
467 static ChildIteratorType child_end(NodeRef Node) {
468 return Node->Dependencies.end();
469 }
470};
471
472using GlobalVariableSCCIterator =
473 scc_iterator<const GlobalVariableDependencyNode *,
474 GlobalVariableDependencyGraphTraits>;
475
476static bool shouldSkipModuleLevelGlobal(const GlobalVariable &GV) {
477 if (GV.hasSection() && GV.getSection() == "llvm.metadata")
478 return true;
479 return GV.getName().starts_with("llvm.") || GV.getName().starts_with("nvvm.");
480}
481
482static bool isForwardDeclarableGlobal(const GlobalVariable *GVar) {
483 if (shouldSkipModuleLevelGlobal(*GVar) || GVar->isDeclaration() ||
484 getPTXOpaqueType(*GVar) != PTXOpaqueType::None)
485 return false;
486
487 // A PTX .extern declaration can be resolved by a later .visible, .weak, or
488 // .common definition, but not by a static definition.
489 if (GVar->hasExternalLinkage())
490 return GVar->hasInitializer();
491
492 if (GVar->hasLinkOnceLinkage() || GVar->hasWeakLinkage() ||
494 return true;
495
496 return false;
497}
498
499/// Order definitions after treating references to forward-declared globals as
500/// already satisfied. A remaining cycle cannot be emitted portably because it
501/// requires an undeclared forward reference.
502static SmallVector<const GlobalVariable *, 4> orderDefinitionsInSCC(
504 const DenseSet<const GlobalVariableDependencyNode *> &ForwardDeclared) {
505 using Node = GlobalVariableDependencyNode;
506
507 DenseSet<const Node *> SCCSet;
508 SCCSet.insert_range(SCC);
509
510 DenseMap<const Node *, unsigned> DependencyCount;
511 DenseMap<const Node *, SmallVector<const Node *, 4>> Dependents;
512 std::set<std::pair<unsigned, const Node *>> Ready;
513
514 // Dependencies outside this SCC have already been emitted. Forward-declared
515 // dependencies are also satisfied, so only count the remaining SCC edges.
516 for (const Node *N : SCC) {
517 unsigned &Count = DependencyCount[N];
518 for (const Node *Dependency : N->Dependencies) {
519 if (!SCCSet.count(Dependency) || ForwardDeclared.count(Dependency))
520 continue;
521 ++Count;
522 Dependents[Dependency].push_back(N);
523 }
524 if (Count == 0)
525 Ready.emplace(N->ModuleOrder, N);
526 }
527
529 while (!Ready.empty()) {
530 const Node *N = Ready.begin()->second;
531 Ready.erase(Ready.begin());
532 Order.push_back(N->GV);
533
534 auto It = Dependents.find(N);
535 if (It == Dependents.end())
536 continue;
537 for (const Node *Dependent : It->second) {
538 assert(DependencyCount[Dependent] && "Dependency already satisfied");
539 if (--DependencyCount[Dependent] == 0)
540 Ready.emplace(Dependent->ModuleOrder, Dependent);
541 }
542 }
543
544 if (Order.size() != SCC.size())
545 report_fatal_error("Circular dependency found in global variable set");
546 return Order;
547}
548
549} // namespace
550
551void NVPTXAsmPrinter::emitInstruction(const MachineInstr *MI) {
552 NVPTX_MC::verifyInstructionPredicates(MI->getOpcode(),
553 getSubtargetInfo().getFeatureBits());
554
555 MCInst Inst;
556 lowerToMCInst(MI, Inst);
557 EmitToStreamer(*OutStreamer, Inst);
558}
559
560void NVPTXAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
561 OutMI.setOpcode(MI->getOpcode());
562 for (const auto MO : MI->operands())
563 OutMI.addOperand(lowerOperand(MO));
564}
565
566MCOperand NVPTXAsmPrinter::lowerOperand(const MachineOperand &MO) {
567 switch (MO.getType()) {
568 default:
569 llvm_unreachable("unknown operand type");
571 return MCOperand::createReg(encodeVirtualRegister(MO.getReg()));
573 return MCOperand::createImm(MO.getImm());
576 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), OutContext));
578 return GetSymbolRef(GetExternalSymbolSymbol(MO.getSymbolName()));
580 return GetSymbolRef(MO.getMCSymbol());
582 // The jump table index names the .branchtargets list emitted for a brx.idx
583 // (see emitJumpTable); reference it by that label.
584 return GetSymbolRef(GetJTISymbol(MO.getIndex()));
586 return GetSymbolRef(getSymbol(MO.getGlobal()));
588 const ConstantFP *Cnt = MO.getFPImm();
589 const APFloat &Val = Cnt->getValueAPF();
590
591 switch (Cnt->getType()->getTypeID()) {
592 default:
593 report_fatal_error("Unsupported FP type");
594 break;
595 case Type::HalfTyID:
598 case Type::BFloatTyID:
601 case Type::FloatTyID:
604 case Type::DoubleTyID:
607 }
608 break;
609 }
610 }
611}
612
613static NVPTX::VirtualRegisterKind
615 if (RC == &NVPTX::B1RegClass)
617 if (RC == &NVPTX::B16RegClass)
619 if (RC == &NVPTX::B32RegClass)
621 if (RC == &NVPTX::B64RegClass)
623 if (RC == &NVPTX::B128RegClass)
625 llvm_unreachable("Bad register class");
626}
627
628unsigned NVPTXAsmPrinter::getVirtualRegisterNumber(Register Reg) const {
629 const auto It = VRegMapping.find(MRI->getRegClass(Reg));
630 assert(It != VRegMapping.end() && "Bad register class");
631
632 const unsigned Num = It->second.lookup(Reg);
633 assert(Num && "Bad virtual register");
634 return Num;
635}
636
637MCRegister NVPTXAsmPrinter::encodeVirtualRegister(Register Reg) {
638 if (Reg.isVirtual()) {
639 // Pack the register class into the upper bits so that
640 // NVPTXInstPrinter::printRegName can recover the declared name.
642 const unsigned Num = getVirtualRegisterNumber(Reg);
643 assert(Num <= NVPTX::VirtualRegisterNumMask &&
644 "Too many virtual registers");
645 return (static_cast<unsigned>(Kind) << NVPTX::VirtualRegisterKindShift) |
646 Num;
647 }
648
649 // Some special-use registers are actually physical registers.
650 // Encode this as the register class ID of 0 and the real register ID.
651 assert(Reg.id() <= NVPTX::VirtualRegisterNumMask &&
652 "Physical register would decode as a virtual register");
653 return Reg.asMCReg();
654}
655
656MCOperand NVPTXAsmPrinter::GetSymbolRef(const MCSymbol *Symbol) {
657 const MCExpr *Expr;
658 Expr = MCSymbolRefExpr::create(Symbol, OutContext);
659 return MCOperand::createExpr(Expr);
660}
661
662template <typename OwnerT>
663static void printParam(const OwnerT *Owner, Type *Ty, unsigned AttrIdx,
664 bool IsByVal, bool IsKernel, StringRef Name,
665 const DataLayout &DL, raw_ostream &O) {
666 O << ".param ";
667
668 if (IsByVal || shouldPassAsArray(Ty)) {
669 const Align ParamAlign =
670 IsByVal && !IsKernel ? getDeviceByValParamAlign(Owner, Ty, AttrIdx, DL)
671 : getPTXParamAlign(Owner, Ty, AttrIdx, DL);
672 O << ".align " << ParamAlign.value() << " .b8 " << Name << "["
673 << DL.getTypeAllocSize(Ty) << "]";
674 return;
675 }
676
677 assert((Ty->isFloatingPointTy() || Ty->isIntOrPtrTy()) &&
678 "Unknown parameter type");
679 const unsigned Size = DL.getTypeSizeInBits(Ty).getFixedValue();
680 O << ".b"
683 << " " << Name;
684}
685
686template <typename OwnerT>
687static void printReturnValClause(const OwnerT *Owner, StringRef Name,
688 const DataLayout &DL, raw_ostream &O) {
689 Type *RetTy = Owner->getFunctionType()->getReturnType();
690
691 // A void or zero-sized return type (e.g. an empty struct) produces no return
692 // parameter.
693 if (RetTy->isVoidTy() || RetTy->isEmptyTy())
694 return;
695
696 // Only device functions return a value, so no kernel promotion applies.
697 O << "(";
698 printParam(Owner, RetTy, AttributeList::ReturnIndex, /*IsByVal=*/false,
699 /*IsKernel=*/false, Name, DL, O);
700 O << ") ";
701}
702
703void NVPTXAsmPrinter::emitCallPrototype(const CallBase &CB,
704 MCSymbol *PrototypeSymbol) const {
705 const DataLayout &DL = getDataLayout();
706 const NVPTXSubtarget &STI = MF->getSubtarget<NVPTXSubtarget>();
707
708 OutStreamer->emitLabel(PrototypeSymbol);
709
710 SmallString<128> Str;
711 raw_svector_ostream O(Str);
712
713 O << ".callprototype ";
714 printReturnValClause(&CB, "_", DL, O);
715 O << "_ (";
716
717 auto MakeArg = [&](const unsigned I) {
718 const bool IsByVal = CB.isByValArgument(I);
719 Type *Ty =
720 IsByVal ? CB.getParamByValType(I) : CB.getArgOperand(I)->getType();
721
722 printParam(&CB, Ty, I + AttributeList::FirstArgIndex, IsByVal,
723 /*IsKernel=*/false, "_", DL, O);
724 };
725
726 const FunctionType *FTy = CB.getFunctionType();
727 const unsigned NumArgs = FTy->getNumParams();
728
729 // Zero-sized arguments (e.g. empty structs) are not passed and so do not
730 // appear in the prototype.
731 const auto NonEmptyArgs = make_filter_range(seq(NumArgs), [&](unsigned I) {
732 return !CB.getArgOperand(I)->getType()->isEmptyTy();
733 });
734
735 interleave(NonEmptyArgs, O, MakeArg, ", ");
736
737 if (FTy->isVarArg() && CB.arg_size() > NumArgs)
738 O << (NonEmptyArgs.empty() ? "" : ",") << " .param .align "
739 << STI.getMaxRequiredAlignment() << " .b8 _[]";
740
741 O << ")\n";
742 printFunctionDirectives(CB, O);
743 O << ";\n";
744
745 OutStreamer->emitRawText(O.str());
746}
747
748void NVPTXAsmPrinter::emitJumpTable(const MachineJumpTableEntry &MJT,
749 unsigned MJTI) const {
750 OutStreamer->emitLabel(GetJTISymbol(MJTI));
751
752 if (MJT.MBBs.empty())
753 return;
754
755 const auto Targets = to_vector(
756 map_range(MJT.MBBs, [](const MachineBasicBlock *MBB) -> const MCSymbol * {
757 return MBB->getSymbol();
758 }));
759 getTargetStreamer()->emitBranchTargetsDirective(Targets);
760}
761
762// Return true if MBB is the header of a loop marked with
763// llvm.loop.unroll.disable or llvm.loop.unroll.count=1.
764bool NVPTXAsmPrinter::isLoopHeaderOfNoUnroll(
765 const MachineBasicBlock &MBB) const {
766 const MachineLoopInfo *LI = GetMLI(*MF);
767 assert(LI && "NVPTXAsmPrinter requires MachineLoopInfo");
768 // We insert .pragma "nounroll" only to the loop header.
769 if (!LI->isLoopHeader(&MBB))
770 return false;
771
772 // llvm.loop.unroll.disable is marked on the back edges of a loop. Therefore,
773 // we iterate through each back edge of the loop with header MBB, and check
774 // whether its metadata contains llvm.loop.unroll.disable.
775 for (const MachineBasicBlock *PMBB : MBB.predecessors()) {
776 if (LI->getLoopFor(PMBB) != LI->getLoopFor(&MBB)) {
777 // Edges from other loops to MBB are not back edges.
778 continue;
779 }
780 if (const BasicBlock *PBB = PMBB->getBasicBlock()) {
781 if (MDNode *LoopID =
782 PBB->getTerminator()->getMetadata(LLVMContext::MD_loop)) {
783 if (GetUnrollMetadata(LoopID, "llvm.loop.unroll.disable"))
784 return true;
785 if (MDNode *UnrollCountMD =
786 GetUnrollMetadata(LoopID, "llvm.loop.unroll.count")) {
787 if (mdconst::extract<ConstantInt>(UnrollCountMD->getOperand(1))
788 ->isOne())
789 return true;
790 }
791 }
792 }
793 }
794 return false;
795}
796
797void NVPTXAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
799 if (isLoopHeaderOfNoUnroll(MBB))
800 getTargetStreamer()->emitPragmaDirective("nounroll");
801}
802
803void NVPTXAsmPrinter::emitFunctionEntryLabel() {
804 SmallString<128> Str;
805 raw_svector_ostream O(Str);
806
807 if (!GlobalsEmitted) {
808 emitGlobals(*MF->getFunction().getParent());
809 GlobalsEmitted = true;
810 }
811
812 // Set up
813 MRI = &MF->getRegInfo();
814 F = &MF->getFunction();
815 emitLinkageDirective(F, O);
816 if (isKernelFunction(*F))
817 O << ".entry ";
818 else {
819 O << ".func ";
820 printReturnValClause(F, "func_retval0", getDataLayout(), O);
821 }
822
823 CurrentFnSym->print(O, MAI);
824
825 emitFunctionParamList(F, O);
826 O << "\n";
827
828 if (isKernelFunction(*F))
829 emitKernelFunctionDirectives(*F, O);
830 else
831 printFunctionDirectives(*F, O);
832
833 OutStreamer->emitRawText(O.str());
834
835 VRegMapping.clear();
836 // Emit open brace for function body.
837 OutStreamer->emitRawText(StringRef("{\n"));
838 setAndEmitFunctionVirtualRegisters(*MF);
839 encodeDebugInfoRegisterNumbers(*MF);
840 // Emit initial .loc debug directive for correct relocation symbol data.
841 emitInitialRawDwarfLocDirective(*MF, getDwarfDebug(), *OutStreamer);
842}
843
844bool NVPTXAsmPrinter::runOnMachineFunction(MachineFunction &F) {
846 // Emit closing brace for the body of function F.
847 // The closing brace must be emitted here because we need to emit additional
848 // debug labels/data after the last basic block.
849 // We need to emit the closing brace here because we don't have function that
850 // finished emission of the function body.
851 OutStreamer->emitRawText(StringRef("}\n"));
852 return Result;
853}
854
855void NVPTXAsmPrinter::emitFunctionBodyStart() {
856 SmallString<128> Str;
857 raw_svector_ostream O(Str);
858 emitDemotedVars(&MF->getFunction(), O);
859 OutStreamer->emitRawText(O.str());
860
861 const auto *MFI = MF->getInfo<NVPTXMachineFunctionInfo>();
862 for (const auto &[CB, Symbol] : MFI->getCallPrototypes())
863 emitCallPrototype(*CB, Symbol);
864
865 if (const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo())
866 for (const auto &[Idx, JT] : enumerate(MJTI->getJumpTables()))
867 emitJumpTable(JT, Idx);
868}
869
870void NVPTXAsmPrinter::emitFunctionBodyEnd() {
871 VRegMapping.clear();
872}
873
874const MCSymbol *NVPTXAsmPrinter::getFunctionFrameSymbol() const {
875 return OutContext.getOrCreateSymbol(DEPOTNAME + Twine(getFunctionNumber()));
876}
877
878void NVPTXAsmPrinter::emitImplicitDef(const MachineInstr *MI) const {
879 Register RegNo = MI->getOperand(0).getReg();
880 if (RegNo.isVirtual())
881 OutStreamer->AddComment(Twine("implicit-def: ") +
882 getVirtualRegisterName(RegNo));
883 else
884 OutStreamer->AddComment(Twine("implicit-def: ") +
886 OutStreamer->addBlankLine();
887}
888
889void NVPTXAsmPrinter::emitKernelFunctionDirectives(const Function &F,
890 raw_ostream &O) const {
891 // If the NVVM IR has some of reqntid* specified, then output
892 // the reqntid directive, and set the unspecified ones to 1.
893 // If none of Reqntid* is specified, don't output reqntid directive.
894 const auto ReqNTID = getReqNTID(F);
895 if (!ReqNTID.empty())
896 O << formatv(".reqntid {0:$[, ]}\n",
898
899 const auto MaxNTID = getMaxNTID(F);
900 if (!MaxNTID.empty())
901 O << formatv(".maxntid {0:$[, ]}\n",
903
904 if (const auto Mincta = getMinCTASm(F))
905 O << ".minnctapersm " << *Mincta << "\n";
906
907 if (const auto Maxnreg = getMaxNReg(F))
908 O << ".maxnreg " << *Maxnreg << "\n";
909
910 // .maxclusterrank directive requires SM_90 or higher, make sure that we
911 // filter it out for lower SM versions, as it causes a hard ptxas crash.
912 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
913 const NVPTXSubtarget *STI = &NTM.getSubtarget<NVPTXSubtarget>(F);
914
915 if (STI->hasFeature(NVPTX::SM90)) {
916 const auto ClusterDim = getClusterDim(F);
918
919 if (!ClusterDim.empty()) {
920
921 if (!BlocksAreClusters)
922 O << ".explicitcluster\n";
923
924 if (ClusterDim[0] != 0) {
925 assert(llvm::all_of(ClusterDim, not_equal_to(0)) &&
926 "cluster_dim_x != 0 implies cluster_dim_y and cluster_dim_z "
927 "should be non-zero as well");
928
929 O << formatv(".reqnctapercluster {0:$[, ]}\n",
931 } else {
932 assert(llvm::all_of(ClusterDim, equal_to(0)) &&
933 "cluster_dim_x == 0 implies cluster_dim_y and cluster_dim_z "
934 "should be 0 as well");
935 }
936 }
937
938 if (BlocksAreClusters) {
939 LLVMContext &Ctx = F.getContext();
940 if (ReqNTID.empty() || ClusterDim.empty())
941 Ctx.diagnose(DiagnosticInfoUnsupported(
942 F, "blocksareclusters requires reqntid and cluster_dim attributes",
943 F.getSubprogram()));
944 else if (!STI->hasFeature(NVPTX::PTX90))
945 Ctx.diagnose(DiagnosticInfoUnsupported(
946 F, "blocksareclusters requires PTX version >= 9.0",
947 F.getSubprogram()));
948 else
949 O << ".blocksareclusters\n";
950 }
951
952 if (const auto Maxclusterrank = getMaxClusterRank(F))
953 O << ".maxclusterrank " << *Maxclusterrank << "\n";
954 }
955}
956
957std::string NVPTXAsmPrinter::getVirtualRegisterName(Register Reg) const {
959
960 std::string Name;
961 raw_string_ostream(Name) << NVPTX::getVirtualRegisterPrefix(Kind)
962 << getVirtualRegisterNumber(Reg);
963 return Name;
964}
965
966void NVPTXAsmPrinter::emitAliasDeclaration(const GlobalAlias *GA,
967 raw_ostream &O) {
969 if (!F || isKernelFunction(*F) || F->isDeclaration())
971 "NVPTX aliasee must be a non-kernel function definition");
972
973 if (GA->hasLinkOnceLinkage() || GA->hasWeakLinkage() ||
975 report_fatal_error("NVPTX aliasee must not be '.weak'");
976
977 emitDeclarationWithName(F, getSymbol(GA), O);
978}
979
980void NVPTXAsmPrinter::emitDeclaration(const Function *F, raw_ostream &O) {
981 emitDeclarationWithName(F, getSymbol(F), O);
982}
983
984void NVPTXAsmPrinter::emitDeclarationWithName(const Function *F, MCSymbol *S,
985 raw_ostream &O) {
986 emitLinkageDirective(F, O);
987 if (isKernelFunction(*F)) {
988 O << ".entry ";
989 } else {
990 O << ".func ";
991 printReturnValClause(F, "func_retval0", getDataLayout(), O);
992 }
993 S->print(O, MAI);
994 O << "\n";
995 emitFunctionParamList(F, O);
996 O << "\n";
997 if (!isKernelFunction(*F))
998 printFunctionDirectives(*F, O);
999 O << ";\n";
1000}
1001
1002static bool usedInGlobalVarDef(const Constant *C) {
1003 if (!C)
1004 return false;
1005
1006 if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C))
1007 return GV->getName() != "llvm.used";
1008
1009 for (const User *U : C->users())
1010 if (const Constant *C = dyn_cast<Constant>(U))
1011 if (usedInGlobalVarDef(C))
1012 return true;
1013
1014 return false;
1015}
1016
1017static bool usedInOneFunc(const User *U, Function const *&OneFunc) {
1018 if (const GlobalVariable *OtherGV = dyn_cast<GlobalVariable>(U))
1019 if (OtherGV->getName() == "llvm.used")
1020 return true;
1021
1022 if (const Instruction *I = dyn_cast<Instruction>(U)) {
1023 if (const Function *CurFunc = I->getFunction()) {
1024 if (OneFunc && (CurFunc != OneFunc))
1025 return false;
1026 OneFunc = CurFunc;
1027 return true;
1028 }
1029 return false;
1030 }
1031
1032 for (const User *UU : U->users())
1033 if (!usedInOneFunc(UU, OneFunc))
1034 return false;
1035
1036 return true;
1037}
1038
1039/* Find out if a global variable can be demoted to local scope.
1040 * Currently, this is valid for CUDA shared variables, which have local
1041 * scope and global lifetime. So the conditions to check are :
1042 * 1. Is the global variable in shared address space?
1043 * 2. Does it have local linkage?
1044 * 3. Is the global variable referenced only in one function?
1045 */
1046static bool canDemoteGlobalVar(const GlobalVariable *GV, Function const *&f) {
1047 if (!GV->hasLocalLinkage())
1048 return false;
1050 return false;
1051
1052 const Function *oneFunc = nullptr;
1053
1054 bool flag = usedInOneFunc(GV, oneFunc);
1055 if (!flag)
1056 return false;
1057 if (!oneFunc)
1058 return false;
1059 f = oneFunc;
1060 return true;
1061}
1062
1063static bool useFuncSeen(const Constant *C,
1064 const SmallPtrSetImpl<const Function *> &SeenSet) {
1065 for (const User *U : C->users()) {
1066 if (const Constant *cu = dyn_cast<Constant>(U)) {
1067 if (useFuncSeen(cu, SeenSet))
1068 return true;
1069 } else if (const Instruction *I = dyn_cast<Instruction>(U)) {
1070 if (const Function *Caller = I->getFunction())
1071 if (SeenSet.contains(Caller))
1072 return true;
1073 }
1074 }
1075 return false;
1076}
1077
1078void NVPTXAsmPrinter::emitDeclarations(const Module &M, raw_ostream &O) {
1079 SmallPtrSet<const Function *, 32> SeenSet;
1080 for (const Function &F : M) {
1081 if (F.getAttributes().hasFnAttr("nvptx-libcall-callee")) {
1082 emitDeclaration(&F, O);
1083 continue;
1084 }
1085
1086 if (F.isDeclaration()) {
1087 if (F.use_empty())
1088 continue;
1089 if (F.getIntrinsicID())
1090 continue;
1091 // An unrecognized intrinsic would produce an invalid PTX declaration. Let
1092 // the user know that, and skip it.
1093 if (F.isIntrinsic()) {
1094 LLVMContext &Ctx = F.getContext();
1095 Ctx.diagnose(DiagnosticInfoUnsupported(
1096 F, "unknown intrinsic '" + F.getName() +
1097 "' cannot be lowered by the NVPTX backend"));
1098 continue;
1099 }
1100 emitDeclaration(&F, O);
1101 continue;
1102 }
1103 for (const User *U : F.users()) {
1104 if (const Constant *C = dyn_cast<Constant>(U)) {
1105 if (usedInGlobalVarDef(C)) {
1106 // The use is in the initialization of a global variable
1107 // that is a function pointer, so print a declaration
1108 // for the original function
1109 emitDeclaration(&F, O);
1110 break;
1111 }
1112 // Emit a declaration of this function if the function that
1113 // uses this constant expr has already been seen.
1114 if (useFuncSeen(C, SeenSet)) {
1115 emitDeclaration(&F, O);
1116 break;
1117 }
1118 }
1119
1120 if (!isa<Instruction>(U))
1121 continue;
1122 const Function *Caller = cast<Instruction>(U)->getFunction();
1123 if (!Caller)
1124 continue;
1125
1126 // If a caller has already been seen, then the caller is
1127 // appearing in the module before the callee. so print out
1128 // a declaration for the callee.
1129 if (SeenSet.contains(Caller)) {
1130 emitDeclaration(&F, O);
1131 break;
1132 }
1133 }
1134 SeenSet.insert(&F);
1135 }
1136 for (const GlobalAlias &GA : M.aliases())
1137 emitAliasDeclaration(&GA, O);
1138}
1139
1140void NVPTXAsmPrinter::emitStartOfAsmFile(Module &M) {
1141 // Construct a default subtarget off of the TargetMachine defaults. The
1142 // rest of NVPTX isn't friendly to change subtargets per function and
1143 // so the default TargetMachine will have all of the options.
1144 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
1145 const NVPTXSubtarget *STI = NTM.getSubtargetImpl();
1146
1147 // Emit header before any dwarf directives are emitted below.
1148 emitHeader(M, *STI);
1149}
1150
1151/// Create NVPTX-specific DwarfDebug handler.
1152DwarfDebug *NVPTXAsmPrinter::createDwarfDebug() {
1153 return new NVPTXDwarfDebug(this);
1154}
1155
1156bool NVPTXAsmPrinter::doInitialization(Module &M) {
1157 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
1158 const NVPTXSubtarget &STI = *NTM.getSubtargetImpl();
1159 if (M.alias_size() &&
1160 (!STI.hasFeature(NVPTX::PTX63) || !STI.hasFeature(NVPTX::SM30)))
1161 report_fatal_error(".alias requires PTX version >= 6.3 and sm_30");
1162
1163 // We need to call the parent's one explicitly.
1165
1166 GlobalsEmitted = false;
1167
1168 // Ensure globals are in the symbol table before ISel so any temp symbols are
1169 // guaranteed not to collide with user symbols
1170 for (const GlobalValue &GV : M.global_values())
1171 getSymbol(&GV);
1172
1173 return Result;
1174}
1175
1176void NVPTXAsmPrinter::emitGlobals(const Module &M) {
1177 SmallString<128> Str2;
1178 raw_svector_ostream OS2(Str2);
1179
1180 emitDeclarations(M, OS2);
1181
1182 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
1183 const NVPTXSubtarget &STI = *NTM.getSubtargetImpl();
1184
1185 // ptxas requires global symbols referenced by initializers to be known
1186 // before use. Acyclic dependencies can be handled by dependency-first
1187 // emission. Cyclic SCCs need compatible .extern declarations first.
1188 // Edges point from each global to the globals used by its initializer.
1189 // Reverse-topological SCC iteration therefore emits dependencies first.
1190 GlobalVariableDependencyGraph DependencyGraph(M);
1191 for (GlobalVariableSCCIterator I =
1192 GlobalVariableSCCIterator::begin(DependencyGraph.getEntryNode());
1193 !I.isAtEnd(); ++I) {
1195 I->end());
1196
1197 // Nothing points to the synthetic root, so it is always in its own SCC.
1198 if (!SCC.front()->GV) {
1199 assert(SCC.size() == 1 && "Synthetic root must be in its own SCC");
1200 continue;
1201 }
1202
1203 llvm::sort(SCC, [](const auto *LHS, const auto *RHS) {
1204 return LHS->ModuleOrder < RHS->ModuleOrder;
1205 });
1206
1207 const bool IsCyclic = I.hasCycle();
1208 DenseSet<const GlobalVariableDependencyNode *> ForwardDeclared;
1209 if (IsCyclic)
1210 for (const auto *Node : SCC)
1211 if (isForwardDeclarableGlobal(Node->GV))
1212 ForwardDeclared.insert(Node);
1213
1214 // Check that declarations break every cycle before writing any output.
1216 IsCyclic ? orderDefinitionsInSCC(SCC, ForwardDeclared)
1217 : SmallVector<const GlobalVariable *, 4>{SCC.front()->GV};
1218
1219 for (const auto *Node : SCC) {
1220 if (!ForwardDeclared.count(Node))
1221 continue;
1222 OS2 << ".extern ";
1223 emitPTXGlobalVariableDefinition(Node->GV, OS2, STI,
1224 /*EmitInitializer=*/false);
1225 OS2 << ";\n";
1226 }
1227
1228 for (const GlobalVariable *GV : OrderedGlobals)
1229 printModuleLevelGV(GV, OS2, /*ProcessDemoted=*/false, STI);
1230 }
1231
1232 OS2 << '\n';
1233
1234 OutStreamer->emitRawText(OS2.str());
1235}
1236
1237void NVPTXAsmPrinter::emitGlobalAlias(const Module &M, const GlobalAlias &GA) {
1238 getTargetStreamer()->emitAliasDirective(getSymbol(&GA),
1239 getSymbol(GA.getAliaseeObject()));
1240}
1241
1242NVPTXTargetStreamer *NVPTXAsmPrinter::getTargetStreamer() const {
1243 return static_cast<NVPTXTargetStreamer *>(OutStreamer->getTargetStreamer());
1244}
1245
1246static bool hasFullDebugInfo(Module &M) {
1247 for (DICompileUnit *CU : M.debug_compile_units()) {
1248 switch(CU->getEmissionKind()) {
1251 break;
1254 return true;
1255 }
1256 }
1257
1258 return false;
1259}
1260
1261void NVPTXAsmPrinter::emitHeader(Module &M, const NVPTXSubtarget &STI) {
1262 auto *TS = getTargetStreamer();
1263
1264 TS->emitBanner();
1265
1266 const unsigned PTXVersion = STI.getPTXVersion();
1267 TS->emitVersionDirective(PTXVersion);
1268
1269 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
1270 bool TexModeIndependent = NTM.getDrvInterface() == NVPTX::NVCL;
1271
1272 TS->emitTargetDirective(STI.getTargetName(), TexModeIndependent,
1273 hasFullDebugInfo(M));
1274 TS->emitAddressSizeDirective(M.getDataLayout().getPointerSizeInBits());
1275}
1276
1277bool NVPTXAsmPrinter::doFinalization(Module &M) {
1278 // If we did not emit any functions, then the global declarations have not
1279 // yet been emitted.
1280 if (!GlobalsEmitted) {
1281 emitGlobals(M);
1282 GlobalsEmitted = true;
1283 }
1284
1285 // call doFinalization
1286 bool ret = AsmPrinter::doFinalization(M);
1287
1289
1290 auto *TS =
1291 static_cast<NVPTXTargetStreamer *>(OutStreamer->getTargetStreamer());
1292 // Close the last emitted section
1293 if (hasDebugInfo()) {
1294 TS->closeLastSection();
1295 // Emit empty .debug_macinfo section for better support of the empty files.
1296 TS->emitEmptySectionDirective(".debug_macinfo");
1297 }
1298
1299 // Output last DWARF .file directives, if any.
1300 TS->outputDwarfFileDirectives();
1301
1302 return ret;
1303}
1304
1305// This function emits appropriate linkage directives for
1306// functions and global variables.
1307//
1308// extern function declaration -> .extern
1309// extern function definition -> .visible
1310// external global variable with init -> .visible
1311// external without init -> .extern
1312// appending -> not allowed, assert.
1313// for any linkage other than
1314// internal, private, linker_private,
1315// linker_private_weak, linker_private_weak_def_auto,
1316// we emit -> .weak.
1317
1318void NVPTXAsmPrinter::emitLinkageDirective(const GlobalValue *V,
1319 raw_ostream &O) {
1320 if (static_cast<NVPTXTargetMachine &>(TM).getDrvInterface() == NVPTX::CUDA) {
1321 if (V->hasExternalLinkage()) {
1322 if (const auto *GVar = dyn_cast<GlobalVariable>(V))
1323 O << (GVar->hasInitializer() ? ".visible " : ".extern ");
1324 else if (V->isDeclaration())
1325 O << ".extern ";
1326 else
1327 O << ".visible ";
1328 } else if (V->hasAppendingLinkage()) {
1329 report_fatal_error("Symbol '" + (V->hasName() ? V->getName() : "") +
1330 "' has unsupported appending linkage type");
1331 } else if (!V->hasInternalLinkage() && !V->hasPrivateLinkage()) {
1332 O << ".weak ";
1333 }
1334 }
1335}
1336
1337void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
1338 raw_ostream &O, bool ProcessDemoted,
1339 const NVPTXSubtarget &STI) {
1340 // Skip metadata and LLVM intrinsic global variables.
1341 if (shouldSkipModuleLevelGlobal(*GVar))
1342 return;
1343
1344 if (GVar->hasExternalLinkage()) {
1345 if (GVar->hasInitializer())
1346 O << ".visible ";
1347 else
1348 O << ".extern ";
1349 } else if (STI.hasFeature(NVPTX::PTX50) && GVar->hasCommonLinkage() &&
1351 O << ".common ";
1352 } else if (GVar->hasLinkOnceLinkage() || GVar->hasWeakLinkage() ||
1354 GVar->hasCommonLinkage()) {
1355 O << ".weak ";
1356 }
1357
1358 const PTXOpaqueType OpaqueType = getPTXOpaqueType(*GVar);
1359
1360 if (OpaqueType == PTXOpaqueType::Texture) {
1361 O << ".global .texref ";
1362 getSymbol(GVar)->print(O, MAI);
1363 O << ";\n";
1364 return;
1365 }
1366
1367 if (OpaqueType == PTXOpaqueType::Surface) {
1368 O << ".global .surfref ";
1369 getSymbol(GVar)->print(O, MAI);
1370 O << ";\n";
1371 return;
1372 }
1373
1374 if (GVar->isDeclaration()) {
1375 // (extern) declarations, no definition or initializer
1376 // Currently the only known declaration is for an automatic __local
1377 // (.shared) promoted to global.
1378 emitPTXGlobalVariableDefinition(GVar, O, STI, /*EmitInitializer=*/false);
1379 O << ";\n";
1380 return;
1381 }
1382
1383 if (OpaqueType == PTXOpaqueType::Sampler) {
1384 O << ".global .samplerref ";
1385 getSymbol(GVar)->print(O, MAI);
1386
1387 const Constant *Initializer = nullptr;
1388 if (GVar->hasInitializer())
1389 Initializer = GVar->getInitializer();
1390 const ConstantInt *CI = nullptr;
1391 if (Initializer)
1392 CI = dyn_cast<ConstantInt>(Initializer);
1393 if (CI) {
1394 unsigned sample = CI->getZExtValue();
1395
1396 O << " = { ";
1397
1398 for (int i = 0,
1399 addr = ((sample & __CLK_ADDRESS_MASK) >> __CLK_ADDRESS_BASE);
1400 i < 3; i++) {
1401 O << "addr_mode_" << i << " = ";
1402 switch (addr) {
1403 case 0:
1404 O << "wrap";
1405 break;
1406 case 1:
1407 O << "clamp_to_border";
1408 break;
1409 case 2:
1410 O << "clamp_to_edge";
1411 break;
1412 case 3:
1413 O << "wrap";
1414 break;
1415 case 4:
1416 O << "mirror";
1417 break;
1418 }
1419 O << ", ";
1420 }
1421 O << "filter_mode = ";
1422 switch ((sample & __CLK_FILTER_MASK) >> __CLK_FILTER_BASE) {
1423 case 0:
1424 O << "nearest";
1425 break;
1426 case 1:
1427 O << "linear";
1428 break;
1429 case 2:
1430 llvm_unreachable("Anisotropic filtering is not supported");
1431 default:
1432 O << "nearest";
1433 break;
1434 }
1435 if (!((sample & __CLK_NORMALIZED_MASK) >> __CLK_NORMALIZED_BASE)) {
1436 O << ", force_unnormalized_coords = 1";
1437 }
1438 O << " }";
1439 }
1440
1441 O << ";\n";
1442 return;
1443 }
1444
1445 if (GVar->hasPrivateLinkage()) {
1446 if (GVar->getName().starts_with("unrollpragma"))
1447 return;
1448
1449 // FIXME - need better way (e.g. Metadata) to avoid generating this global
1450 if (GVar->getName().starts_with("filename"))
1451 return;
1452 if (GVar->use_empty())
1453 return;
1454 }
1455
1456 const Function *DemotedFunc = nullptr;
1457 if (!ProcessDemoted && canDemoteGlobalVar(GVar, DemotedFunc)) {
1458 O << "// " << GVar->getName() << " has been demoted\n";
1459 localDecls[DemotedFunc].push_back(GVar);
1460 return;
1461 }
1462
1463 emitPTXGlobalVariableDefinition(GVar, O, STI, /*EmitInitializer=*/true);
1464 O << ";\n";
1465}
1466
1467template <typename T>
1468void NVPTXAsmPrinter::printFunctionDirectives(const T &V,
1469 raw_ostream &O) const {
1470 const NVPTXSubtarget &STI =
1471 *static_cast<const NVPTXTargetMachine &>(TM).getSubtargetImpl();
1472
1473 if (STI.hasNoReturn() && V.doesNotReturn() &&
1474 V.getFunctionType()->getReturnType()->isVoidTy())
1475 O << ".noreturn\n";
1476
1477 // Don't emit abi_preserve directives on targets where they are
1478 // unsupported.
1479 if (!STI.hasABIPreserve())
1480 return;
1481
1482 const ABIPreserveInfo ABI = getABIPreserve(V.getAttributes());
1483 if (ABI.Preserve)
1484 O << ".abi_preserve " << *ABI.Preserve << "\n";
1485 if (ABI.PreserveControl)
1486 O << ".abi_preserve_control " << *ABI.PreserveControl << "\n";
1487}
1488
1489void NVPTXAsmPrinter::emitPTXGlobalVariableDefinition(
1490 const GlobalVariable *GVar, raw_ostream &O, const NVPTXSubtarget &STI,
1491 bool EmitInitializer) {
1492 const DataLayout &DL = getDataLayout();
1493
1494 Type *ETy = GVar->getValueType();
1495
1496 emitPTXAddressSpace(GVar->getAddressSpace(), O);
1497
1498 if (isManaged(*GVar)) {
1499 if (!STI.hasFeature(NVPTX::PTX40) || !STI.hasFeature(NVPTX::SM30))
1501 ".attribute(.managed) requires PTX version >= 4.0 and sm_30");
1502 O << " .attribute(.managed)";
1503 }
1504
1505 O << " .align "
1506 << GVar->getAlign().value_or(DL.getPrefTypeAlign(ETy)).value();
1507
1508 const Constant *Initializer = nullptr;
1509 if (GVar->hasInitializer()) {
1510 const Constant *Init = GVar->getInitializer();
1511 if (!Init->isNullValue() && !isa<UndefValue>(Init)) {
1512 if (GVar->getAddressSpace() != ADDRESS_SPACE_GLOBAL &&
1514 report_fatal_error("initial value of '" + GVar->getName() +
1515 "' is not allowed in addrspace(" +
1516 Twine(GVar->getAddressSpace()) + ")");
1517 Initializer = Init;
1518 }
1519 }
1520
1521 if (ETy->isPointerTy() || ((ETy->isIntegerTy() || ETy->isFloatingPointTy()) &&
1522 ETy->getScalarSizeInBits() <= 64)) {
1523 O << " ." << getPTXFundamentalTypeStr(ETy) << " ";
1524 getSymbol(GVar)->print(O, MAI);
1525
1526 if (EmitInitializer && Initializer) {
1527 O << " = ";
1528 printScalarConstant(Initializer, O);
1529 }
1530 return;
1531 }
1532
1533 // Although PTX has direct support for struct type and array type and LLVM IR
1534 // is very similar to PTX, the LLVM CodeGen does not support for targets that
1535 // support these high level field accesses. Structs, arrays and vectors are
1536 // lowered into arrays of bytes.
1537 assert((ETy->isIntegerTy() || ETy->isFP128Ty() || ETy->isAggregateType() ||
1538 isa<FixedVectorType>(ETy)) &&
1539 "type not supported yet");
1540
1541 const uint64_t ElementSize = DL.getTypeStoreSize(ETy);
1542
1543 if (!Initializer) {
1544 O << " .b8 ";
1545 getSymbol(GVar)->print(O, MAI);
1546 if (ElementSize)
1547 O << "[" << ElementSize << "]";
1548 else if (!EmitInitializer)
1549 O << "[]";
1550 return;
1551 }
1552
1553 AggBuffer aggBuffer(ElementSize, *this);
1554 bufferAggregateConstant(Initializer, &aggBuffer);
1555 if (aggBuffer.numSymbols()) {
1556 const unsigned int ptrSize = MAI.getCodePointerSize();
1557 if (ElementSize % ptrSize || !aggBuffer.allSymbolsAligned(ptrSize)) {
1558 // Print in bytes and use the mask() operator for pointers.
1559 if (!STI.hasMaskOperator())
1560 report_fatal_error("initialized packed aggregate with pointers '" +
1561 GVar->getName() +
1562 "' requires at least PTX ISA version 7.1");
1563 O << " .u8 ";
1564 getSymbol(GVar)->print(O, MAI);
1565 O << "[" << ElementSize << "]";
1566 if (EmitInitializer) {
1567 O << " = {";
1568 aggBuffer.printBytes(O);
1569 O << "}";
1570 }
1571 } else {
1572 O << " .u" << ptrSize * 8 << " ";
1573 getSymbol(GVar)->print(O, MAI);
1574 O << "[" << ElementSize / ptrSize << "]";
1575 if (EmitInitializer) {
1576 O << " = {";
1577 aggBuffer.printWords(O);
1578 O << "}";
1579 }
1580 }
1581 } else {
1582 O << " .b8 ";
1583 getSymbol(GVar)->print(O, MAI);
1584 O << "[" << ElementSize << "]";
1585 if (EmitInitializer) {
1586 O << " = {";
1587 aggBuffer.printBytes(O);
1588 O << "}";
1589 }
1590 }
1591}
1592
1593void NVPTXAsmPrinter::AggBuffer::printSymbol(unsigned nSym, raw_ostream &os) {
1594 const Value *v = Symbols[nSym];
1595 const Value *v0 = SymbolsBeforeStripping[nSym];
1596 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(v)) {
1597 MCSymbol *Name = AP.getSymbol(GVar);
1599 // Is v0 a generic pointer?
1600 bool isGenericPointer = PTy && PTy->getAddressSpace() == 0;
1601 if (EmitGeneric && isGenericPointer && !isa<Function>(v)) {
1602 os << "generic(";
1603 Name->print(os, AP.MAI);
1604 os << ")";
1605 } else {
1606 Name->print(os, AP.MAI);
1607 }
1608 } else if (const ConstantExpr *CExpr = dyn_cast<ConstantExpr>(v0)) {
1609 const MCExpr *Expr = AP.lowerConstantForGV(CExpr, false);
1610 AP.printMCExpr(*Expr, os);
1611 } else
1612 llvm_unreachable("symbol type unknown");
1613}
1614
1615void NVPTXAsmPrinter::AggBuffer::printBytes(raw_ostream &os) {
1616 unsigned int ptrSize = AP.MAI.getCodePointerSize();
1617 // Do not emit trailing zero initializers. They will be zero-initialized by
1618 // ptxas. This saves on both space requirements for the generated PTX and on
1619 // memory use by ptxas. (See:
1620 // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#global-state-space)
1621 unsigned int InitializerCount = Size;
1622 // TODO: symbols make this harder, but it would still be good to trim trailing
1623 // 0s for aggs with symbols as well.
1624 if (numSymbols() == 0)
1625 while (InitializerCount >= 1 && !buffer[InitializerCount - 1])
1626 InitializerCount--;
1627
1628 symbolPosInBuffer.push_back(InitializerCount);
1629 unsigned int nSym = 0;
1630 unsigned int nextSymbolPos = symbolPosInBuffer[nSym];
1631 for (unsigned int pos = 0; pos < InitializerCount;) {
1632 if (pos)
1633 os << ", ";
1634 if (pos != nextSymbolPos) {
1635 os << (unsigned int)buffer[pos];
1636 ++pos;
1637 continue;
1638 }
1639 // Generate a per-byte mask() operator for the symbol, which looks like:
1640 // .global .u8 addr[] = {0xFF(foo), 0xFF00(foo), 0xFF0000(foo), ...};
1641 // See https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#initializers
1642 std::string symText;
1643 llvm::raw_string_ostream oss(symText);
1644 printSymbol(nSym, oss);
1645 for (unsigned i = 0; i < ptrSize; ++i) {
1646 if (i)
1647 os << ", ";
1648 llvm::write_hex(os, 0xFFULL << i * 8, HexPrintStyle::PrefixUpper);
1649 os << "(" << symText << ")";
1650 }
1651 pos += ptrSize;
1652 nextSymbolPos = symbolPosInBuffer[++nSym];
1653 assert(nextSymbolPos >= pos);
1654 }
1655}
1656
1657void NVPTXAsmPrinter::AggBuffer::printWords(raw_ostream &os) {
1658 unsigned int ptrSize = AP.MAI.getCodePointerSize();
1659 symbolPosInBuffer.push_back(Size);
1660 unsigned int nSym = 0;
1661 unsigned int nextSymbolPos = symbolPosInBuffer[nSym];
1662 assert(nextSymbolPos % ptrSize == 0);
1663 for (unsigned int pos = 0; pos < Size; pos += ptrSize) {
1664 if (pos)
1665 os << ", ";
1666 if (pos == nextSymbolPos) {
1667 printSymbol(nSym, os);
1668 nextSymbolPos = symbolPosInBuffer[++nSym];
1669 assert(nextSymbolPos % ptrSize == 0);
1670 assert(nextSymbolPos >= pos + ptrSize);
1671 } else if (ptrSize == 4)
1672 os << support::endian::read32le(&buffer[pos]);
1673 else
1674 os << support::endian::read64le(&buffer[pos]);
1675 }
1676}
1677
1678void NVPTXAsmPrinter::emitDemotedVars(const Function *F, raw_ostream &O) {
1679 auto It = localDecls.find(F);
1680 if (It == localDecls.end())
1681 return;
1682
1683 ArrayRef<const GlobalVariable *> GVars = It->second;
1684
1685 const NVPTXTargetMachine &NTM = static_cast<const NVPTXTargetMachine &>(TM);
1686 const NVPTXSubtarget &STI = *NTM.getSubtargetImpl();
1687
1688 for (const GlobalVariable *GV : GVars) {
1689 O << "\t// demoted variable\n\t";
1690 printModuleLevelGV(GV, O, /*processDemoted=*/true, STI);
1691 }
1692}
1693
1694/// The PTX state space directive for \p AddressSpace, or an empty string if it
1695/// does not name one, as is the case for the generic address space.
1697 switch (AddressSpace) {
1699 return ".local";
1701 return ".global";
1703 return ".const";
1705 return ".shared";
1706 default:
1707 return {};
1708 }
1709}
1710
1711/// The PTX opaque type directive for an image or sampler handle, or an empty
1712/// string for PTXOpaqueType::None.
1714 switch (OpaqueType) {
1716 return ".samplerref";
1718 return ".texref";
1720 return ".surfref";
1722 return {};
1723 }
1724 llvm_unreachable("unexpected PTXOpaqueType");
1725}
1726
1727void NVPTXAsmPrinter::emitPTXAddressSpace(unsigned int AddressSpace,
1728 raw_ostream &O) const {
1729 const StringRef Name = getPTXAddressSpaceName(AddressSpace);
1730 if (Name.empty())
1731 report_fatal_error("Bad address space found while emitting PTX: " +
1732 llvm::Twine(AddressSpace));
1733 O << Name;
1734}
1735
1736std::string NVPTXAsmPrinter::getPTXFundamentalTypeStr(Type *Ty) const {
1737 switch (Ty->getTypeID()) {
1738 case Type::IntegerTyID:
1739 case Type::PointerTyID: {
1740 const uint64_t NumBits = getDataLayout().getTypeStoreSizeInBits(Ty);
1741 assert(NumBits <= 64 && "type too large");
1742 return "u" + utostr(promoteScalarKernelArgumentSize(NumBits));
1743 }
1744 case Type::BFloatTyID:
1745 case Type::HalfTyID:
1746 case Type::FloatTyID:
1747 case Type::DoubleTyID:
1748 return "b" + utostr(Ty->getScalarSizeInBits());
1749 default:
1750 break;
1751 }
1752 llvm_unreachable("unexpected type");
1753}
1754
1755void NVPTXAsmPrinter::emitFunctionParamList(const Function *F, raw_ostream &O) {
1756 const DataLayout &DL = getDataLayout();
1757 const NVPTXSubtarget &STI = TM.getSubtarget<NVPTXSubtarget>(*F);
1758 const auto *TLI = cast<NVPTXTargetLowering>(STI.getTargetLowering());
1759 const NVPTXMachineFunctionInfo *MFI =
1760 MF ? MF->getInfo<NVPTXMachineFunctionInfo>() : nullptr;
1761
1762 const bool IsKernelFunc = isKernelFunction(*F);
1763
1764 // Zero-sized arguments (e.g. empty structs) do not produce a parameter.
1765 // Number the emitted parameters contiguously, skipping the zero-sized ones,
1766 // so that the names match those used in LowerFormalArguments and the
1767 // contiguous numbering used by callers (see LowerCall).
1768 const auto NonEmptyArgs =
1769 make_filter_range(F->args(), [](const Argument &Arg) {
1770 return !Arg.getType()->isEmptyTy();
1771 });
1772
1773 if (NonEmptyArgs.empty() && !F->isVarArg()) {
1774 O << "()";
1775 return;
1776 }
1777
1778 O << "(\n";
1779
1780 auto MakeParam = [&](const auto &IndexedArg) {
1781 const auto &[ParamIndex, Arg] = IndexedArg;
1782 Type *Ty = Arg.getType();
1783 MCSymbol *const ParamSym = TLI->getParamSymbol(OutContext, F, ParamIndex);
1784
1785 O << "\t";
1786
1787 // A byval param is passed as a copy of the pointee and an aggregate is
1788 // passed as a blob of bytes; both are declared as a byte array.
1789 const bool IsByVal = Arg.hasByValAttr();
1790 const bool AsArray = IsByVal || shouldPassAsArray(Ty);
1791
1792 // Kernels declare image/sampler handles and the address space of a
1793 // pointee. Both of those are scalar handles, so a byte-array param is
1794 // neither.
1795 if (IsKernelFunc && !AsArray) {
1796 const StringRef OpaqueType = getPTXOpaqueTypeName(getPTXOpaqueType(Arg));
1797 if (!OpaqueType.empty()) {
1798 O << ".param ";
1799 if (!MFI || !MFI->checkImageHandleSymbol(ParamSym))
1800 O << ".u64 .ptr ";
1801
1802 O << OpaqueType << " " << *ParamSym;
1803 return;
1804 }
1805
1806 if (auto *PTy = dyn_cast<PointerType>(Ty)) {
1807 const unsigned AS = PTy->getAddressSpace();
1808 O << ".param .u" << DL.getPointerSizeInBits(AS) << " .ptr";
1809
1810 const StringRef Space = getPTXAddressSpaceName(AS);
1811 if (!Space.empty())
1812 O << " " << Space;
1813
1814 O << " .align " << Arg.getParamAlign().valueOrOne().value() << " "
1815 << *ParamSym;
1816 return;
1817 }
1818 }
1819
1820 printParam(F, IsByVal ? Arg.getParamByValType() : Ty,
1821 Arg.getArgNo() + AttributeList::FirstArgIndex, IsByVal,
1822 IsKernelFunc, ParamSym->getName(), DL, O);
1823 };
1824
1825 interleave(enumerate(NonEmptyArgs), O, MakeParam, ",\n");
1826
1827 if (F->isVarArg())
1828 O << (NonEmptyArgs.empty() ? "" : ",\n") << "\t.param .align "
1829 << STI.getMaxRequiredAlignment() << " .b8 "
1830 << *TLI->getParamSymbol(OutContext, F, /* vararg */ -1) << "[]";
1831
1832 O << "\n)";
1833}
1834
1835void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters(
1836 const MachineFunction &MF) {
1837 auto *TS = getTargetStreamer();
1838
1839 // Emit the Fake Stack Object
1840 const MachineFrameInfo &MFI = MF.getFrameInfo();
1841 if (const int64_t NumBytes = MFI.getStackSize()) {
1842 TS->emitLocalDirective(MFI.getMaxAlign(), getFunctionFrameSymbol(),
1843 NumBytes);
1844
1845 // Declare the frame pointers that NVPTXFrameLowering's prologue defines.
1846 const NVPTXRegisterInfo *NRI =
1847 MF.getSubtarget<NVPTXSubtarget>().getRegisterInfo();
1848 for (const Register FrameReg :
1849 {NRI->getFrameRegister(MF), NRI->getFrameLocalRegister(MF)})
1850 TS->emitRegDirective(
1851 NRI->getRegSizeInBits(FrameReg, *MRI).getFixedValue(),
1853 }
1854
1855 // Go through all virtual registers to establish the mapping between the
1856 // global virtual
1857 // register number and the per class virtual register number.
1858 // We use the per class virtual register number in the ptx output.
1859 for (unsigned I : llvm::seq(MRI->getNumVirtRegs())) {
1860 Register VR = Register::index2VirtReg(I);
1861 if (MRI->use_empty(VR) && MRI->def_empty(VR))
1862 continue;
1863 auto &RCRegMap = VRegMapping[MRI->getRegClass(VR)];
1864 RCRegMap[VR] = RCRegMap.size() + 1;
1865 }
1866
1867 // Emit declaration of the virtual registers or 'physical' registers for
1868 // each register class
1869 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
1870 for (const TargetRegisterClass &RC : TRI->regclasses()) {
1871 // Only declare those registers that may be used.
1872 const auto It = VRegMapping.find(&RC);
1873 if (It == VRegMapping.end() || It->second.empty())
1874 continue;
1875
1876 TS->emitRegDirective(
1877 TRI->getRegSizeInBits(RC).getFixedValue(),
1878 NVPTX::getVirtualRegisterPrefix(getVirtualRegisterKind(&RC)),
1879 It->second.size() + 1);
1880 }
1881}
1882
1883/// Translate virtual register numbers in DebugInfo locations to their printed
1884/// encodings, as used by CUDA-GDB.
1885void NVPTXAsmPrinter::encodeDebugInfoRegisterNumbers(
1886 const MachineFunction &MF) {
1887 const NVPTXSubtarget &STI = MF.getSubtarget<NVPTXSubtarget>();
1888 const NVPTXRegisterInfo *NRI = STI.getRegisterInfo();
1889
1890 // Clear the old mapping, and add the new one. This mapping is used after the
1891 // printing of the current function is complete, but before the next function
1892 // is printed.
1893 NRI->clearDebugRegisterMap();
1894
1895 for (const VRegMap &RegMap : make_second_range(VRegMapping))
1896 for (const Register Reg : make_first_range(RegMap))
1897 NRI->addToDebugRegisterMap(Reg, getVirtualRegisterName(Reg));
1898}
1899
1900void NVPTXAsmPrinter::printFPConstant(const ConstantFP *Fp,
1901 raw_ostream &O) const {
1902 if (Fp->getType()->isFloatTy())
1903 O << "0f";
1904 else if (Fp->getType()->isDoubleTy())
1905 O << "0d";
1906 else
1907 llvm_unreachable("unsupported fp type");
1908
1909 const APInt API = Fp->getValueAPF().bitcastToAPInt();
1910 O << format_hex_no_prefix(API.getZExtValue(), API.getBitWidth() / 4,
1911 /*Upper=*/true);
1912}
1913
1914void NVPTXAsmPrinter::printScalarConstant(const Constant *CPV, raw_ostream &O) {
1915 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CPV)) {
1916 O << CI->getValue();
1917 return;
1918 }
1919 if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CPV)) {
1920 const APInt API = CFP->getValueAPF().bitcastToAPInt();
1921 O << "0x"
1922 << format_hex_no_prefix(API.getZExtValue(), API.getBitWidth() / 4,
1923 /*Upper=*/true);
1924 return;
1925 }
1926 if (isa<ConstantPointerNull>(CPV)) {
1927 O << "0";
1928 return;
1929 }
1930 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(CPV)) {
1931 const bool IsNonGenericPointer = GVar->getAddressSpace() != 0;
1932 if (EmitGeneric && !isa<Function>(CPV) && !IsNonGenericPointer) {
1933 O << "generic(";
1934 getSymbol(GVar)->print(O, MAI);
1935 O << ")";
1936 } else {
1937 getSymbol(GVar)->print(O, MAI);
1938 }
1939 return;
1940 }
1941 if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
1942 const MCExpr *E = lowerConstantForGV(cast<Constant>(Cexpr), false);
1943 printMCExpr(*E, O);
1944 return;
1945 }
1946 llvm_unreachable("Not scalar type found in printScalarConstant()");
1947}
1948
1949void NVPTXAsmPrinter::bufferLEByte(const Constant *CPV, int Bytes,
1950 AggBuffer *AggBuffer) {
1951 const DataLayout &DL = getDataLayout();
1952 int AllocSize = DL.getTypeAllocSize(CPV->getType());
1953 if (isa<UndefValue>(CPV) || CPV->isNullValue()) {
1954 // Non-zero Bytes indicates that we need to zero-fill everything. Otherwise,
1955 // only the space allocated by CPV.
1956 AggBuffer->addZeros(Bytes ? Bytes : AllocSize);
1957 return;
1958 }
1959
1960 // Helper for filling AggBuffer with APInts.
1961 auto AddIntToBuffer = [AggBuffer, Bytes](const APInt &Val) {
1962 size_t NumBytes = (Val.getBitWidth() + 7) / 8;
1963 SmallVector<unsigned char, 16> Buf(NumBytes);
1964 // `extractBitsAsZExtValue` does not allow the extraction of bits beyond the
1965 // input's bit width, and i1 arrays may not have a length that is a multuple
1966 // of 8. We handle the last byte separately, so we never request out of
1967 // bounds bits.
1968 for (unsigned I = 0; I < NumBytes - 1; ++I) {
1969 Buf[I] = Val.extractBitsAsZExtValue(8, I * 8);
1970 }
1971 size_t LastBytePosition = (NumBytes - 1) * 8;
1972 size_t LastByteBits = Val.getBitWidth() - LastBytePosition;
1973 Buf[NumBytes - 1] =
1974 Val.extractBitsAsZExtValue(LastByteBits, LastBytePosition);
1975 AggBuffer->addBytes(Buf.data(), NumBytes, Bytes);
1976 };
1977
1978 switch (CPV->getType()->getTypeID()) {
1979 case Type::IntegerTyID:
1980 if (const auto *CI = dyn_cast<ConstantInt>(CPV)) {
1981 AddIntToBuffer(CI->getValue());
1982 break;
1983 }
1984 if (const auto *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
1985 if (const auto *CI =
1987 AddIntToBuffer(CI->getValue());
1988 break;
1989 }
1990 if (Cexpr->getOpcode() == Instruction::PtrToInt) {
1991 Value *V = Cexpr->getOperand(0)->stripPointerCasts();
1992 AggBuffer->addSymbol(V, Cexpr->getOperand(0));
1993 AggBuffer->addZeros(AllocSize);
1994 break;
1995 }
1996 // A symbol-relative integer whose offset is applied outside the
1997 // ptrtoint, e.g. add(ptrtoint(@g), C). It can't fold to a ConstantInt
1998 // because it references a symbol; emit it through lowerConstantForGV, the
1999 // same path scalar symbol-relative integer globals use.
2000 AggBuffer->addSymbol(Cexpr, Cexpr);
2001 AggBuffer->addZeros(AllocSize);
2002 break;
2003 }
2004 llvm_unreachable("unsupported integer const type");
2005 break;
2006
2007 case Type::HalfTyID:
2008 case Type::BFloatTyID:
2009 case Type::FloatTyID:
2010 case Type::DoubleTyID:
2011 case Type::FP128TyID:
2012 AddIntToBuffer(cast<ConstantFP>(CPV)->getValueAPF().bitcastToAPInt());
2013 break;
2014
2015 case Type::PointerTyID: {
2016 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(CPV)) {
2017 AggBuffer->addSymbol(GVar, GVar);
2018 } else if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
2019 const Value *v = Cexpr->stripPointerCasts();
2020 AggBuffer->addSymbol(v, Cexpr);
2021 }
2022 AggBuffer->addZeros(AllocSize);
2023 break;
2024 }
2025
2026 case Type::ArrayTyID:
2027 case Type::FixedVectorTyID:
2028 case Type::StructTyID: {
2030 // bufferAggregateConstant doesn't emit tail-padding, i.e. it writes
2031 // `store_size` bytes, not `alloc_size` bytes. Do it ourselves here.
2032 unsigned StartPos = AggBuffer->getCurpos();
2033 bufferAggregateConstant(CPV, AggBuffer);
2034 unsigned Written = AggBuffer->getCurpos() - StartPos;
2035 unsigned SlotSize = std::max<int>(Bytes, AllocSize);
2036 if (SlotSize > Written)
2037 AggBuffer->addZeros(SlotSize - Written);
2038 } else if (isa<ConstantAggregateZero>(CPV))
2039 AggBuffer->addZeros(Bytes);
2040 else
2041 llvm_unreachable("Unexpected Constant type");
2042 break;
2043 }
2044
2045 default:
2046 llvm_unreachable("unsupported type");
2047 }
2048}
2049
2050void NVPTXAsmPrinter::bufferAggregateConstant(const Constant *CPV,
2051 AggBuffer *aggBuffer) {
2052 const DataLayout &DL = getDataLayout();
2053
2054 auto ExtendBuffer = [](APInt Val, AggBuffer *Buffer) {
2055 unsigned NumBytes = divideCeil(Val.getBitWidth(), 8);
2056 for (unsigned I : llvm::seq(NumBytes)) {
2057 unsigned NumBits = std::min(8u, Val.getBitWidth() - I * 8);
2058 Buffer->addByte(Val.extractBitsAsZExtValue(NumBits, I * 8));
2059 }
2060 };
2061
2062 // Integer or floating point vector splats.
2064 if (auto *VTy = dyn_cast<FixedVectorType>(CPV->getType())) {
2065 for (unsigned I : llvm::seq(VTy->getNumElements()))
2066 bufferLEByte(CPV->getAggregateElement(I), 0, aggBuffer);
2067 return;
2068 }
2069 }
2070
2071 // Integers of arbitrary width
2072 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CPV)) {
2073 assert(CI->getType()->isIntegerTy() && "Expected integer constant!");
2074 ExtendBuffer(CI->getValue(), aggBuffer);
2075 return;
2076 }
2077
2078 // f128
2079 if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CPV)) {
2080 assert(CFP->getType()->isFloatingPointTy() && "Expected fp constant!");
2081 if (CFP->getType()->isFP128Ty()) {
2082 ExtendBuffer(CFP->getValueAPF().bitcastToAPInt(), aggBuffer);
2083 return;
2084 }
2085 }
2086
2087 // Buffer arrays one element at a time.
2088 if (isa<ConstantArray>(CPV)) {
2089 for (const auto &Op : CPV->operands())
2090 bufferLEByte(cast<Constant>(Op), 0, aggBuffer);
2091 return;
2092 }
2093
2094 // Constant vectors
2095 if (const auto *CVec = dyn_cast<ConstantVector>(CPV)) {
2096 bufferAggregateConstVec(CVec, aggBuffer);
2097 return;
2098 }
2099
2100 if (const auto *CDS = dyn_cast<ConstantDataSequential>(CPV)) {
2101 for (unsigned I : llvm::seq(CDS->getNumElements()))
2102 bufferLEByte(cast<Constant>(CDS->getElementAsConstant(I)), 0, aggBuffer);
2103 return;
2104 }
2105
2106 if (isa<ConstantStruct>(CPV)) {
2107 if (CPV->getNumOperands()) {
2108 StructType *ST = cast<StructType>(CPV->getType());
2109 for (unsigned I : llvm::seq(CPV->getNumOperands())) {
2110 int EndOffset = (I + 1 == CPV->getNumOperands())
2111 ? DL.getStructLayout(ST)->getElementOffset(0) +
2112 DL.getTypeAllocSize(ST)
2113 : DL.getStructLayout(ST)->getElementOffset(I + 1);
2114 int Bytes = EndOffset - DL.getStructLayout(ST)->getElementOffset(I);
2115 bufferLEByte(cast<Constant>(CPV->getOperand(I)), Bytes, aggBuffer);
2116 }
2117 }
2118 return;
2119 }
2120 llvm_unreachable("unsupported constant type in printAggregateConstant()");
2121}
2122
2123void NVPTXAsmPrinter::bufferAggregateConstVec(const ConstantVector *CV,
2124 AggBuffer *aggBuffer) {
2125 unsigned NumElems = CV->getType()->getNumElements();
2126 const unsigned BuffSize = aggBuffer->getBufferSize();
2127
2128 // Buffer one element at a time if we have allocated enough buffer space.
2129 if (BuffSize >= NumElems) {
2130 for (const auto &Op : CV->operands())
2131 bufferLEByte(cast<Constant>(Op), 0, aggBuffer);
2132 return;
2133 }
2134
2135 // Sub-byte datatypes will have more elements than bytes allocated for the
2136 // buffer. Merge consecutive elements to form a full byte. We expect that 8 %
2137 // sub-byte-elem-size should be 0 and current expected usage is for i4 (for
2138 // e2m1-fp4 types).
2139 Type *ElemTy = CV->getType()->getElementType();
2140 assert(ElemTy->isIntegerTy() && "Expected integer data type.");
2141 unsigned ElemTySize = ElemTy->getPrimitiveSizeInBits();
2142 assert(ElemTySize < 8 && "Expected sub-byte data type.");
2143 assert(8 % ElemTySize == 0 && "Element type size must evenly divide a byte.");
2144 // Number of elements to merge to form a full byte.
2145 unsigned NumElemsPerByte = 8 / ElemTySize;
2146 unsigned NumCompleteBytes = NumElems / NumElemsPerByte;
2147 unsigned NumTailElems = NumElems % NumElemsPerByte;
2148
2149 // Helper lambda to constant-fold sub-vector of sub-byte type elements into
2150 // i8. Start and end indices of the sub-vector is provided, along with number
2151 // of padding zeros if required.
2152 auto ConvertSubCVtoInt8 = [this, &ElemTy](const ConstantVector *CV,
2153 unsigned Start, unsigned End,
2154 unsigned NumPaddingZeros = 0) {
2155 // Collect elements to create sub-vector.
2156 SmallVector<Constant *, 8> SubCVElems;
2157 for (unsigned I : llvm::seq(Start, End))
2158 SubCVElems.push_back(CV->getAggregateElement(I));
2159
2160 // Optionally pad with zeros.
2161 if (NumPaddingZeros)
2162 SubCVElems.append(NumPaddingZeros, ConstantInt::getNullValue(ElemTy));
2163
2164 auto SubCV = ConstantVector::get(SubCVElems);
2165 Type *Int8Ty = IntegerType::get(SubCV->getContext(), 8);
2166
2167 // Merge elements of the sub-vector using ConstantFolding.
2168 ConstantInt *MergedElem =
2170 ConstantExpr::getBitCast(const_cast<Constant *>(SubCV), Int8Ty),
2171 getDataLayout()));
2172
2173 if (!MergedElem)
2175 "Cannot lower vector global with unusual element type");
2176
2177 return MergedElem;
2178 };
2179
2180 // Iterate through elements of vector one chunk at a time and buffer that
2181 // chunk.
2182 for (unsigned ByteIdx : llvm::seq(NumCompleteBytes))
2183 bufferLEByte(ConvertSubCVtoInt8(CV, ByteIdx * NumElemsPerByte,
2184 (ByteIdx + 1) * NumElemsPerByte),
2185 0, aggBuffer);
2186
2187 // For unevenly sized vectors add tail padding zeros.
2188 if (NumTailElems > 0)
2189 bufferLEByte(ConvertSubCVtoInt8(CV, NumElems - NumTailElems, NumElems,
2190 NumElemsPerByte - NumTailElems),
2191 0, aggBuffer);
2192}
2193
2194/// lowerConstantForGV - Return an MCExpr for the given Constant. This is mostly
2195/// a copy from AsmPrinter::lowerConstant, except customized to only handle
2196/// expressions that are representable in PTX and create
2197/// NVPTXGenericMCSymbolRefExpr nodes for addrspacecast instructions.
2198const MCExpr *
2199NVPTXAsmPrinter::lowerConstantForGV(const Constant *CV,
2200 bool ProcessingGeneric) const {
2201 MCContext &Ctx = OutContext;
2202
2203 if (CV->isNullValue() || isa<UndefValue>(CV))
2204 return MCConstantExpr::create(0, Ctx);
2205
2206 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV))
2207 return MCConstantExpr::create(CI->getZExtValue(), Ctx);
2208
2209 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
2210 const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx);
2211 if (ProcessingGeneric)
2212 return NVPTXGenericMCSymbolRefExpr::create(Expr, Ctx);
2213 return Expr;
2214 }
2215
2216 const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV);
2217 if (!CE) {
2218 llvm_unreachable("Unknown constant value to lower!");
2219 }
2220
2221 switch (CE->getOpcode()) {
2222 default:
2223 break; // Error
2224
2225 case Instruction::AddrSpaceCast: {
2226 // Strip the addrspacecast and pass along the operand
2227 PointerType *DstTy = cast<PointerType>(CE->getType());
2228 if (DstTy->getAddressSpace() == 0)
2229 return lowerConstantForGV(cast<const Constant>(CE->getOperand(0)), true);
2230
2231 break; // Error
2232 }
2233
2234 case Instruction::GetElementPtr: {
2235 const DataLayout &DL = getDataLayout();
2236
2237 // Generate a symbolic expression for the byte address
2238 APInt OffsetAI(DL.getPointerTypeSizeInBits(CE->getType()), 0);
2239 cast<GEPOperator>(CE)->accumulateConstantOffset(DL, OffsetAI);
2240
2241 const MCExpr *Base = lowerConstantForGV(CE->getOperand(0),
2242 ProcessingGeneric);
2243 if (!OffsetAI)
2244 return Base;
2245
2246 int64_t Offset = OffsetAI.getSExtValue();
2248 Ctx);
2249 }
2250
2251 case Instruction::Trunc:
2252 // We emit the value and depend on the assembler to truncate the generated
2253 // expression properly. This is important for differences between
2254 // blockaddress labels. Since the two labels are in the same function, it
2255 // is reasonable to treat their delta as a 32-bit value.
2256 [[fallthrough]];
2257 case Instruction::BitCast:
2258 return lowerConstantForGV(CE->getOperand(0), ProcessingGeneric);
2259
2260 case Instruction::IntToPtr: {
2261 const DataLayout &DL = getDataLayout();
2262
2263 // Handle casts to pointers by changing them into casts to the appropriate
2264 // integer type. This promotes constant folding and simplifies this code.
2265 Constant *Op = CE->getOperand(0);
2266 Op = ConstantFoldIntegerCast(Op, DL.getIntPtrType(CV->getType()),
2267 /*IsSigned*/ false, DL);
2268 if (Op)
2269 return lowerConstantForGV(Op, ProcessingGeneric);
2270
2271 break; // Error
2272 }
2273
2274 case Instruction::PtrToInt: {
2275 const DataLayout &DL = getDataLayout();
2276
2277 // Support only foldable casts to/from pointers that can be eliminated by
2278 // changing the pointer to the appropriately sized integer type.
2279 Constant *Op = CE->getOperand(0);
2280 Type *Ty = CE->getType();
2281
2282 const MCExpr *OpExpr = lowerConstantForGV(Op, ProcessingGeneric);
2283
2284 // We can emit the pointer value into this slot if the slot is an
2285 // integer slot equal to the size of the pointer.
2286 if (DL.getTypeAllocSize(Ty) == DL.getTypeAllocSize(Op->getType()))
2287 return OpExpr;
2288
2289 // Otherwise the pointer is smaller than the resultant integer, mask off
2290 // the high bits so we are sure to get a proper truncation if the input is
2291 // a constant expr.
2292 unsigned InBits = DL.getTypeAllocSizeInBits(Op->getType());
2293 const MCExpr *MaskExpr = MCConstantExpr::create(~0ULL >> (64-InBits), Ctx);
2294 return MCBinaryExpr::createAnd(OpExpr, MaskExpr, Ctx);
2295 }
2296
2297 // The MC library also has a right-shift operator, but it isn't consistently
2298 // signed or unsigned between different targets.
2299 case Instruction::Add: {
2300 const MCExpr *LHS = lowerConstantForGV(CE->getOperand(0), ProcessingGeneric);
2301 const MCExpr *RHS = lowerConstantForGV(CE->getOperand(1), ProcessingGeneric);
2302 switch (CE->getOpcode()) {
2303 default: llvm_unreachable("Unknown binary operator constant cast expr");
2304 case Instruction::Add: return MCBinaryExpr::createAdd(LHS, RHS, Ctx);
2305 }
2306 }
2307 }
2308
2309 // If the code isn't optimized, there may be outstanding folding
2310 // opportunities. Attempt to fold the expression using DataLayout as a
2311 // last resort before giving up.
2312 Constant *C = ConstantFoldConstant(CE, getDataLayout());
2313 if (C != CE)
2314 return lowerConstantForGV(C, ProcessingGeneric);
2315
2316 // Otherwise report the problem to the user.
2317 std::string S;
2318 raw_string_ostream OS(S);
2319 OS << "Unsupported expression in static initializer: ";
2320 CE->printAsOperand(OS, /*PrintType=*/false,
2321 !MF ? nullptr : MF->getFunction().getParent());
2322 report_fatal_error(Twine(OS.str()));
2323}
2324
2325void NVPTXAsmPrinter::printMCExpr(const MCExpr &Expr, raw_ostream &OS) const {
2326 OutContext.getAsmInfo().printExpr(OS, Expr);
2327}
2328
2329/// PrintAsmOperand - Print out an operand for an inline asm expression.
2330///
2331bool NVPTXAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
2332 const char *ExtraCode, raw_ostream &O) {
2333 if (ExtraCode && ExtraCode[0]) {
2334 if (ExtraCode[1] != 0)
2335 return true; // Unknown modifier.
2336
2337 switch (ExtraCode[0]) {
2338 default:
2339 // See if this is a generic print operand
2340 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
2341 case 'r':
2342 break;
2343 }
2344 }
2345
2346 printOperand(MI, OpNo, O);
2347
2348 return false;
2349}
2350
2351bool NVPTXAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
2352 unsigned OpNo,
2353 const char *ExtraCode,
2354 raw_ostream &O) {
2355 if (ExtraCode && ExtraCode[0])
2356 return true; // Unknown modifier
2357
2358 O << '[';
2359 printMemOperand(MI, OpNo, O);
2360 O << ']';
2361
2362 return false;
2363}
2364
2365void NVPTXAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
2366 raw_ostream &O) {
2367 const MachineOperand &MO = MI->getOperand(OpNum);
2368 switch (MO.getType()) {
2370 if (MO.getReg().isPhysical()) {
2371 if (MO.getReg() == NVPTX::VRDepot)
2372 getFunctionFrameSymbol()->print(O, MAI);
2373 else
2375 } else {
2376 O << getVirtualRegisterName(MO.getReg());
2377 }
2378 break;
2379
2381 O << MO.getImm();
2382 break;
2383
2385 printFPConstant(MO.getFPImm(), O);
2386 break;
2387
2389 PrintSymbolOperand(MO, O);
2390 break;
2391
2393 MO.getMCSymbol()->print(O, MAI);
2394 break;
2395
2397 MO.getMBB()->getSymbol()->print(O, MAI);
2398 break;
2399
2400 default:
2401 llvm_unreachable("Operand type not supported.");
2402 }
2403}
2404
2405void NVPTXAsmPrinter::printMemOperand(const MachineInstr *MI, unsigned OpNum,
2406 raw_ostream &O, const char *Modifier) {
2407 printOperand(MI, OpNum, O);
2408
2409 if (Modifier && strcmp(Modifier, "add") == 0) {
2410 O << ", ";
2411 printOperand(MI, OpNum + 1, O);
2412 } else {
2413 if (MI->getOperand(OpNum + 1).isImm() &&
2414 MI->getOperand(OpNum + 1).getImm() == 0)
2415 return; // don't print ',0' or '+0'
2416 O << "+";
2417 printOperand(MI, OpNum + 1, O);
2418 }
2419}
2420
2421/// Returns true if \p Line begins with an alphabetic character or underscore,
2422/// indicating it is a PTX instruction that should receive a .loc directive.
2423static bool isPTXInstruction(StringRef Line) {
2424 StringRef Trimmed = Line.ltrim();
2425 return !Trimmed.empty() &&
2426 (std::isalpha(static_cast<unsigned char>(Trimmed[0])) ||
2427 Trimmed[0] == '_');
2428}
2429
2430/// Returns the DILocation for an inline asm MachineInstr if debug line info
2431/// should be emitted, or nullptr otherwise.
2433 if (!MI || !MI->getDebugLoc())
2434 return nullptr;
2435 const DISubprogram *SP = MI->getMF()->getFunction().getSubprogram();
2436 if (!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
2437 return nullptr;
2438 const DILocation *DL = MI->getDebugLoc();
2439 if (!DL->getFile() || !DL->getLine() || DL->isImplicitCode())
2440 return nullptr;
2441 return DL;
2442}
2443
2444namespace {
2445struct InlineAsmInliningContext {
2446 MCSymbol *FuncNameSym = nullptr;
2447 unsigned FileIA = 0;
2448 unsigned LineIA = 0;
2449 unsigned ColIA = 0;
2450
2451 bool hasInlinedAt() const { return FuncNameSym != nullptr; }
2452};
2453} // namespace
2454
2455/// Resolves the enhanced-lineinfo inlining context for an inline asm debug
2456/// location. Returns a default (empty) context if inlining info is unavailable.
2457static InlineAsmInliningContext
2460 unsigned CUID) {
2461 InlineAsmInliningContext Ctx;
2462 const DILocation *InlinedAt = DL->getInlinedAt();
2463 if (!InlinedAt || !InlinedAt->getFile() || !NVDD ||
2464 !NVDD->isEnhancedLineinfo(MF))
2465 return Ctx;
2466 const auto *SubProg = getDISubprogram(DL->getScope());
2467 if (!SubProg)
2468 return Ctx;
2469 Ctx.FuncNameSym = NVDD->getOrCreateFuncNameSymbol(SubProg->getLinkageName());
2470 Ctx.FileIA = Streamer.emitDwarfFileDirective(
2471 0, InlinedAt->getFile()->getDirectory(),
2472 InlinedAt->getFile()->getFilename(), std::nullopt, std::nullopt, CUID);
2473 Ctx.LineIA = InlinedAt->getLine();
2474 Ctx.ColIA = InlinedAt->getColumn();
2475 return Ctx;
2476}
2477
2478void NVPTXAsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
2479 const MCTargetOptions &MCOptions,
2480 const MDNode *LocMDNode,
2481 InlineAsm::AsmDialect Dialect,
2482 const MachineInstr *MI) {
2483 assert(!Str.empty() && "Can't emit empty inline asm block");
2484 if (Str.back() == 0)
2485 Str = Str.substr(0, Str.size() - 1);
2486
2487 auto emitAsmStr = [&](StringRef AsmStr) {
2488 emitInlineAsmStart();
2489 OutStreamer->emitRawText(AsmStr);
2490 emitInlineAsmEnd(STI, nullptr, MI);
2491 };
2492
2493 const DILocation *DL = getInlineAsmDebugLoc(MI);
2494 if (!DL) {
2495 emitAsmStr(Str);
2496 return;
2497 }
2498
2499 const DIFile *File = DL->getFile();
2500 unsigned Line = DL->getLine();
2501 const unsigned Column = DL->getColumn();
2502 const unsigned CUID = OutStreamer->getContext().getDwarfCompileUnitID();
2503 const unsigned FileNumber = OutStreamer->emitDwarfFileDirective(
2504 0, File->getDirectory(), File->getFilename(), std::nullopt, std::nullopt,
2505 CUID);
2506
2507 auto *NVDD = static_cast<NVPTXDwarfDebug *>(getDwarfDebug());
2508 InlineAsmInliningContext InlineCtx =
2509 getInlineAsmInliningContext(DL, *MI->getMF(), NVDD, *OutStreamer, CUID);
2510
2511 SmallVector<StringRef, 16> Lines;
2512 Str.split(Lines, '\n');
2513 emitInlineAsmStart();
2514 for (const StringRef &L : Lines) {
2515 StringRef RTrimmed = L.rtrim('\r');
2516 if (isPTXInstruction(L)) {
2517 if (InlineCtx.hasInlinedAt()) {
2518 OutStreamer->emitDwarfLocDirectiveWithInlinedAt(
2519 FileNumber, Line, Column, InlineCtx.FileIA, InlineCtx.LineIA,
2520 InlineCtx.ColIA, InlineCtx.FuncNameSym, DWARF2_FLAG_IS_STMT, 0, 0,
2521 File->getFilename());
2522 } else {
2523 OutStreamer->emitDwarfLocDirective(FileNumber, Line, Column,
2524 DWARF2_FLAG_IS_STMT, 0, 0,
2525 File->getFilename());
2526 }
2527 }
2528 OutStreamer->emitRawText(RTrimmed);
2529 ++Line;
2530 }
2531 emitInlineAsmEnd(STI, nullptr, MI);
2532}
2533
2534char NVPTXAsmPrinter::ID = 0;
2535
2536INITIALIZE_PASS(NVPTXAsmPrinter, "nvptx-asm-printer", "NVPTX Assembly Printer",
2537 false, false)
2538
2539// Force static initialization.
2540extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
2541LLVMInitializeNVPTXAsmPrinter() {
2544}
2545
2548 AsmPrinter &Printer = MAM.getResult<AsmPrinterAnalysis>(M).getPrinter();
2550 Printer.doInitialization(M);
2551 return PreservedAnalyses::all();
2552}
2553
2559 .getCachedResult<AsmPrinterAnalysis>(*MF.getFunction().getParent())
2560 ->getPrinter();
2562 Printer.runOnMachineFunction(MF);
2563 return PreservedAnalyses::all();
2564}
2565
2568 AsmPrinter &Printer = MAM.getResult<AsmPrinterAnalysis>(M).getPrinter();
2570 Printer.doFinalization(M);
2571 return PreservedAnalyses::all();
2572}
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
uint64_t uint64_t
amdgpu next use AMDGPU Next Use Analysis Printer
This file declares a class to represent arbitrary precision floating point values and provide a varie...
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the simple types necessary to represent the attributes associated with functions a...
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:211
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static ManagedStatic< DebugCounterOwner > Owner
static bool hasDebugInfo(const MachineFunction *MF)
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo, uint8_t DefaultVisibility)
Hexagon Common GEP
#define _
static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol, HexagonAsmPrinter &Printer, bool MustExtend)
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define DWARF2_FLAG_IS_STMT
Definition MCDwarf.h:119
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static void emitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText)
#define T
static const DILocation * getInlineAsmDebugLoc(const MachineInstr *MI)
Returns the DILocation for an inline asm MachineInstr if debug line info should be emitted,...
#define DEPOTNAME
static bool hasFullDebugInfo(Module &M)
static bool canDemoteGlobalVar(const GlobalVariable *GV, Function const *&f)
static void printReturnValClause(const OwnerT *Owner, StringRef Name, const DataLayout &DL, raw_ostream &O)
static StringRef getPTXAddressSpaceName(unsigned AddressSpace)
The PTX state space directive for AddressSpace, or an empty string if it does not name one,...
static StringRef getPTXOpaqueTypeName(PTXOpaqueType OpaqueType)
The PTX opaque type directive for an image or sampler handle, or an empty string for PTXOpaqueType::N...
static bool useFuncSeen(const Constant *C, const SmallPtrSetImpl< const Function * > &SeenSet)
static NVPTX::VirtualRegisterKind getVirtualRegisterKind(const TargetRegisterClass *RC)
static void printParam(const OwnerT *Owner, Type *Ty, unsigned AttrIdx, bool IsByVal, bool IsKernel, StringRef Name, const DataLayout &DL, raw_ostream &O)
static bool usedInGlobalVarDef(const Constant *C)
static InlineAsmInliningContext getInlineAsmInliningContext(const DILocation *DL, const MachineFunction &MF, NVPTXDwarfDebug *NVDD, MCStreamer &Streamer, unsigned CUID)
Resolves the enhanced-lineinfo inlining context for an inline asm debug location.
static bool isPTXInstruction(StringRef Line)
Returns true if Line begins with an alphabetic character or underscore, indicating it is a PTX instru...
static bool usedInOneFunc(const User *U, Function const *&OneFunc)
static void emitInitialRawDwarfLocDirective(const MachineFunction &MF, DwarfDebug *DD, MCStreamer &OutStreamer)
Emits initial debug location directive.
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
This file contains some templates that are useful if you are working with the STL at all.
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
static void printMemOperand(raw_ostream &OS, const MachineMemOperand &MMO, const MachineFunction *MF, const Module *M, const MachineFrameInfo *MFI, const TargetInstrInfo *TII, LLVMContext &Ctx)
Provides some synthesis utilities to produce sequences of values.
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
std::unique_ptr< MCStreamer > && Streamer
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
Value * RHS
Value * LHS
@ __CLK_ADDRESS_BASE
@ __CLK_FILTER_BASE
@ __CLK_NORMALIZED_BASE
@ __CLK_NORMALIZED_MASK
@ __CLK_ADDRESS_MASK
@ __CLK_FILTER_MASK
APInt bitcastToAPInt() const
Definition APFloat.h:1475
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const
Definition APInt.cpp:517
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:95
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
bool doFinalization(Module &M) override
Shut down the asmprinter.
virtual void emitBasicBlockStart(const MachineBasicBlock &MBB)
Targets can override this to emit stuff at the start of a basic block.
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition AsmPrinter.h:478
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
bool isByValArgument(unsigned ArgNo) const
Determine whether this argument is passed by value.
Type * getParamByValType(unsigned ArgNo) const
Extract the byval type for a call or parameter.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
static LLVM_ABI Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
Constant Vector Declarations.
Definition Constants.h:674
FixedVectorType * getType() const
Specialize the getType() method to always return a FixedVectorType, which reduces the amount of casti...
Definition Constants.h:697
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
Definition Constant.h:44
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Definition Constant.h:65
LLVM_ABI Constant * getAggregateElement(unsigned Elt) const
For aggregates (struct/array/vector) return the constant that corresponds to the specified element if...
Subprogram description. Uses SubclassData1.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
unsigned size() const
Definition DenseMap.h:717
Collects and handles dwarf debug information.
Definition DwarfDebug.h:352
const MachineInstr * emitInitialLocDirective(const MachineFunction &MF, unsigned CUID)
Emits inital debug location directive.
unsigned getNumElements() const
DISubprogram * getSubprogram() const
Get the attached subprogram.
LLVM_ABI const GlobalObject * getAliaseeObject() const
Definition Globals.cpp:730
StringRef getSection() const
Get the custom section of this global if it has one.
bool hasSection() const
Check if this global has a custom object file section.
bool hasLinkOnceLinkage() const
bool hasExternalLinkage() const
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
bool hasLocalLinkage() const
bool hasPrivateLinkage() const
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
bool hasWeakLinkage() const
bool hasCommonLinkage() const
bool hasAvailableExternallyLinkage() const
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasInitializer() const
Definitions have initializers, declarations don't.
MaybeAlign getAlign() const
Returns the alignment of the given variable.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
bool isLoopHeader(const BlockT *BB) const
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:342
static const MCBinaryExpr * createAnd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:347
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
Definition MCStreamer.h:385
Generic base class for all target subtargets.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:60
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
Metadata node.
Definition Metadata.h:1081
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
iterator_range< pred_iterator > predecessors()
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
Align getMaxAlign() const
Return alignment of this function's frame.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() const
MachineBasicBlock * getMBB() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MCSymbol * getMCSymbol() const
@ MO_Immediate
Immediate operand.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
@ MO_FPImmediate
Floating-point immediate operand.
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.
bool def_empty(Register RegNo) const
def_empty - Return true if there are no instructions defining the specified register (it may be live-...
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
bool use_empty(Register RegNo) const
use_empty - Return true if there are no instructions using the specified register.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
NVPTX-specific DwarfDebug implementation.
bool isEnhancedLineinfo(const MachineFunction &MF) const
Returns true if the enhanced lineinfo mode (with inlined_at) is active for the given MachineFunction.
MCSymbol * getOrCreateFuncNameSymbol(StringRef LinkageName)
Get or create an MCSymbol in .debug_str for a function's linkage name.
static const NVPTXFloatMCExpr * createConstantBFPHalf(const APFloat &Flt, MCContext &Ctx)
Definition NVPTXMCExpr.h:44
static const NVPTXFloatMCExpr * createConstantFPHalf(const APFloat &Flt, MCContext &Ctx)
Definition NVPTXMCExpr.h:49
static const NVPTXFloatMCExpr * createConstantFPSingle(const APFloat &Flt, MCContext &Ctx)
Definition NVPTXMCExpr.h:54
static const NVPTXFloatMCExpr * createConstantFPDouble(const APFloat &Flt, MCContext &Ctx)
Definition NVPTXMCExpr.h:59
static const NVPTXGenericMCSymbolRefExpr * create(const MCSymbolRefExpr *SymExpr, MCContext &Ctx)
static const char * getRegisterName(MCRegister Reg)
bool checkImageHandleSymbol(const MCSymbol *Symbol) const
Check whether Symbol's handle was replaced with an image reference.
Register getFrameLocalRegister(const MachineFunction &MF) const
Register getFrameRegister(const MachineFunction &MF) const override
unsigned getMaxRequiredAlignment() const
StringRef getTargetName() const
bool hasMaskOperator() const
const NVPTXTargetLowering * getTargetLowering() const override
unsigned getPTXVersion() const
bool hasABIPreserve() const
const NVPTXRegisterInfo * getRegisterInfo() const override
NVPTX::DrvInterface getDrvInterface() const
const NVPTXSubtarget * getSubtargetImpl(const Function &) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Implments NVPTX-specific streamer.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Wrapper class representing virtual and physical registers.
Definition Register.h:20
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
Definition Register.h:107
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
constexpr unsigned id() const
Definition Register.h:100
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
typename SuperClass::const_iterator const_iterator
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
iterator begin() const
Definition StringRef.h:114
StringRef ltrim(char Char) const
Return string with consecutive Char characters starting from the the left removed.
Definition StringRef.h:826
iterator end() const
Definition StringRef.h:116
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI bool isEmptyTy() const
Return true if this type is empty, that is, it has no elements or all of its elements are empty.
Definition Type.cpp:170
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition Type.h:155
bool isFP128Ty() const
Return true if this is 'fp128'.
Definition Type.h:164
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:314
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:222
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition Type.h:158
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
TypeID getTypeID() const
Return the type id for the type.
Definition Type.h:138
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
op_range operands()
Definition User.h:267
Value * getOperand(unsigned i) const
Definition User.h:207
unsigned getNumOperands() const
Definition User.h:229
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
iterator_range< user_iterator > users()
Definition Value.h:428
bool use_empty() const
Definition Value.h:348
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:314
Type * getElementType() const
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:210
void insert_range(Range &&R)
Definition DenseSet.h:236
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition DenseSet.h:188
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr StringLiteral MaxNTID("nvvm.maxntid")
constexpr StringLiteral ReqNTID("nvvm.reqntid")
constexpr StringLiteral ClusterDim("nvvm.cluster_dim")
constexpr StringLiteral BlocksAreClusters("nvvm.blocksareclusters")
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:51
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
Definition Metadata.h:679
@ Ready
Emitted to memory, but waiting on transitive dependencies.
Definition Core.h:552
std::pair< NodeId, LaneBitmask > NodeRef
Definition RDFLiveness.h:35
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
uint64_t read64le(const void *P)
Definition Endian.h:415
uint32_t read32le(const void *P)
Definition Endian.h:412
This is an optimization pass for GlobalISel generic memory operations.
bool isManaged(const Value &)
SmallVector< unsigned, 3 > getReqNTID(const Function &)
@ Offset
Definition DWP.cpp:577
constexpr auto not_equal_to(T &&Arg)
Functor variant of std::not_equal_to that can be used as a UnaryPredicate in functional algorithms li...
Definition STLExtras.h:2196
Align getDeviceByValParamAlign(const Function *F, Type *ArgTy, unsigned AttrIdx, const DataLayout &DL)
The .param-space alignment for a byval parameter or call argument: the (possibly promoted) parameter ...
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
OuterAnalysisManagerProxy< ModuleAnalysisManager, MachineFunction > ModuleAnalysisManagerMachineFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
bool hasBlocksAreClusters(const Function &)
SmallVector< unsigned, 3 > getClusterDim(const Function &)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
void interleave(ForwardIterator begin, ForwardIterator end, UnaryFunctor each_fn, NullaryFunctor between_fn)
An STL-style algorithm similar to std::for_each that applies a second functor between every pair of e...
Definition STLExtras.h:2291
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
std::optional< unsigned > getMaxNReg(const Function &)
unsigned promoteScalarKernelArgumentSize(unsigned Size)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
PTXOpaqueType getPTXOpaqueType(const GlobalVariable &)
std::string utostr(uint64_t X, bool isNeg=false)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr auto equal_to(T &&Arg)
Functor variant of std::equal_to that can be used as a UnaryPredicate in functional algorithms like a...
Definition STLExtras.h:2189
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:366
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
std::optional< unsigned > getMinCTASm(const Function &)
LLVM_ABI Constant * ConstantFoldConstant(const Constant *C, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr)
ConstantFoldConstant - Fold the constant using the specified DataLayout.
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
SmallVector< unsigned, 3 > getMaxNTID(const Function &)
LLVM_ABI void setupModuleAsmPrinter(Module &M, ModuleAnalysisManager &MAM, AsmPrinter &AsmPrinter)
auto make_first_range(ContainerTy &&c)
Given a container of pairs, return a range over the first elements.
Definition STLExtras.h:1415
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool shouldPassAsArray(Type *Ty)
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
Definition STLExtras.h:552
std::optional< unsigned > getMaxClusterRank(const Function &)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, bool Upper=false)
format_hex_no_prefix - Output N as a fixed width hexadecimal.
Definition Format.h:177
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
unsigned promoteScalarArgumentSize(unsigned Size)
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
LLVM_ABI void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style, std::optional< size_t > Width=std::nullopt)
DWARFExpression::Operation Op
Align getPTXParamAlign(const Function *F, Type *Ty, unsigned AttrIdx, const DataLayout &DL)
Alignment for a function parameter or return value at AttributeList index AttrIdx (FirstArgIndex + ar...
ArrayRef(const T &OneElt) -> ArrayRef< T >
Target & getTheNVPTXTarget64()
auto make_second_range(ContainerTy &&c)
Given a container of pairs, return a range over the second elements.
Definition STLExtras.h:1425
LLVM_ABI void setupMachineFunctionAsmPrinter(MachineFunctionAnalysisManager &MFAM, MachineFunction &MF, AsmPrinter &AsmPrinter)
bool isKernelFunction(const Function &F)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
void clearAnnotationCache(const Module *)
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
ABIPreserveInfo getABIPreserve(AttributeList Attrs)
On a function, the attributes are looked up on the function definition or declaration.
LLVM_ABI Constant * ConstantFoldIntegerCast(Constant *C, Type *DestTy, bool IsSigned, const DataLayout &DL)
Constant fold a zext, sext or trunc, depending on IsSigned and whether the DestTy is wider or narrowe...
LLVM_ABI MDNode * GetUnrollMetadata(MDNode *LoopID, StringRef Name)
Given an llvm.loop loop id metadata node, returns the loop hint metadata node with the given name (fo...
LLVM_ABI DISubprogram * getDISubprogram(const MDNode *Scope)
Find subprogram that is enclosing this scope.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Target & getTheNVPTXTarget32()
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
MachineJumpTableEntry - One jump table in the jump table info.
std::vector< MachineBasicBlock * > MBBs
MBBs - The vector of basic blocks from which to create the jump table.
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...