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