1 //===-- AMDGPUAsmPrinter.h - Print AMDGPU assembly code ---------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// AMDGPU Assembly printer class.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUASMPRINTER_H
16 #define LLVM_LIB_TARGET_AMDGPU_AMDGPUASMPRINTER_H
17 
18 #include "AMDGPU.h"
19 #include "AMDKernelCodeT.h"
20 #include "MCTargetDesc/AMDGPUHSAMetadataStreamer.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/CodeGen/AsmPrinter.h"
23 #include "llvm/Support/AMDHSAKernelDescriptor.h"
24 #include <cstddef>
25 #include <cstdint>
26 #include <limits>
27 #include <memory>
28 #include <string>
29 #include <vector>
30 
31 namespace llvm {
32 
33 class AMDGPUMachineFunction;
34 class AMDGPUTargetStreamer;
35 class MCOperand;
36 class SISubtarget;
37 
38 class AMDGPUAsmPrinter final : public AsmPrinter {
39 private:
40   // Track resource usage for callee functions.
41   struct SIFunctionResourceInfo {
42     // Track the number of explicitly used VGPRs. Special registers reserved at
43     // the end are tracked separately.
44     int32_t NumVGPR = 0;
45     int32_t NumExplicitSGPR = 0;
46     uint64_t PrivateSegmentSize = 0;
47     bool UsesVCC = false;
48     bool UsesFlatScratch = false;
49     bool HasDynamicallySizedStack = false;
50     bool HasRecursion = false;
51 
52     int32_t getTotalNumSGPRs(const SISubtarget &ST) const;
53   };
54 
55   // Track resource usage for kernels / entry functions.
56   struct SIProgramInfo {
57     // Fields set in PGM_RSRC1 pm4 packet.
58     uint32_t VGPRBlocks = 0;
59     uint32_t SGPRBlocks = 0;
60     uint32_t Priority = 0;
61     uint32_t FloatMode = 0;
62     uint32_t Priv = 0;
63     uint32_t DX10Clamp = 0;
64     uint32_t DebugMode = 0;
65     uint32_t IEEEMode = 0;
66     uint64_t ScratchSize = 0;
67 
68     uint64_t ComputePGMRSrc1 = 0;
69 
70     // Fields set in PGM_RSRC2 pm4 packet.
71     uint32_t LDSBlocks = 0;
72     uint32_t ScratchBlocks = 0;
73 
74     uint64_t ComputePGMRSrc2 = 0;
75 
76     uint32_t NumVGPR = 0;
77     uint32_t NumSGPR = 0;
78     uint32_t LDSSize = 0;
79     bool FlatUsed = false;
80 
81     // Number of SGPRs that meets number of waves per execution unit request.
82     uint32_t NumSGPRsForWavesPerEU = 0;
83 
84     // Number of VGPRs that meets number of waves per execution unit request.
85     uint32_t NumVGPRsForWavesPerEU = 0;
86 
87     // Fixed SGPR number used to hold wave scratch offset for entire kernel
88     // execution, or std::numeric_limits<uint16_t>::max() if the register is not
89     // used or not known.
90     uint16_t DebuggerWavefrontPrivateSegmentOffsetSGPR =
91         std::numeric_limits<uint16_t>::max();
92 
93     // Fixed SGPR number of the first 4 SGPRs used to hold scratch V# for entire
94     // kernel execution, or std::numeric_limits<uint16_t>::max() if the register
95     // is not used or not known.
96     uint16_t DebuggerPrivateSegmentBufferSGPR =
97         std::numeric_limits<uint16_t>::max();
98 
99     // Whether there is recursion, dynamic allocas, indirect calls or some other
100     // reason there may be statically unknown stack usage.
101     bool DynamicCallStack = false;
102 
103     // Bonus information for debugging.
104     bool VCCUsed = false;
105 
106     SIProgramInfo() = default;
107   };
108 
109   SIProgramInfo CurrentProgramInfo;
110   DenseMap<const Function *, SIFunctionResourceInfo> CallGraphResourceInfo;
111 
112   AMDGPU::HSAMD::MetadataStreamer HSAMetadataStream;
113   std::map<uint32_t, uint32_t> PALMetadataMap;
114 
115   uint64_t getFunctionCodeSize(const MachineFunction &MF) const;
116   SIFunctionResourceInfo analyzeResourceUsage(const MachineFunction &MF) const;
117 
118   void readPALMetadata(Module &M);
119   void getSIProgramInfo(SIProgramInfo &Out, const MachineFunction &MF);
120   void getAmdKernelCode(amd_kernel_code_t &Out, const SIProgramInfo &KernelInfo,
121                         const MachineFunction &MF) const;
122   void findNumUsedRegistersSI(const MachineFunction &MF,
123                               unsigned &NumSGPR,
124                               unsigned &NumVGPR) const;
125 
126   AMDGPU::HSAMD::Kernel::CodeProps::Metadata getHSACodeProps(
127       const MachineFunction &MF,
128       const SIProgramInfo &ProgramInfo) const;
129   AMDGPU::HSAMD::Kernel::DebugProps::Metadata getHSADebugProps(
130       const MachineFunction &MF,
131       const SIProgramInfo &ProgramInfo) const;
132 
133   /// Emit register usage information so that the GPU driver
134   /// can correctly setup the GPU state.
135   void EmitProgramInfoSI(const MachineFunction &MF,
136                          const SIProgramInfo &KernelInfo);
137   void EmitPALMetadata(const MachineFunction &MF,
138                        const SIProgramInfo &KernelInfo);
139   void emitCommonFunctionComments(uint32_t NumVGPR,
140                                   uint32_t NumSGPR,
141                                   uint64_t ScratchSize,
142                                   uint64_t CodeSize,
143                                   const AMDGPUMachineFunction* MFI);
144 
145   uint16_t getAmdhsaKernelCodeProperties(
146       const MachineFunction &MF) const;
147 
148   amdhsa::kernel_descriptor_t getAmdhsaKernelDescriptor(
149       const MachineFunction &MF,
150       const SIProgramInfo &PI) const;
151 
152 public:
153   explicit AMDGPUAsmPrinter(TargetMachine &TM,
154                             std::unique_ptr<MCStreamer> Streamer);
155 
156   StringRef getPassName() const override;
157 
158   const MCSubtargetInfo* getSTI() const;
159 
160   AMDGPUTargetStreamer* getTargetStreamer() const;
161 
162   bool doFinalization(Module &M) override;
163   bool runOnMachineFunction(MachineFunction &MF) override;
164 
165   /// Wrapper for MCInstLowering.lowerOperand() for the tblgen'erated
166   /// pseudo lowering.
167   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
168 
169   /// Lower the specified LLVM Constant to an MCExpr.
170   /// The AsmPrinter::lowerConstantof does not know how to lower
171   /// addrspacecast, therefore they should be lowered by this function.
172   const MCExpr *lowerConstant(const Constant *CV) override;
173 
174   /// tblgen'erated driver function for lowering simple MI->MC pseudo
175   /// instructions.
176   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
177                                    const MachineInstr *MI);
178 
179   /// Implemented in AMDGPUMCInstLower.cpp
180   void EmitInstruction(const MachineInstr *MI) override;
181 
182   void EmitFunctionBodyStart() override;
183 
184   void EmitFunctionBodyEnd() override;
185 
186   void EmitFunctionEntryLabel() override;
187 
188   void EmitBasicBlockStart(const MachineBasicBlock &MBB) const override;
189 
190   void EmitGlobalVariable(const GlobalVariable *GV) override;
191 
192   void EmitStartOfAsmFile(Module &M) override;
193 
194   void EmitEndOfAsmFile(Module &M) override;
195 
196   bool isBlockOnlyReachableByFallthrough(
197     const MachineBasicBlock *MBB) const override;
198 
199   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
200                        unsigned AsmVariant, const char *ExtraCode,
201                        raw_ostream &O) override;
202 
203 protected:
204   mutable std::vector<std::string> DisasmLines, HexLines;
205   mutable size_t DisasmLineMaxLen;
206   AMDGPUAS AMDGPUASI;
207 };
208 
209 } // end namespace llvm
210 
211 #endif // LLVM_LIB_TARGET_AMDGPU_AMDGPUASMPRINTER_H
212