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