Path: blob/main/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h
35271 views
//===-- NVPTXAsmPrinter.h - NVPTX LLVM assembly writer ----------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains a printer that converts from our internal representation9// of machine-dependent LLVM code to NVPTX assembly language.10//11//===----------------------------------------------------------------------===//1213#ifndef LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H14#define LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H1516#include "NVPTX.h"17#include "NVPTXSubtarget.h"18#include "NVPTXTargetMachine.h"19#include "llvm/ADT/DenseMap.h"20#include "llvm/ADT/SmallVector.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/CodeGen/AsmPrinter.h"23#include "llvm/CodeGen/MachineFunction.h"24#include "llvm/CodeGen/MachineLoopInfo.h"25#include "llvm/IR/Constants.h"26#include "llvm/IR/DebugLoc.h"27#include "llvm/IR/DerivedTypes.h"28#include "llvm/IR/Function.h"29#include "llvm/IR/GlobalAlias.h"30#include "llvm/IR/GlobalValue.h"31#include "llvm/IR/Value.h"32#include "llvm/MC/MCExpr.h"33#include "llvm/MC/MCStreamer.h"34#include "llvm/MC/MCSymbol.h"35#include "llvm/Pass.h"36#include "llvm/Support/Casting.h"37#include "llvm/Support/Compiler.h"38#include "llvm/Support/ErrorHandling.h"39#include "llvm/Support/raw_ostream.h"40#include "llvm/Target/TargetMachine.h"41#include <algorithm>42#include <cassert>43#include <map>44#include <memory>45#include <string>46#include <vector>4748// The ptx syntax and format is very different from that usually seem in a .s49// file,50// therefore we are not able to use the MCAsmStreamer interface here.51//52// We are handcrafting the output method here.53//54// A better approach is to clone the MCAsmStreamer to a MCPTXAsmStreamer55// (subclass of MCStreamer).5657namespace llvm {5859class MCOperand;6061class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {6263class AggBuffer {64// Used to buffer the emitted string for initializing global aggregates.65//66// Normally an aggregate (array, vector, or structure) is emitted as a u8[].67// However, if either element/field of the aggregate is a non-NULL address,68// and all such addresses are properly aligned, then the aggregate is69// emitted as u32[] or u64[]. In the case of unaligned addresses, the70// aggregate is emitted as u8[], and the mask() operator is used for all71// pointers.72//73// We first layout the aggregate in 'buffer' in bytes, except for those74// symbol addresses. For the i-th symbol address in the aggregate, its75// corresponding 4-byte or 8-byte elements in 'buffer' are filled with 0s.76// symbolPosInBuffer[i-1] records its position in 'buffer', and Symbols[i-1]77// records the Value*.78//79// Once we have this AggBuffer setup, we can choose how to print it out.80public:81// number of symbol addresses82unsigned numSymbols() const { return Symbols.size(); }8384bool allSymbolsAligned(unsigned ptrSize) const {85return llvm::all_of(symbolPosInBuffer,86[=](unsigned pos) { return pos % ptrSize == 0; });87}8889private:90const unsigned size; // size of the buffer in bytes91std::vector<unsigned char> buffer; // the buffer92SmallVector<unsigned, 4> symbolPosInBuffer;93SmallVector<const Value *, 4> Symbols;94// SymbolsBeforeStripping[i] is the original form of Symbols[i] before95// stripping pointer casts, i.e.,96// Symbols[i] == SymbolsBeforeStripping[i]->stripPointerCasts().97//98// We need to keep these values because AggBuffer::print decides whether to99// emit a "generic()" cast for Symbols[i] depending on the address space of100// SymbolsBeforeStripping[i].101SmallVector<const Value *, 4> SymbolsBeforeStripping;102unsigned curpos;103NVPTXAsmPrinter &AP;104bool EmitGeneric;105106public:107AggBuffer(unsigned size, NVPTXAsmPrinter &AP)108: size(size), buffer(size), AP(AP) {109curpos = 0;110EmitGeneric = AP.EmitGeneric;111}112113// Copy Num bytes from Ptr.114// if Bytes > Num, zero fill up to Bytes.115unsigned addBytes(unsigned char *Ptr, int Num, int Bytes) {116assert((curpos + Num) <= size);117assert((curpos + Bytes) <= size);118for (int i = 0; i < Num; ++i) {119buffer[curpos] = Ptr[i];120curpos++;121}122for (int i = Num; i < Bytes; ++i) {123buffer[curpos] = 0;124curpos++;125}126return curpos;127}128129unsigned addZeros(int Num) {130assert((curpos + Num) <= size);131for (int i = 0; i < Num; ++i) {132buffer[curpos] = 0;133curpos++;134}135return curpos;136}137138void addSymbol(const Value *GVar, const Value *GVarBeforeStripping) {139symbolPosInBuffer.push_back(curpos);140Symbols.push_back(GVar);141SymbolsBeforeStripping.push_back(GVarBeforeStripping);142}143144void printBytes(raw_ostream &os);145void printWords(raw_ostream &os);146147private:148void printSymbol(unsigned nSym, raw_ostream &os);149};150151friend class AggBuffer;152153private:154StringRef getPassName() const override { return "NVPTX Assembly Printer"; }155156const Function *F;157std::string CurrentFnName;158159void emitStartOfAsmFile(Module &M) override;160void emitBasicBlockStart(const MachineBasicBlock &MBB) override;161void emitFunctionEntryLabel() override;162void emitFunctionBodyStart() override;163void emitFunctionBodyEnd() override;164void emitImplicitDef(const MachineInstr *MI) const override;165166void emitInstruction(const MachineInstr *) override;167void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);168bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp);169MCOperand GetSymbolRef(const MCSymbol *Symbol);170unsigned encodeVirtualRegister(unsigned Reg);171172void printMemOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O,173const char *Modifier = nullptr);174void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O,175bool processDemoted, const NVPTXSubtarget &STI);176void emitGlobals(const Module &M);177void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;178void emitHeader(Module &M, raw_ostream &O, const NVPTXSubtarget &STI);179void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const;180void emitVirtualRegister(unsigned int vr, raw_ostream &);181void emitFunctionParamList(const Function *, raw_ostream &O);182void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF);183void printReturnValStr(const Function *, raw_ostream &O);184void printReturnValStr(const MachineFunction &MF, raw_ostream &O);185bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,186const char *ExtraCode, raw_ostream &) override;187void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);188bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,189const char *ExtraCode, raw_ostream &) override;190191const MCExpr *lowerConstantForGV(const Constant *CV, bool ProcessingGeneric);192void printMCExpr(const MCExpr &Expr, raw_ostream &OS);193194protected:195bool doInitialization(Module &M) override;196bool doFinalization(Module &M) override;197198private:199bool GlobalsEmitted;200201// This is specific per MachineFunction.202const MachineRegisterInfo *MRI;203// The contents are specific for each204// MachineFunction. But the size of the205// array is not.206typedef DenseMap<unsigned, unsigned> VRegMap;207typedef DenseMap<const TargetRegisterClass *, VRegMap> VRegRCMap;208VRegRCMap VRegMapping;209210// List of variables demoted to a function scope.211std::map<const Function *, std::vector<const GlobalVariable *>> localDecls;212213void emitPTXGlobalVariable(const GlobalVariable *GVar, raw_ostream &O,214const NVPTXSubtarget &STI);215void emitPTXAddressSpace(unsigned int AddressSpace, raw_ostream &O) const;216std::string getPTXFundamentalTypeStr(Type *Ty, bool = true) const;217void printScalarConstant(const Constant *CPV, raw_ostream &O);218void printFPConstant(const ConstantFP *Fp, raw_ostream &O);219void bufferLEByte(const Constant *CPV, int Bytes, AggBuffer *aggBuffer);220void bufferAggregateConstant(const Constant *CV, AggBuffer *aggBuffer);221222void emitLinkageDirective(const GlobalValue *V, raw_ostream &O);223void emitDeclarations(const Module &, raw_ostream &O);224void emitDeclaration(const Function *, raw_ostream &O);225void emitAliasDeclaration(const GlobalAlias *, raw_ostream &O);226void emitDeclarationWithName(const Function *, MCSymbol *, raw_ostream &O);227void emitDemotedVars(const Function *, raw_ostream &);228229bool lowerImageHandleOperand(const MachineInstr *MI, unsigned OpNo,230MCOperand &MCOp);231void lowerImageHandleSymbol(unsigned Index, MCOperand &MCOp);232233bool isLoopHeaderOfNoUnroll(const MachineBasicBlock &MBB) const;234235// Used to control the need to emit .generic() in the initializer of236// module scope variables.237// Although ptx supports the hybrid mode like the following,238// .global .u32 a;239// .global .u32 b;240// .global .u32 addr[] = {a, generic(b)}241// we have difficulty representing the difference in the NVVM IR.242//243// Since the address value should always be generic in CUDA C and always244// be specific in OpenCL, we use this simple control here.245//246bool EmitGeneric;247248public:249NVPTXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)250: AsmPrinter(TM, std::move(Streamer)),251EmitGeneric(static_cast<NVPTXTargetMachine &>(TM).getDrvInterface() ==252NVPTX::CUDA) {}253254bool runOnMachineFunction(MachineFunction &F) override;255256void getAnalysisUsage(AnalysisUsage &AU) const override {257AU.addRequired<MachineLoopInfoWrapperPass>();258AsmPrinter::getAnalysisUsage(AU);259}260261std::string getVirtualRegisterName(unsigned) const;262263const MCSymbol *getFunctionFrameSymbol() const override;264265// Make emitGlobalVariable() no-op for NVPTX.266// Global variables have been already emitted by the time the base AsmPrinter267// attempts to do so in doFinalization() (see NVPTXAsmPrinter::emitGlobals()).268void emitGlobalVariable(const GlobalVariable *GV) override {}269};270271} // end namespace llvm272273#endif // LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H274275276