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