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