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
18using namespace llvm;
19
20void 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.
36bool 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
51void 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
94bool 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
171bool 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