1 | //===- AMDGPUMIRFormatter.cpp ---------------------------------------------===// |
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 | /// Implementation of AMDGPU overrides of MIRFormatter. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "AMDGPUMIRFormatter.h" |
15 | #include "GCNSubtarget.h" |
16 | #include "SIMachineFunctionInfo.h" |
17 | |
18 | using namespace llvm; |
19 | |
20 | void AMDGPUMIRFormatter::printImm(raw_ostream &OS, const MachineInstr &MI, |
21 | std::optional<unsigned int> OpIdx, int64_t Imm) const { |
22 | |
23 | switch (MI.getOpcode()) { |
24 | case AMDGPU::S_DELAY_ALU: |
25 | assert(OpIdx == 0); |
26 | printSDelayAluImm(Imm, OS); |
27 | break; |
28 | default: |
29 | MIRFormatter::printImm(OS, MI, OpIdx, Imm); |
30 | break; |
31 | } |
32 | } |
33 | |
34 | /// Implement target specific parsing of immediate mnemonics. The mnemonic is |
35 | /// a string with a leading dot. |
36 | bool AMDGPUMIRFormatter::parseImmMnemonic(const unsigned OpCode, |
37 | const unsigned OpIdx, |
38 | StringRef Src, int64_t &Imm, |
39 | ErrorCallbackType ErrorCallback) const |
40 | { |
41 | |
42 | switch (OpCode) { |
43 | case AMDGPU::S_DELAY_ALU: |
44 | return parseSDelayAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback); |
45 | default: |
46 | break; |
47 | } |
48 | return true; // Don't know what this is |
49 | } |
50 | |
51 | void AMDGPUMIRFormatter::printSDelayAluImm(int64_t Imm, |
52 | llvm::raw_ostream &OS) const { |
53 | // Construct an immediate string to represent the information encoded in the |
54 | // s_delay_alu immediate. |
55 | // .id0_<dep>[_skip_<count>_id1<dep>] |
56 | constexpr int64_t None = 0; |
57 | constexpr int64_t Same = 0; |
58 | |
59 | uint64_t Id0 = (Imm & 0xF); |
60 | uint64_t Skip = ((Imm >> 4) & 0x7); |
61 | uint64_t Id1 = ((Imm >> 7) & 0xF); |
62 | auto Outdep = [&](uint64_t Id) { |
63 | if (Id == None) |
64 | OS << "NONE" ; |
65 | else if (Id < 5) |
66 | OS << "VALU_DEP_" << Id; |
67 | else if (Id < 8) |
68 | OS << "TRANS32_DEP_" << Id - 4; |
69 | else |
70 | OS << "SALU_CYCLE_" << Id - 8; |
71 | }; |
72 | |
73 | OS << ".id0_" ; |
74 | Outdep(Id0); |
75 | |
76 | // If the second inst is "same" and "none", no need to print the rest of the |
77 | // string. |
78 | if (Skip == Same && Id1 == None) |
79 | return; |
80 | |
81 | // Encode the second delay specification. |
82 | OS << "_skip_" ; |
83 | if (Skip == 0) |
84 | OS << "SAME" ; |
85 | else if (Skip == 1) |
86 | OS << "NEXT" ; |
87 | else |
88 | OS << "SKIP_" << Skip - 1; |
89 | |
90 | OS << "_id1_" ; |
91 | Outdep(Id1); |
92 | } |
93 | |
94 | bool AMDGPUMIRFormatter::parseSDelayAluImmMnemonic( |
95 | const unsigned int OpIdx, int64_t &Imm, llvm::StringRef &Src, |
96 | llvm::MIRFormatter::ErrorCallbackType &ErrorCallback) const |
97 | { |
98 | assert(OpIdx == 0); |
99 | |
100 | Imm = 0; |
101 | bool Expected = Src.consume_front(Prefix: ".id0_" ); |
102 | if (!Expected) |
103 | return ErrorCallback(Src.begin(), "Expected .id0_" ); |
104 | |
105 | auto ExpectInt = [&](StringRef &Src, int64_t Offset) -> int64_t { |
106 | int64_t Dep; |
107 | if (!Src.consumeInteger(Radix: 10, Result&: Dep)) |
108 | return Dep + Offset; |
109 | |
110 | return -1; |
111 | }; |
112 | |
113 | auto DecodeDelay = [&](StringRef &Src) -> int64_t { |
114 | if (Src.consume_front(Prefix: "NONE" )) |
115 | return 0; |
116 | if (Src.consume_front(Prefix: "VALU_DEP_" )) |
117 | return ExpectInt(Src, 0); |
118 | if (Src.consume_front(Prefix: "TRANS32_DEP_" )) |
119 | return ExpectInt(Src, 4); |
120 | if (Src.consume_front(Prefix: "SALU_CYCLE_" )) |
121 | return ExpectInt(Src, 8); |
122 | |
123 | return -1; |
124 | }; |
125 | |
126 | int64_t Delay0 = DecodeDelay(Src); |
127 | int64_t Skip = 0; |
128 | int64_t Delay1 = 0; |
129 | if (Delay0 == -1) |
130 | return ErrorCallback(Src.begin(), "Could not decode delay0" ); |
131 | |
132 | |
133 | // Set the Imm so far, to that early return has the correct value. |
134 | Imm = Delay0; |
135 | |
136 | // If that was the end of the string, the second instruction is "same" and |
137 | // "none" |
138 | if (Src.begin() == Src.end()) |
139 | return false; |
140 | |
141 | Expected = Src.consume_front(Prefix: "_skip_" ); |
142 | if (!Expected) |
143 | return ErrorCallback(Src.begin(), "Expected _skip_" ); |
144 | |
145 | |
146 | if (Src.consume_front(Prefix: "SAME" )) { |
147 | Skip = 0; |
148 | } else if (Src.consume_front(Prefix: "NEXT" )) { |
149 | Skip = 1; |
150 | } else if (Src.consume_front(Prefix: "SKIP_" )) { |
151 | if (Src.consumeInteger(Radix: 10, Result&: Skip)) { |
152 | return ErrorCallback(Src.begin(), "Expected integer Skip value" ); |
153 | } |
154 | Skip += 1; |
155 | } else { |
156 | ErrorCallback(Src.begin(), "Unexpected Skip Value" ); |
157 | } |
158 | |
159 | Expected = Src.consume_front(Prefix: "_id1_" ); |
160 | if (!Expected) |
161 | return ErrorCallback(Src.begin(), "Expected _id1_" ); |
162 | |
163 | Delay1 = DecodeDelay(Src); |
164 | if (Delay1 == -1) |
165 | return ErrorCallback(Src.begin(), "Could not decode delay1" ); |
166 | |
167 | Imm = Imm | (Skip << 4) | (Delay1 << 7); |
168 | return false; |
169 | } |
170 | |
171 | bool AMDGPUMIRFormatter::parseCustomPseudoSourceValue( |
172 | StringRef Src, MachineFunction &MF, PerFunctionMIParsingState &PFS, |
173 | const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const { |
174 | SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); |
175 | const AMDGPUTargetMachine &TM = |
176 | static_cast<const AMDGPUTargetMachine &>(MF.getTarget()); |
177 | if (Src == "GWSResource" ) { |
178 | PSV = MFI->getGWSPSV(TM); |
179 | return false; |
180 | } |
181 | llvm_unreachable("unknown MIR custom pseudo source value" ); |
182 | } |
183 | |