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
17using namespace llvm;
18
19void 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.
35bool 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
50void 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
93bool 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
170bool 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