1 | //===-- R600AsmPrinter.cpp - R600 Assembly printer ------------------------===// |
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 | /// \file |
10 | /// |
11 | /// The R600AsmPrinter is used to print both assembly string and also binary |
12 | /// code. When passed an MCAsmStreamer it prints assembly and when passed |
13 | /// an MCObjectStreamer it outputs binary code. |
14 | // |
15 | //===----------------------------------------------------------------------===// |
16 | |
17 | #include "R600AsmPrinter.h" |
18 | #include "MCTargetDesc/R600MCTargetDesc.h" |
19 | #include "R600Defines.h" |
20 | #include "R600MachineFunctionInfo.h" |
21 | #include "R600Subtarget.h" |
22 | #include "llvm/BinaryFormat/ELF.h" |
23 | #include "llvm/MC/MCContext.h" |
24 | #include "llvm/MC/MCSectionELF.h" |
25 | #include "llvm/MC/MCStreamer.h" |
26 | #include "llvm/Target/TargetLoweringObjectFile.h" |
27 | |
28 | using namespace llvm; |
29 | |
30 | AsmPrinter * |
31 | llvm::createR600AsmPrinterPass(TargetMachine &TM, |
32 | std::unique_ptr<MCStreamer> &&Streamer) { |
33 | return new R600AsmPrinter(TM, std::move(Streamer)); |
34 | } |
35 | |
36 | R600AsmPrinter::R600AsmPrinter(TargetMachine &TM, |
37 | std::unique_ptr<MCStreamer> Streamer) |
38 | : AsmPrinter(TM, std::move(Streamer)) { } |
39 | |
40 | StringRef R600AsmPrinter::getPassName() const { |
41 | return "R600 Assembly Printer" ; |
42 | } |
43 | |
44 | void R600AsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) { |
45 | unsigned MaxGPR = 0; |
46 | bool killPixel = false; |
47 | const R600Subtarget &STM = MF.getSubtarget<R600Subtarget>(); |
48 | const R600RegisterInfo *RI = STM.getRegisterInfo(); |
49 | const R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); |
50 | |
51 | for (const MachineBasicBlock &MBB : MF) { |
52 | for (const MachineInstr &MI : MBB) { |
53 | if (MI.getOpcode() == R600::KILLGT) |
54 | killPixel = true; |
55 | unsigned numOperands = MI.getNumOperands(); |
56 | for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) { |
57 | const MachineOperand &MO = MI.getOperand(i: op_idx); |
58 | if (!MO.isReg()) |
59 | continue; |
60 | unsigned HWReg = RI->getHWRegIndex(Reg: MO.getReg()); |
61 | |
62 | // Register with value > 127 aren't GPR |
63 | if (HWReg > 127) |
64 | continue; |
65 | MaxGPR = std::max(a: MaxGPR, b: HWReg); |
66 | } |
67 | } |
68 | } |
69 | |
70 | unsigned RsrcReg; |
71 | if (STM.getGeneration() >= AMDGPUSubtarget::EVERGREEN) { |
72 | // Evergreen / Northern Islands |
73 | switch (MF.getFunction().getCallingConv()) { |
74 | default: [[fallthrough]]; |
75 | case CallingConv::AMDGPU_CS: RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break; |
76 | case CallingConv::AMDGPU_GS: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break; |
77 | case CallingConv::AMDGPU_PS: RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break; |
78 | case CallingConv::AMDGPU_VS: RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break; |
79 | } |
80 | } else { |
81 | // R600 / R700 |
82 | switch (MF.getFunction().getCallingConv()) { |
83 | default: [[fallthrough]]; |
84 | case CallingConv::AMDGPU_GS: [[fallthrough]]; |
85 | case CallingConv::AMDGPU_CS: [[fallthrough]]; |
86 | case CallingConv::AMDGPU_VS: RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break; |
87 | case CallingConv::AMDGPU_PS: RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break; |
88 | } |
89 | } |
90 | |
91 | OutStreamer->emitInt32(Value: RsrcReg); |
92 | OutStreamer->emitIntValue(S_NUM_GPRS(MaxGPR + 1) | |
93 | S_STACK_SIZE(MFI->CFStackSize), Size: 4); |
94 | OutStreamer->emitInt32(R_02880C_DB_SHADER_CONTROL); |
95 | OutStreamer->emitInt32(S_02880C_KILL_ENABLE(killPixel)); |
96 | |
97 | if (AMDGPU::isCompute(CC: MF.getFunction().getCallingConv())) { |
98 | OutStreamer->emitInt32(R_0288E8_SQ_LDS_ALLOC); |
99 | OutStreamer->emitIntValue(Value: alignTo(Value: MFI->getLDSSize(), Align: 4) >> 2, Size: 4); |
100 | } |
101 | } |
102 | |
103 | bool R600AsmPrinter::runOnMachineFunction(MachineFunction &MF) { |
104 | |
105 | |
106 | // Functions needs to be cacheline (256B) aligned. |
107 | MF.ensureAlignment(A: Align(256)); |
108 | |
109 | SetupMachineFunction(MF); |
110 | |
111 | MCContext &Context = getObjFileLowering().getContext(); |
112 | MCSectionELF *ConfigSection = |
113 | Context.getELFSection(Section: ".AMDGPU.config" , Type: ELF::SHT_PROGBITS, Flags: 0); |
114 | OutStreamer->switchSection(Section: ConfigSection); |
115 | |
116 | EmitProgramInfoR600(MF); |
117 | |
118 | emitFunctionBody(); |
119 | |
120 | if (isVerbose()) { |
121 | MCSectionELF * = |
122 | Context.getELFSection(Section: ".AMDGPU.csdata" , Type: ELF::SHT_PROGBITS, Flags: 0); |
123 | OutStreamer->switchSection(Section: CommentSection); |
124 | |
125 | R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); |
126 | OutStreamer->emitRawComment( |
127 | T: Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->CFStackSize))); |
128 | } |
129 | |
130 | return false; |
131 | } |
132 | |