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(".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(10, Dep)) 108 return Dep + Offset; 109 110 return -1; 111 }; 112 113 auto DecodeDelay = [&](StringRef &Src) -> int64_t { 114 if (Src.consume_front("NONE")) 115 return 0; 116 if (Src.consume_front("VALU_DEP_")) 117 return ExpectInt(Src, 0); 118 if (Src.consume_front("TRANS32_DEP_")) 119 return ExpectInt(Src, 4); 120 if (Src.consume_front("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("_skip_"); 142 if (!Expected) 143 return ErrorCallback(Src.begin(), "Expected _skip_"); 144 145 146 if (Src.consume_front("SAME")) { 147 Skip = 0; 148 } else if (Src.consume_front("NEXT")) { 149 Skip = 1; 150 } else if (Src.consume_front("SKIP_")) { 151 if (Src.consumeInteger(10, 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("_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