diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp @@ -287,9 +287,19 @@ } void AMDGPUDAGToDAGISel::PreprocessISelDAG() { - if (!Subtarget->d16PreservesUnusedBits()) - return; + auto doMatchLoadD16 = std::function( + [&](SDNode *) {return false;} + ); + + if (Subtarget->d16PreservesUnusedBits()) { + doMatchLoadD16 = [&](SDNode * N) { + assert(N->getOpcode() == ISD::BUILD_VECTOR); + return matchLoadD16FromBuildVector(N); + }; + } + + auto Chains = SmallVector(); SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); bool MadeChange = false; @@ -300,13 +310,41 @@ switch (N->getOpcode()) { case ISD::BUILD_VECTOR: - MadeChange |= matchLoadD16FromBuildVector(N); + MadeChange |= doMatchLoadD16(N); break; + case AMDGPUISD::ILLEGAL: { + // Create an `ILLEGAL` node without any value types to replace `N`. + auto DL = SDLoc(N); + auto Repl = CurDAG->getNode(AMDGPUISD::ILLEGAL, DL, MVT::Other); + Chains.push_back(Repl); + + // Replace all uses of return value with a constant to break + // remaining dependencies. + auto VT = N->getValueType(0u); + assert(VT.isSimple()); + auto RetVal = [&]() { + if (VT.isFloatingPoint()) { + return CurDAG->getConstantFP(0.0, DL, VT); + } + return CurDAG->getConstant(0u, DL, VT); + }(); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0u), RetVal); + + MadeChange = true; + break; + } default: break; } } + if (!Chains.empty()) { + // Merge chains and update root. + Chains.push_back(CurDAG->getRoot()); + auto Root = CurDAG->getTokenFactor(SDLoc(Chains.back()), Chains); + CurDAG->setRoot(Root); + } + if (MadeChange) { CurDAG->RemoveDeadNodes(); LLVM_DEBUG(dbgs() << "After PreProcess:\n"; @@ -707,6 +745,15 @@ SelectINTRINSIC_VOID(N); return; } + case AMDGPUISD::ILLEGAL: { + // At this point `ILLEGAL` should have no parameters or uses. Replace + // it with `V_ILLEGAL`. + auto DL = SDLoc(N); + auto VT = N->getValueType(0u); + auto Repl = CurDAG->getMachineNode(AMDGPU::V_ILLEGAL, DL, VT); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0u), SDValue(Repl, 0u)); + return; + } } SelectCode(N); diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -536,6 +536,8 @@ BUFFER_ATOMIC_FMIN, BUFFER_ATOMIC_FMAX, + ILLEGAL, + LAST_AMDGPU_ISD_NUMBER }; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -4408,6 +4408,8 @@ NODE_NAME_CASE(BUFFER_ATOMIC_FMIN) NODE_NAME_CASE(BUFFER_ATOMIC_FMAX) + NODE_NAME_CASE(ILLEGAL) + case AMDGPUISD::LAST_AMDGPU_ISD_NUMBER: break; } return nullptr; diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -6271,7 +6271,7 @@ MVT LoadVT = ResultTypes[0].getSimpleVT(); if (LoadVT.getScalarType() == MVT::f16) { if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16) - return Op; // D16 is unsupported for this instruction + return {}; // D16 is unsupported for this instruction IsD16 = true; } @@ -6505,9 +6505,7 @@ if (Subtarget->hasGFX90AInsts()) { Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx90a, NumVDataDwords, NumVAddrDwords); - if (Opcode == -1) - report_fatal_error( - "requested image instruction is not supported on this GPU"); + return Op; } if (Opcode == -1 && Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) @@ -7686,14 +7684,21 @@ M->getVTList(), Ops, M->getMemoryVT(), M->getMemOperand()); } - default: - - if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr = - AMDGPU::getImageDimIntrinsicInfo(IntrID)) - return lowerImage(Op, ImageDimIntr, DAG, true); + default: break; + } - return SDValue(); + // Attempt to lower image intrinsic. + if (auto ImageDimIntr = AMDGPU::getImageDimIntrinsicInfo(IntrID)) { + auto Result = lowerImage(Op, ImageDimIntr, DAG, true); + if (Result != Op) { + return Result; + } } + + // Failing to lower a target specific intrinsic is a fatal error. Emit + // `ILLEGAL` so compilation can continue. + auto VTs = Op.getNode()->getVTList(); + return DAG.getNode(AMDGPUISD::ILLEGAL, DL, VTs); } // Call DAG.getMemIntrinsicNode for a load, but first widen a dwordx3 type to diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td --- a/llvm/lib/Target/AMDGPU/SIInstructions.td +++ b/llvm/lib/Target/AMDGPU/SIInstructions.td @@ -3258,3 +3258,13 @@ let InOperandList = (ins type1:$src0); let hasSideEffects = 0; } + +//============================================================================// +// Dummy Instructions +//============================================================================// + +def V_ILLEGAL : Enc32, InstSI<(outs), (ins), "v_illegal"> { + let Inst{31-0} = 0; + let FixedSize = 1; + let Uses = [EXEC]; +}