R600/SI: Default to no single precision denormals.
[oota-llvm.git] / lib / Target / R600 / AMDGPUAsmPrinter.cpp
1 //===-- AMDGPUAsmPrinter.cpp - AMDGPU Assebly printer  --------------------===//
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 ///
12 /// The AMDGPUAsmPrinter is used to print both assembly string and also binary
13 /// code.  When passed an MCAsmStreamer it prints assembly and when passed
14 /// an MCObjectStreamer it outputs binary code.
15 //
16 //===----------------------------------------------------------------------===//
17 //
18
19 #include "AMDGPUAsmPrinter.h"
20 #include "AMDGPU.h"
21 #include "AMDGPUSubtarget.h"
22 #include "R600Defines.h"
23 #include "R600MachineFunctionInfo.h"
24 #include "R600RegisterInfo.h"
25 #include "SIDefines.h"
26 #include "SIMachineFunctionInfo.h"
27 #include "SIRegisterInfo.h"
28 #include "llvm/MC/MCContext.h"
29 #include "llvm/MC/MCSectionELF.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/Support/ELF.h"
32 #include "llvm/Support/MathExtras.h"
33 #include "llvm/Support/TargetRegistry.h"
34 #include "llvm/Target/TargetLoweringObjectFile.h"
35
36 using namespace llvm;
37
38 // TODO: This should get the default rounding mode from the kernel. We just set
39 // the default here, but this could change if the OpenCL rounding mode pragmas
40 // are used.
41 //
42 // The denormal mode here should match what is reported by the OpenCL runtime
43 // for the CL_FP_DENORM bit from CL_DEVICE_{HALF|SINGLE|DOUBLE}_FP_CONFIG, but
44 // can also be override to flush with the -cl-denorms-are-zero compiler flag.
45 //
46 // AMD OpenCL only sets flush none and reports CL_FP_DENORM for double
47 // precision, and leaves single precision to flush all and does not report
48 // CL_FP_DENORM for CL_DEVICE_SINGLE_FP_CONFIG. Mesa's OpenCL currently reports
49 // CL_FP_DENORM for both.
50 //
51 // FIXME: It seems some instructions do not support single precision denormals
52 // regardless of the mode (exp_*_f32, rcp_*_f32, rsq_*_f32, rsq_*f32, sqrt_f32,
53 // and sin_f32, cos_f32 on most parts).
54
55 // We want to use these instructions, and using fp32 denormals also causes
56 // instructions to run at the double precision rate for the device so it's
57 // probably best to just report no single precision denormals.
58 static uint32_t getFPMode(const MachineFunction &) {
59   return FP_ROUND_MODE_SP(FP_ROUND_ROUND_TO_NEAREST) |
60          FP_ROUND_MODE_DP(FP_ROUND_ROUND_TO_NEAREST) |
61          FP_DENORM_MODE_SP(FP_DENORM_FLUSH_IN_FLUSH_OUT) |
62          FP_DENORM_MODE_DP(FP_DENORM_FLUSH_NONE);
63 }
64
65 static AsmPrinter *createAMDGPUAsmPrinterPass(TargetMachine &tm,
66                                               MCStreamer &Streamer) {
67   return new AMDGPUAsmPrinter(tm, Streamer);
68 }
69
70 extern "C" void LLVMInitializeR600AsmPrinter() {
71   TargetRegistry::RegisterAsmPrinter(TheAMDGPUTarget, createAMDGPUAsmPrinterPass);
72 }
73
74 AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
75     : AsmPrinter(TM, Streamer) {
76   DisasmEnabled = TM.getSubtarget<AMDGPUSubtarget>().dumpCode();
77 }
78
79 bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
80   SetupMachineFunction(MF);
81
82   OutStreamer.emitRawComment(Twine('@') + MF.getName() + Twine(':'));
83
84   MCContext &Context = getObjFileLowering().getContext();
85   const MCSectionELF *ConfigSection = Context.getELFSection(".AMDGPU.config",
86                                               ELF::SHT_PROGBITS, 0,
87                                               SectionKind::getReadOnly());
88   OutStreamer.SwitchSection(ConfigSection);
89
90   const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();
91   SIProgramInfo KernelInfo;
92   if (STM.getGeneration() > AMDGPUSubtarget::NORTHERN_ISLANDS) {
93     getSIProgramInfo(KernelInfo, MF);
94     EmitProgramInfoSI(MF, KernelInfo);
95   } else {
96     EmitProgramInfoR600(MF);
97   }
98
99   DisasmLines.clear();
100   HexLines.clear();
101   DisasmLineMaxLen = 0;
102
103   OutStreamer.SwitchSection(getObjFileLowering().getTextSection());
104   EmitFunctionBody();
105
106   if (isVerbose()) {
107     const MCSectionELF *CommentSection
108       = Context.getELFSection(".AMDGPU.csdata",
109                               ELF::SHT_PROGBITS, 0,
110                               SectionKind::getReadOnly());
111     OutStreamer.SwitchSection(CommentSection);
112
113     if (STM.getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) {
114       OutStreamer.emitRawComment(" Kernel info:", false);
115       OutStreamer.emitRawComment(" codeLenInByte = " + Twine(KernelInfo.CodeLen),
116                                  false);
117       OutStreamer.emitRawComment(" NumSgprs: " + Twine(KernelInfo.NumSGPR),
118                                  false);
119       OutStreamer.emitRawComment(" NumVgprs: " + Twine(KernelInfo.NumVGPR),
120                                  false);
121       OutStreamer.emitRawComment(" FloatMode: " + Twine(KernelInfo.FloatMode),
122                                  false);
123       OutStreamer.emitRawComment(" IeeeMode: " + Twine(KernelInfo.IEEEMode),
124                                  false);
125     } else {
126       R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
127       OutStreamer.emitRawComment(
128         Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->StackSize)));
129     }
130   }
131
132   if (STM.dumpCode()) {
133 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
134     MF.dump();
135 #endif
136
137     if (DisasmEnabled) {
138       OutStreamer.SwitchSection(Context.getELFSection(".AMDGPU.disasm",
139                                                   ELF::SHT_NOTE, 0,
140                                                   SectionKind::getReadOnly()));
141
142       for (size_t i = 0; i < DisasmLines.size(); ++i) {
143         std::string Comment(DisasmLineMaxLen - DisasmLines[i].size(), ' ');
144         Comment += " ; " + HexLines[i] + "\n";
145
146         OutStreamer.EmitBytes(StringRef(DisasmLines[i]));
147         OutStreamer.EmitBytes(StringRef(Comment));
148       }
149     }
150   }
151
152   return false;
153 }
154
155 void AMDGPUAsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) {
156   unsigned MaxGPR = 0;
157   bool killPixel = false;
158   const R600RegisterInfo *RI
159     = static_cast<const R600RegisterInfo*>(TM.getRegisterInfo());
160   const R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
161   const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();
162
163   for (const MachineBasicBlock &MBB : MF) {
164     for (const MachineInstr &MI : MBB) {
165       if (MI.getOpcode() == AMDGPU::KILLGT)
166         killPixel = true;
167       unsigned numOperands = MI.getNumOperands();
168       for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
169         const MachineOperand &MO = MI.getOperand(op_idx);
170         if (!MO.isReg())
171           continue;
172         unsigned HWReg = RI->getEncodingValue(MO.getReg()) & 0xff;
173
174         // Register with value > 127 aren't GPR
175         if (HWReg > 127)
176           continue;
177         MaxGPR = std::max(MaxGPR, HWReg);
178       }
179     }
180   }
181
182   unsigned RsrcReg;
183   if (STM.getGeneration() >= AMDGPUSubtarget::EVERGREEN) {
184     // Evergreen / Northern Islands
185     switch (MFI->getShaderType()) {
186     default: // Fall through
187     case ShaderType::COMPUTE:  RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break;
188     case ShaderType::GEOMETRY: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break;
189     case ShaderType::PIXEL:    RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break;
190     case ShaderType::VERTEX:   RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break;
191     }
192   } else {
193     // R600 / R700
194     switch (MFI->getShaderType()) {
195     default: // Fall through
196     case ShaderType::GEOMETRY: // Fall through
197     case ShaderType::COMPUTE:  // Fall through
198     case ShaderType::VERTEX:   RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break;
199     case ShaderType::PIXEL:    RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break;
200     }
201   }
202
203   OutStreamer.EmitIntValue(RsrcReg, 4);
204   OutStreamer.EmitIntValue(S_NUM_GPRS(MaxGPR + 1) |
205                            S_STACK_SIZE(MFI->StackSize), 4);
206   OutStreamer.EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4);
207   OutStreamer.EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4);
208
209   if (MFI->getShaderType() == ShaderType::COMPUTE) {
210     OutStreamer.EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4);
211     OutStreamer.EmitIntValue(RoundUpToAlignment(MFI->LDSSize, 4) >> 2, 4);
212   }
213 }
214
215 void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
216                                         const MachineFunction &MF) const {
217   uint64_t CodeSize = 0;
218   unsigned MaxSGPR = 0;
219   unsigned MaxVGPR = 0;
220   bool VCCUsed = false;
221   const SIRegisterInfo *RI
222     = static_cast<const SIRegisterInfo*>(TM.getRegisterInfo());
223
224   for (const MachineBasicBlock &MBB : MF) {
225     for (const MachineInstr &MI : MBB) {
226       // TODO: CodeSize should account for multiple functions.
227       CodeSize += MI.getDesc().Size;
228
229       unsigned numOperands = MI.getNumOperands();
230       for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
231         const MachineOperand &MO = MI.getOperand(op_idx);
232         unsigned width = 0;
233         bool isSGPR = false;
234
235         if (!MO.isReg()) {
236           continue;
237         }
238         unsigned reg = MO.getReg();
239         if (reg == AMDGPU::VCC || reg == AMDGPU::VCC_LO ||
240             reg == AMDGPU::VCC_HI) {
241           VCCUsed = true;
242           continue;
243         }
244
245         switch (reg) {
246         default: break;
247         case AMDGPU::SCC:
248         case AMDGPU::EXEC:
249         case AMDGPU::M0:
250           continue;
251         }
252
253         if (AMDGPU::SReg_32RegClass.contains(reg)) {
254           isSGPR = true;
255           width = 1;
256         } else if (AMDGPU::VReg_32RegClass.contains(reg)) {
257           isSGPR = false;
258           width = 1;
259         } else if (AMDGPU::SReg_64RegClass.contains(reg)) {
260           isSGPR = true;
261           width = 2;
262         } else if (AMDGPU::VReg_64RegClass.contains(reg)) {
263           isSGPR = false;
264           width = 2;
265         } else if (AMDGPU::VReg_96RegClass.contains(reg)) {
266           isSGPR = false;
267           width = 3;
268         } else if (AMDGPU::SReg_128RegClass.contains(reg)) {
269           isSGPR = true;
270           width = 4;
271         } else if (AMDGPU::VReg_128RegClass.contains(reg)) {
272           isSGPR = false;
273           width = 4;
274         } else if (AMDGPU::SReg_256RegClass.contains(reg)) {
275           isSGPR = true;
276           width = 8;
277         } else if (AMDGPU::VReg_256RegClass.contains(reg)) {
278           isSGPR = false;
279           width = 8;
280         } else if (AMDGPU::SReg_512RegClass.contains(reg)) {
281           isSGPR = true;
282           width = 16;
283         } else if (AMDGPU::VReg_512RegClass.contains(reg)) {
284           isSGPR = false;
285           width = 16;
286         } else {
287           llvm_unreachable("Unknown register class");
288         }
289         unsigned hwReg = RI->getEncodingValue(reg) & 0xff;
290         unsigned maxUsed = hwReg + width - 1;
291         if (isSGPR) {
292           MaxSGPR = maxUsed > MaxSGPR ? maxUsed : MaxSGPR;
293         } else {
294           MaxVGPR = maxUsed > MaxVGPR ? maxUsed : MaxVGPR;
295         }
296       }
297     }
298   }
299
300   if (VCCUsed)
301     MaxSGPR += 2;
302
303   ProgInfo.NumVGPR = MaxVGPR;
304   ProgInfo.NumSGPR = MaxSGPR;
305
306   // Set the value to initialize FP_ROUND and FP_DENORM parts of the mode
307   // register.
308   ProgInfo.FloatMode = getFPMode(MF);
309
310   // XXX: Not quite sure what this does, but sc seems to unset this.
311   ProgInfo.IEEEMode = 0;
312
313   // Do not clamp NAN to 0.
314   ProgInfo.DX10Clamp = 0;
315
316   ProgInfo.CodeLen = CodeSize;
317 }
318
319 void AMDGPUAsmPrinter::EmitProgramInfoSI(const MachineFunction &MF,
320                                          const SIProgramInfo &KernelInfo) {
321   const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();
322   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
323
324   unsigned RsrcReg;
325   switch (MFI->getShaderType()) {
326   default: // Fall through
327   case ShaderType::COMPUTE:  RsrcReg = R_00B848_COMPUTE_PGM_RSRC1; break;
328   case ShaderType::GEOMETRY: RsrcReg = R_00B228_SPI_SHADER_PGM_RSRC1_GS; break;
329   case ShaderType::PIXEL:    RsrcReg = R_00B028_SPI_SHADER_PGM_RSRC1_PS; break;
330   case ShaderType::VERTEX:   RsrcReg = R_00B128_SPI_SHADER_PGM_RSRC1_VS; break;
331   }
332
333   unsigned LDSAlignShift;
334   if (STM.getGeneration() < AMDGPUSubtarget::SEA_ISLANDS) {
335     // LDS is allocated in 64 dword blocks.
336     LDSAlignShift = 8;
337   } else {
338     // LDS is allocated in 128 dword blocks.
339     LDSAlignShift = 9;
340   }
341
342   unsigned LDSBlocks =
343     RoundUpToAlignment(MFI->LDSSize, 1 << LDSAlignShift) >> LDSAlignShift;
344
345   if (MFI->getShaderType() == ShaderType::COMPUTE) {
346     OutStreamer.EmitIntValue(R_00B848_COMPUTE_PGM_RSRC1, 4);
347
348     const uint32_t ComputePGMRSrc1 =
349       S_00B848_VGPRS(KernelInfo.NumVGPR / 4) |
350       S_00B848_SGPRS(KernelInfo.NumSGPR / 8) |
351       S_00B848_PRIORITY(KernelInfo.Priority) |
352       S_00B848_FLOAT_MODE(KernelInfo.FloatMode) |
353       S_00B848_PRIV(KernelInfo.Priv) |
354       S_00B848_DX10_CLAMP(KernelInfo.DX10Clamp) |
355       S_00B848_IEEE_MODE(KernelInfo.DebugMode) |
356       S_00B848_IEEE_MODE(KernelInfo.IEEEMode);
357
358     OutStreamer.EmitIntValue(ComputePGMRSrc1, 4);
359
360     OutStreamer.EmitIntValue(R_00B84C_COMPUTE_PGM_RSRC2, 4);
361     OutStreamer.EmitIntValue(S_00B84C_LDS_SIZE(LDSBlocks), 4);
362   } else {
363     OutStreamer.EmitIntValue(RsrcReg, 4);
364     OutStreamer.EmitIntValue(S_00B028_VGPRS(KernelInfo.NumVGPR / 4) |
365                              S_00B028_SGPRS(KernelInfo.NumSGPR / 8), 4);
366   }
367
368   if (MFI->getShaderType() == ShaderType::PIXEL) {
369     OutStreamer.EmitIntValue(R_00B02C_SPI_SHADER_PGM_RSRC2_PS, 4);
370     OutStreamer.EmitIntValue(S_00B02C_EXTRA_LDS_SIZE(LDSBlocks), 4);
371     OutStreamer.EmitIntValue(R_0286CC_SPI_PS_INPUT_ENA, 4);
372     OutStreamer.EmitIntValue(MFI->PSInputAddr, 4);
373   }
374 }