diff options
Diffstat (limited to 'llvm/lib/Target/AMDGPU/SIISelLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 1288 |
1 files changed, 908 insertions, 380 deletions
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index b632c50dae0e..6cf2055c8e56 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -27,7 +27,7 @@ #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/ByteProvider.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" -#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" +#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h" #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -61,6 +61,14 @@ static cl::opt<bool> UseDivergentRegisterIndexing( cl::desc("Use indirect register addressing for divergent indexes"), cl::init(false)); +// TODO: This option should be removed once we switch to always using PTRADD in +// the SelectionDAG. +static cl::opt<bool> UseSelectionDAGPTRADD( + "amdgpu-use-sdag-ptradd", cl::Hidden, + cl::desc("Generate ISD::PTRADD nodes for 64-bit pointer arithmetic in the " + "SelectionDAG ISel"), + cl::init(false)); + static bool denormalModeIsFlushAllF32(const MachineFunction &MF) { const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); return Info->getMode().FP32Denormals == DenormalMode::getPreserveSign(); @@ -523,8 +531,9 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction({ISD::SADDSAT, ISD::SSUBSAT}, {MVT::i16, MVT::i32}, Legal); - setOperationAction({ISD::FMINNUM, ISD::FMAXNUM}, {MVT::f32, MVT::f64}, - Custom); + setOperationAction( + {ISD::FMINNUM, ISD::FMAXNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM}, + {MVT::f32, MVT::f64}, Custom); // These are really only legal for ieee_mode functions. We should be avoiding // them for functions that don't have ieee_mode enabled, so just say they are @@ -582,7 +591,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, MVT::i16, Custom); setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i16, Custom); - setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i16, Custom); + setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i1, Custom); setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i32, Custom); @@ -751,12 +760,21 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::BUILD_VECTOR, {MVT::v2i16, MVT::v2f16, MVT::v2bf16}, Subtarget->hasVOP3PInsts() ? Legal : Custom); - setOperationAction(ISD::FNEG, MVT::v2f16, Legal); + setOperationAction(ISD::FNEG, {MVT::v2f16, MVT::v2bf16}, Legal); // This isn't really legal, but this avoids the legalizer unrolling it (and // allows matching fneg (fabs x) patterns) - setOperationAction(ISD::FABS, MVT::v2f16, Legal); + setOperationAction(ISD::FABS, {MVT::v2f16, MVT::v2bf16}, Legal); + + // Can do this in one BFI plus a constant materialize. + setOperationAction(ISD::FCOPYSIGN, + {MVT::v2f16, MVT::v2bf16, MVT::v4f16, MVT::v4bf16, + MVT::v8f16, MVT::v8bf16, MVT::v16f16, MVT::v16bf16, + MVT::v32f16, MVT::v32bf16}, + Custom); - setOperationAction({ISD::FMAXNUM, ISD::FMINNUM}, MVT::f16, Custom); + setOperationAction( + {ISD::FMAXNUM, ISD::FMINNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM}, + MVT::f16, Custom); setOperationAction({ISD::FMAXNUM_IEEE, ISD::FMINNUM_IEEE}, MVT::f16, Legal); setOperationAction({ISD::FMINNUM_IEEE, ISD::FMAXNUM_IEEE, ISD::FMINIMUMNUM, @@ -810,8 +828,9 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FCANONICALIZE}, VT, Custom); - setOperationAction({ISD::FMAXNUM, ISD::FMINNUM}, {MVT::v2f16, MVT::v4f16}, - Custom); + setOperationAction( + {ISD::FMAXNUM, ISD::FMINNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM}, + {MVT::v2f16, MVT::v4f16}, Custom); setOperationAction(ISD::FEXP, MVT::v2f16, Custom); setOperationAction(ISD::SELECT, {MVT::v4i16, MVT::v4f16, MVT::v4bf16}, @@ -855,22 +874,31 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, if (Subtarget->hasMad64_32()) setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, MVT::i32, Custom); - if (Subtarget->hasPrefetch()) + if (Subtarget->hasPrefetch() && Subtarget->hasSafeSmemPrefetch()) setOperationAction(ISD::PREFETCH, MVT::Other, Custom); - if (Subtarget->hasIEEEMinMax()) { + if (Subtarget->hasIEEEMinimumMaximumInsts()) { setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, {MVT::f16, MVT::f32, MVT::f64, MVT::v2f16}, Legal); - setOperationAction({ISD::FMINIMUM, ISD::FMAXIMUM}, - {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16}, - Custom); } else { // FIXME: For nnan fmaximum, emit the fmaximum3 instead of fmaxnum if (Subtarget->hasMinimum3Maximum3F32()) setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f32, Legal); - if (Subtarget->hasMinimum3Maximum3PKF16()) + if (Subtarget->hasMinimum3Maximum3PKF16()) { setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::v2f16, Legal); + + // If only the vector form is available, we need to widen to a vector. + if (!Subtarget->hasMinimum3Maximum3F16()) + setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f16, Custom); + } + } + + if (Subtarget->hasVOP3PInsts()) { + // We want to break these into v2f16 pieces, not scalarize. + setOperationAction({ISD::FMINIMUM, ISD::FMAXIMUM}, + {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16}, + Custom); } setOperationAction(ISD::INTRINSIC_WO_CHAIN, @@ -906,16 +934,18 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::MUL, MVT::i1, Promote); if (Subtarget->hasBF16ConversionInsts()) { - setOperationAction(ISD::FP_ROUND, MVT::v2bf16, Legal); - setOperationAction(ISD::FP_ROUND, MVT::bf16, Legal); + setOperationAction(ISD::FP_ROUND, {MVT::bf16, MVT::v2bf16}, Custom); setOperationAction(ISD::BUILD_VECTOR, MVT::v2bf16, Legal); } if (Subtarget->hasCvtPkF16F32Inst()) { - setOperationAction(ISD::FP_ROUND, MVT::v2f16, Legal); + setOperationAction(ISD::FP_ROUND, + {MVT::v2f16, MVT::v4f16, MVT::v8f16, MVT::v16f16}, + Custom); } setTargetDAGCombine({ISD::ADD, + ISD::PTRADD, ISD::UADDO_CARRY, ISD::SUB, ISD::USUBO_CARRY, @@ -930,6 +960,8 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, ISD::FMAXNUM_IEEE, ISD::FMINIMUM, ISD::FMAXIMUM, + ISD::FMINIMUMNUM, + ISD::FMAXIMUMNUM, ISD::FMA, ISD::SMIN, ISD::SMAX, @@ -1175,19 +1207,20 @@ static EVT memVTFromLoadIntrReturn(const SITargetLowering &TLI, return memVTFromLoadIntrData(TLI, DL, ST->getContainedType(0), MaxNumLanes); } -/// Map address space 7 to MVT::v5i32 because that's its in-memory -/// representation. This return value is vector-typed because there is no -/// MVT::i160 and it is not clear if one can be added. While this could -/// cause issues during codegen, these address space 7 pointers will be -/// rewritten away by then. Therefore, we can return MVT::v5i32 in order -/// to allow pre-codegen passes that query TargetTransformInfo, often for cost -/// modeling, to work. +/// Map address space 7 to MVT::amdgpuBufferFatPointer because that's its +/// in-memory representation. This return value is a custom type because there +/// is no MVT::i160 and adding one breaks integer promotion logic. While this +/// could cause issues during codegen, these address space 7 pointers will be +/// rewritten away by then. Therefore, we can return MVT::amdgpuBufferFatPointer +/// in order to allow pre-codegen passes that query TargetTransformInfo, often +/// for cost modeling, to work. (This also sets us up decently for doing the +/// buffer lowering in GlobalISel if SelectionDAG ever goes away.) MVT SITargetLowering::getPointerTy(const DataLayout &DL, unsigned AS) const { if (AMDGPUAS::BUFFER_FAT_POINTER == AS && DL.getPointerSizeInBits(AS) == 160) - return MVT::v5i32; + return MVT::amdgpuBufferFatPointer; if (AMDGPUAS::BUFFER_STRIDED_POINTER == AS && DL.getPointerSizeInBits(AS) == 192) - return MVT::v6i32; + return MVT::amdgpuBufferStridedPointer; return AMDGPUTargetLowering::getPointerTy(DL, AS); } /// Similarly, the in-memory representation of a p7 is {p8, i32}, aka @@ -1216,8 +1249,8 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, if (const AMDGPU::RsrcIntrinsic *RsrcIntr = AMDGPU::lookupRsrcIntrinsic(IntrID)) { - AttributeList Attr = - Intrinsic::getAttributes(CI.getContext(), (Intrinsic::ID)IntrID); + AttributeSet Attr = + Intrinsic::getFnAttributes(CI.getContext(), (Intrinsic::ID)IntrID); MemoryEffects ME = Attr.getMemoryEffects(); if (ME.doesNotAccessMemory()) return false; @@ -1371,6 +1404,19 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, return true; } + case Intrinsic::amdgcn_ds_atomic_async_barrier_arrive_b64: + case Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64: { + Info.opc = (IntrID == Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64) + ? ISD::INTRINSIC_W_CHAIN + : ISD::INTRINSIC_VOID; + Info.memVT = MVT::getVT(CI.getType()); + Info.ptrVal = CI.getOperand(0); + Info.memVT = MVT::i64; + Info.size = 8; + Info.align.reset(); + Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore; + return true; + } case Intrinsic::amdgcn_global_atomic_csub: { Info.opc = ISD::INTRINSIC_W_CHAIN; Info.memVT = MVT::getVT(CI.getType()); @@ -1380,9 +1426,15 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, MachineMemOperand::MOVolatile; return true; } - case Intrinsic::amdgcn_image_bvh_intersect_ray: { + case Intrinsic::amdgcn_image_bvh_dual_intersect_ray: + case Intrinsic::amdgcn_image_bvh_intersect_ray: + case Intrinsic::amdgcn_image_bvh8_intersect_ray: { Info.opc = ISD::INTRINSIC_W_CHAIN; - Info.memVT = MVT::getVT(CI.getType()); // XXX: what is correct VT? + Info.memVT = + MVT::getVT(IntrID == Intrinsic::amdgcn_image_bvh_intersect_ray + ? CI.getType() + : cast<StructType>(CI.getType()) + ->getElementType(0)); // XXX: what is correct VT? Info.fallbackAddressSpace = AMDGPUAS::BUFFER_RESOURCE; Info.align.reset(); @@ -1405,6 +1457,12 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, MachineMemOperand::MOVolatile; return true; } + case Intrinsic::amdgcn_ds_load_tr6_b96: + case Intrinsic::amdgcn_ds_load_tr4_b64: + case Intrinsic::amdgcn_ds_load_tr8_b64: + case Intrinsic::amdgcn_ds_load_tr16_b128: + case Intrinsic::amdgcn_global_load_tr6_b96: + case Intrinsic::amdgcn_global_load_tr4_b64: case Intrinsic::amdgcn_global_load_tr_b64: case Intrinsic::amdgcn_global_load_tr_b128: case Intrinsic::amdgcn_ds_read_tr4_b64: @@ -1443,6 +1501,7 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, Info.flags |= MachineMemOperand::MOStore; return true; } + case Intrinsic::amdgcn_load_to_lds: case Intrinsic::amdgcn_global_load_lds: { Info.opc = ISD::INTRINSIC_VOID; unsigned Width = cast<ConstantInt>(CI.getArgOperand(2))->getZExtValue(); @@ -1451,7 +1510,10 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore; return true; } - case Intrinsic::amdgcn_ds_bvh_stack_rtn: { + case Intrinsic::amdgcn_ds_bvh_stack_rtn: + case Intrinsic::amdgcn_ds_bvh_stack_push4_pop1_rtn: + case Intrinsic::amdgcn_ds_bvh_stack_push8_pop1_rtn: + case Intrinsic::amdgcn_ds_bvh_stack_push8_pop2_rtn: { Info.opc = ISD::INTRINSIC_W_CHAIN; const GCNTargetMachine &TM = @@ -1505,12 +1567,18 @@ bool SITargetLowering::getAddrModeArguments(const IntrinsicInst *II, case Intrinsic::amdgcn_atomic_cond_sub_u32: case Intrinsic::amdgcn_ds_append: case Intrinsic::amdgcn_ds_consume: + case Intrinsic::amdgcn_ds_load_tr8_b64: + case Intrinsic::amdgcn_ds_load_tr16_b128: + case Intrinsic::amdgcn_ds_load_tr4_b64: + case Intrinsic::amdgcn_ds_load_tr6_b96: case Intrinsic::amdgcn_ds_read_tr4_b64: case Intrinsic::amdgcn_ds_read_tr6_b96: case Intrinsic::amdgcn_ds_read_tr8_b64: case Intrinsic::amdgcn_ds_read_tr16_b64: case Intrinsic::amdgcn_ds_ordered_add: case Intrinsic::amdgcn_ds_ordered_swap: + case Intrinsic::amdgcn_ds_atomic_async_barrier_arrive_b64: + case Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64: case Intrinsic::amdgcn_flat_atomic_fmax_num: case Intrinsic::amdgcn_flat_atomic_fmin_num: case Intrinsic::amdgcn_global_atomic_csub: @@ -1519,8 +1587,11 @@ bool SITargetLowering::getAddrModeArguments(const IntrinsicInst *II, case Intrinsic::amdgcn_global_atomic_ordered_add_b64: case Intrinsic::amdgcn_global_load_tr_b64: case Intrinsic::amdgcn_global_load_tr_b128: + case Intrinsic::amdgcn_global_load_tr4_b64: + case Intrinsic::amdgcn_global_load_tr6_b96: Ptr = II->getArgOperand(0); break; + case Intrinsic::amdgcn_load_to_lds: case Intrinsic::amdgcn_global_load_lds: Ptr = II->getArgOperand(1); break; @@ -1877,6 +1948,20 @@ bool SITargetLowering::allowsMisalignedMemoryAccessesImpl( Subtarget->hasUnalignedBufferAccessEnabled(); } + // Ensure robust out-of-bounds guarantees for buffer accesses are met if + // RelaxedBufferOOBMode is disabled. Normally hardware will ensure proper + // out-of-bounds behavior, but in the edge case where an access starts + // out-of-bounds and then enter in-bounds, the entire access would be treated + // as out-of-bounds. Prevent misaligned memory accesses by requiring the + // natural alignment of buffer accesses. + if (AddrSpace == AMDGPUAS::BUFFER_FAT_POINTER || + AddrSpace == AMDGPUAS::BUFFER_RESOURCE || + AddrSpace == AMDGPUAS::BUFFER_STRIDED_POINTER) { + if (!Subtarget->hasRelaxedBufferOOBMode() && + Alignment < Align(PowerOf2Ceil(divideCeil(Size, 8)))) + return false; + } + // Smaller than dword value must be aligned. if (Size < 32) return false; @@ -1898,7 +1983,8 @@ bool SITargetLowering::allowsMisalignedMemoryAccesses( } EVT SITargetLowering::getOptimalMemOpType( - const MemOp &Op, const AttributeList &FuncAttributes) const { + LLVMContext &Context, const MemOp &Op, + const AttributeList &FuncAttributes) const { // FIXME: Should account for address space here. // The default fallback uses the private pointer size as a guess for a type to @@ -2202,7 +2288,7 @@ SDValue SITargetLowering::getPreloadedValue( // It's undefined behavior if a function marked with the amdgpu-no-* // attributes uses the corresponding intrinsic. - return DAG.getUNDEF(VT); + return DAG.getPOISON(VT); } return loadInputValue(DAG, RC, VT, SDLoc(DAG.getEntryNode()), *Reg); @@ -2402,7 +2488,7 @@ void SITargetLowering::allocateSpecialInputVGPRsFixed( SIMachineFunctionInfo &Info) const { Register Reg = CCInfo.AllocateReg(AMDGPU::VGPR31); if (!Reg) - report_fatal_error("failed to allocated VGPR for implicit arguments"); + report_fatal_error("failed to allocate VGPR for implicit arguments"); const unsigned Mask = 0x3ff; Info.setWorkItemIDX(ArgDescriptor::createRegister(Reg, Mask)); @@ -2822,12 +2908,12 @@ SDValue SITargetLowering::LowerFormalArguments( const Function &Fn = MF.getFunction(); FunctionType *FType = MF.getFunction().getFunctionType(); SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); + bool IsError = false; if (Subtarget->isAmdHsaOS() && AMDGPU::isGraphics(CallConv)) { - DiagnosticInfoUnsupported NoGraphicsHSA( - Fn, "unsupported non-compute shaders with HSA", DL.getDebugLoc()); - DAG.getContext()->diagnose(NoGraphicsHSA); - return DAG.getEntryNode(); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + Fn, "unsupported non-compute shaders with HSA", DL.getDebugLoc())); + IsError = true; } SmallVector<ISD::InputArg, 16> Splits; @@ -2936,8 +3022,8 @@ SDValue SITargetLowering::LowerFormalArguments( for (unsigned i = 0, e = Ins.size(), ArgIdx = 0; i != e; ++i) { const ISD::InputArg &Arg = Ins[i]; - if (Arg.isOrigArg() && Skipped[Arg.getOrigArgIndex()]) { - InVals.push_back(DAG.getUNDEF(Arg.VT)); + if ((Arg.isOrigArg() && Skipped[Arg.getOrigArgIndex()]) || IsError) { + InVals.push_back(DAG.getPOISON(Arg.VT)); continue; } @@ -3050,11 +3136,10 @@ SDValue SITargetLowering::LowerFormalArguments( if (Arg.isOrigArg()) { Argument *OrigArg = Fn.getArg(Arg.getOrigArgIndex()); if (OrigArg->hasAttribute("amdgpu-hidden-argument")) { - DiagnosticInfoUnsupported NonPreloadHiddenArg( + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( *OrigArg->getParent(), "hidden argument in kernel signature was not preloaded", - DL.getDebugLoc()); - DAG.getContext()->diagnose(NonPreloadHiddenArg); + DL.getDebugLoc())); } } @@ -3196,6 +3281,7 @@ SITargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, const SDLoc &DL, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); + const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo(); if (AMDGPU::isKernel(CallConv)) { return AMDGPUTargetLowering::LowerReturn(Chain, CallConv, isVarArg, Outs, @@ -3209,7 +3295,6 @@ SITargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, // CCValAssign - represent the assignment of the return value to a location. SmallVector<CCValAssign, 48> RVLocs; - SmallVector<ISD::OutputArg, 48> Splits; // CCState - Info about the registers and stack slots. CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, @@ -3222,6 +3307,8 @@ SITargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, SmallVector<SDValue, 48> RetOps; RetOps.push_back(Chain); // Operand #0 = Chain (updated below) + SDValue ReadFirstLane = + DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, DL, MVT::i32); // Copy the result values into the output registers. for (unsigned I = 0, RealRVLocIdx = 0, E = RVLocs.size(); I != E; ++I, ++RealRVLocIdx) { @@ -3249,7 +3336,9 @@ SITargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, default: llvm_unreachable("Unknown loc info!"); } - + if (TRI->isSGPRPhysReg(VA.getLocReg())) + Arg = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Arg.getValueType(), + ReadFirstLane, Arg); Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Arg, Glue); Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); @@ -3416,12 +3505,12 @@ void SITargetLowering::passSpecialInputs( if (Id.has_value()) { InputReg = DAG.getConstant(*Id, DL, ArgVT); } else { - InputReg = DAG.getUNDEF(ArgVT); + InputReg = DAG.getPOISON(ArgVT); } } else { // We may have proven the input wasn't needed, although the ABI is // requiring it. We just need to allocate the register appropriately. - InputReg = DAG.getUNDEF(ArgVT); + InputReg = DAG.getPOISON(ArgVT); } if (OutgoingArg->isRegister()) { @@ -3501,7 +3590,7 @@ void SITargetLowering::passSpecialInputs( // ID, but the calling function does not have it (e.g a graphics function // calling a C calling convention function). This is illegal, but we need // to produce something. - InputReg = DAG.getUNDEF(MVT::i32); + InputReg = DAG.getPOISON(MVT::i32); } else { // Workitem ids are already packed, any of present incoming arguments // will carry all required fields. @@ -3529,21 +3618,6 @@ void SITargetLowering::passSpecialInputs( } } -static bool canGuaranteeTCO(CallingConv::ID CC) { - return CC == CallingConv::Fast; -} - -/// Return true if we might ever do TCO for calls with this calling convention. -static bool mayTailCallThisCC(CallingConv::ID CC) { - switch (CC) { - case CallingConv::C: - case CallingConv::AMDGPU_Gfx: - return true; - default: - return canGuaranteeTCO(CC); - } -} - bool SITargetLowering::isEligibleForTailCallOptimization( SDValue Callee, CallingConv::ID CalleeCC, bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, @@ -3552,7 +3626,7 @@ bool SITargetLowering::isEligibleForTailCallOptimization( if (AMDGPU::isChainCC(CalleeCC)) return true; - if (!mayTailCallThisCC(CalleeCC)) + if (!AMDGPU::mayTailCallThisCC(CalleeCC)) return false; // For a divergent call target, we need to do a waterfall loop over the @@ -3574,7 +3648,7 @@ bool SITargetLowering::isEligibleForTailCallOptimization( bool CCMatch = CallerCC == CalleeCC; if (DAG.getTarget().Options.GuaranteedTailCallOpt) { - if (canGuaranteeTCO(CalleeCC) && CCMatch) + if (AMDGPU::canGuaranteeTCO(CalleeCC) && CCMatch) return true; return false; } @@ -3650,6 +3724,19 @@ bool SITargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { return true; } +namespace { +// Chain calls have special arguments that we need to handle. These are +// tagging along at the end of the arguments list(s), after the SGPR and VGPR +// arguments (index 0 and 1 respectively). +enum ChainCallArgIdx { + Exec = 2, + Flags, + NumVGPRs, + FallbackExec, + FallbackCallee +}; +} // anonymous namespace + // The wave scratch offset register is used as the global base pointer. SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const { @@ -3658,37 +3745,75 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, SelectionDAG &DAG = CLI.DAG; - TargetLowering::ArgListEntry RequestedExec; + const SDLoc &DL = CLI.DL; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + + llvm::SmallVector<SDValue, 6> ChainCallSpecialArgs; + bool UsesDynamicVGPRs = false; if (IsChainCallConv) { - // The last argument should be the value that we need to put in EXEC. - // Pop it out of CLI.Outs and CLI.OutVals before we do any processing so we - // don't treat it like the rest of the arguments. - RequestedExec = CLI.Args.back(); - assert(RequestedExec.Node && "No node for EXEC"); + // The last arguments should be the value that we need to put in EXEC, + // followed by the flags and any other arguments with special meanings. + // Pop them out of CLI.Outs and CLI.OutVals before we do any processing so + // we don't treat them like the "real" arguments. + auto RequestedExecIt = + llvm::find_if(CLI.Outs, [](const ISD::OutputArg &Arg) { + return Arg.OrigArgIndex == 2; + }); + assert(RequestedExecIt != CLI.Outs.end() && "No node for EXEC"); - if (!RequestedExec.Ty->isIntegerTy(Subtarget->getWavefrontSize())) + size_t SpecialArgsBeginIdx = RequestedExecIt - CLI.Outs.begin(); + CLI.OutVals.erase(CLI.OutVals.begin() + SpecialArgsBeginIdx, + CLI.OutVals.end()); + CLI.Outs.erase(RequestedExecIt, CLI.Outs.end()); + + assert(CLI.Outs.back().OrigArgIndex < 2 && + "Haven't popped all the special args"); + + TargetLowering::ArgListEntry RequestedExecArg = + CLI.Args[ChainCallArgIdx::Exec]; + if (!RequestedExecArg.Ty->isIntegerTy(Subtarget->getWavefrontSize())) return lowerUnhandledCall(CLI, InVals, "Invalid value for EXEC"); - assert(CLI.Outs.back().OrigArgIndex == 2 && "Unexpected last arg"); - CLI.Outs.pop_back(); - CLI.OutVals.pop_back(); + // Convert constants into TargetConstants, so they become immediate operands + // instead of being selected into S_MOV. + auto PushNodeOrTargetConstant = [&](TargetLowering::ArgListEntry Arg) { + if (const auto *ArgNode = dyn_cast<ConstantSDNode>(Arg.Node)) { + ChainCallSpecialArgs.push_back(DAG.getTargetConstant( + ArgNode->getAPIntValue(), DL, ArgNode->getValueType(0))); + } else + ChainCallSpecialArgs.push_back(Arg.Node); + }; - if (RequestedExec.Ty->isIntegerTy(64)) { - assert(CLI.Outs.back().OrigArgIndex == 2 && "Exec wasn't split up"); - CLI.Outs.pop_back(); - CLI.OutVals.pop_back(); - } + PushNodeOrTargetConstant(RequestedExecArg); + + // Process any other special arguments depending on the value of the flags. + TargetLowering::ArgListEntry Flags = CLI.Args[ChainCallArgIdx::Flags]; + + const APInt &FlagsValue = cast<ConstantSDNode>(Flags.Node)->getAPIntValue(); + if (FlagsValue.isZero()) { + if (CLI.Args.size() > ChainCallArgIdx::Flags + 1) + return lowerUnhandledCall(CLI, InVals, + "no additional args allowed if flags == 0"); + } else if (FlagsValue.isOneBitSet(0)) { + if (CLI.Args.size() != ChainCallArgIdx::FallbackCallee + 1) { + return lowerUnhandledCall(CLI, InVals, "expected 3 additional args"); + } - assert(CLI.Outs.back().OrigArgIndex != 2 && - "Haven't popped all the pieces of the EXEC mask"); + if (!Subtarget->isWave32()) { + return lowerUnhandledCall( + CLI, InVals, "dynamic VGPR mode is only supported for wave32"); + } + + UsesDynamicVGPRs = true; + std::for_each(CLI.Args.begin() + ChainCallArgIdx::NumVGPRs, + CLI.Args.end(), PushNodeOrTargetConstant); + } } - const SDLoc &DL = CLI.DL; SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs; SmallVector<SDValue, 32> &OutVals = CLI.OutVals; SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins; - SDValue Chain = CLI.Chain; - SDValue Callee = CLI.Callee; bool &IsTailCall = CLI.IsTailCall; bool IsVarArg = CLI.IsVarArg; bool IsSibCall = false; @@ -3697,7 +3822,7 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, if (Callee.isUndef() || isNullConstant(Callee)) { if (!CLI.IsTailCall) { for (ISD::InputArg &Arg : CLI.Ins) - InVals.push_back(DAG.getUNDEF(Arg.VT)); + InVals.push_back(DAG.getPOISON(Arg.VT)); } return Chain; @@ -3709,7 +3834,7 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, } if (!CLI.CB) - report_fatal_error("unsupported libcall legalization"); + return lowerUnhandledCall(CLI, InVals, "unsupported libcall legalization"); if (IsTailCall && MF.getTarget().Options.GuaranteedTailCallOpt) { return lowerUnhandledCall(CLI, InVals, @@ -3768,7 +3893,7 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, // arguments to begin at SP+0. Completely unused for non-tail calls. int32_t FPDiff = 0; MachineFrameInfo &MFI = MF.getFrameInfo(); - auto *TRI = static_cast<const SIRegisterInfo *>(Subtarget->getRegisterInfo()); + auto *TRI = Subtarget->getRegisterInfo(); // Adjust the stack pointer for the new arguments... // These operations are automatically eliminated by the prolog/epilog pass @@ -3976,7 +4101,7 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, } if (IsChainCallConv) - Ops.push_back(RequestedExec.Node); + llvm::append_range(Ops, ChainCallSpecialArgs); // Add argument registers to the end of the list so that they are known live // into the call. @@ -4013,7 +4138,8 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI, break; case CallingConv::AMDGPU_CS_Chain: case CallingConv::AMDGPU_CS_ChainPreserve: - OPC = AMDGPUISD::TC_RETURN_CHAIN; + OPC = UsesDynamicVGPRs ? AMDGPUISD::TC_RETURN_CHAIN_DVGPR + : AMDGPUISD::TC_RETURN_CHAIN; break; } @@ -4384,6 +4510,8 @@ SDValue SITargetLowering::lowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const { Register SITargetLowering::getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const { + const Function &Fn = MF.getFunction(); + Register Reg = StringSwitch<Register>(RegName) .Case("m0", AMDGPU::M0) .Case("exec", AMDGPU::EXEC) @@ -4393,16 +4521,13 @@ Register SITargetLowering::getRegisterByName(const char *RegName, LLT VT, .Case("flat_scratch_lo", AMDGPU::FLAT_SCR_LO) .Case("flat_scratch_hi", AMDGPU::FLAT_SCR_HI) .Default(Register()); - - if (Reg == AMDGPU::NoRegister) { - report_fatal_error( - Twine("invalid register name \"" + StringRef(RegName) + "\".")); - } + if (!Reg) + return Reg; if (!Subtarget->hasFlatScrRegister() && Subtarget->getRegisterInfo()->regsOverlap(Reg, AMDGPU::FLAT_SCR)) { - report_fatal_error(Twine("invalid register \"" + StringRef(RegName) + - "\" for subtarget.")); + Fn.getContext().emitError(Twine("invalid register \"" + StringRef(RegName) + + "\" for subtarget.")); } switch (Reg) { @@ -4432,7 +4557,7 @@ Register SITargetLowering::getRegisterByName(const char *RegName, LLT VT, MachineBasicBlock * SITargetLowering::splitKillBlock(MachineInstr &MI, MachineBasicBlock *BB) const { - MachineBasicBlock *SplitBB = BB->splitAt(MI, false /*UpdateLiveIns*/); + MachineBasicBlock *SplitBB = BB->splitAt(MI, /*UpdateLiveIns=*/true); const SIInstrInfo *TII = getSubtarget()->getInstrInfo(); MI.setDesc(TII->getKillTerminatorFromPseudo(MI.getOpcode())); return SplitBB; @@ -4563,7 +4688,8 @@ emitLoadM0FromVGPRLoop(const SIInstrInfo *TII, MachineRegisterInfo &MRI, const TargetRegisterClass *BoolRC = TRI->getBoolRC(); Register PhiExec = MRI.createVirtualRegister(BoolRC); Register NewExec = MRI.createVirtualRegister(BoolRC); - Register CurrentIdxReg = MRI.createVirtualRegister(&AMDGPU::SGPR_32RegClass); + Register CurrentIdxReg = + MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); Register CondReg = MRI.createVirtualRegister(BoolRC); BuildMI(LoopBB, I, DL, TII->get(TargetOpcode::PHI), PhiReg) @@ -4608,7 +4734,7 @@ emitLoadM0FromVGPRLoop(const SIInstrInfo *TII, MachineRegisterInfo &MRI, } else { // Move index from VCC into M0 if (Offset == 0) { - BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0) + BuildMI(LoopBB, I, DL, TII->get(AMDGPU::COPY), AMDGPU::M0) .addReg(CurrentIdxReg, RegState::Kill); } else { BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0) @@ -4722,7 +4848,7 @@ static void setM0ToIndexFromSGPR(const SIInstrInfo *TII, if (Offset == 0) { // clang-format off - BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0) + BuildMI(*MBB, I, DL, TII->get(AMDGPU::COPY), AMDGPU::M0) .add(*Idx); // clang-format on } else { @@ -4940,6 +5066,28 @@ static MachineBasicBlock *emitIndirectDst(MachineInstr &MI, return LoopBB; } +static uint32_t getIdentityValueForWaveReduction(unsigned Opc) { + switch (Opc) { + case AMDGPU::S_MIN_U32: + return std::numeric_limits<uint32_t>::max(); + case AMDGPU::S_MIN_I32: + return std::numeric_limits<int32_t>::max(); + case AMDGPU::S_MAX_U32: + return std::numeric_limits<uint32_t>::min(); + case AMDGPU::S_MAX_I32: + return std::numeric_limits<int32_t>::min(); + case AMDGPU::S_ADD_I32: + case AMDGPU::S_SUB_I32: + case AMDGPU::S_OR_B32: + case AMDGPU::S_XOR_B32: + return std::numeric_limits<uint32_t>::min(); + case AMDGPU::S_AND_B32: + return std::numeric_limits<uint32_t>::max(); + default: + llvm_unreachable("Unexpected opcode in getIdentityValueForWaveReduction"); + } +} + static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI, MachineBasicBlock &BB, const GCNSubtarget &ST, @@ -4955,13 +5103,78 @@ static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI, Register DstReg = MI.getOperand(0).getReg(); MachineBasicBlock *RetBB = nullptr; if (isSGPR) { - // These operations with a uniform value i.e. SGPR are idempotent. - // Reduced value will be same as given sgpr. - // clang-format off - BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstReg) - .addReg(SrcReg); - // clang-format on - RetBB = &BB; + switch (Opc) { + case AMDGPU::S_MIN_U32: + case AMDGPU::S_MIN_I32: + case AMDGPU::S_MAX_U32: + case AMDGPU::S_MAX_I32: + case AMDGPU::S_AND_B32: + case AMDGPU::S_OR_B32: { + // Idempotent operations. + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstReg).addReg(SrcReg); + RetBB = &BB; + break; + } + case AMDGPU::S_XOR_B32: + case AMDGPU::S_ADD_I32: + case AMDGPU::S_SUB_I32: { + const TargetRegisterClass *WaveMaskRegClass = TRI->getWaveMaskRegClass(); + const TargetRegisterClass *DstRegClass = MRI.getRegClass(DstReg); + Register ExecMask = MRI.createVirtualRegister(WaveMaskRegClass); + Register ActiveLanes = MRI.createVirtualRegister(DstRegClass); + + bool IsWave32 = ST.isWave32(); + unsigned MovOpc = IsWave32 ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64; + MCRegister ExecReg = IsWave32 ? AMDGPU::EXEC_LO : AMDGPU::EXEC; + unsigned CountReg = + IsWave32 ? AMDGPU::S_BCNT1_I32_B32 : AMDGPU::S_BCNT1_I32_B64; + + auto Exec = + BuildMI(BB, MI, DL, TII->get(MovOpc), ExecMask).addReg(ExecReg); + + auto NewAccumulator = BuildMI(BB, MI, DL, TII->get(CountReg), ActiveLanes) + .addReg(Exec->getOperand(0).getReg()); + + switch (Opc) { + case AMDGPU::S_XOR_B32: { + // Performing an XOR operation on a uniform value + // depends on the parity of the number of active lanes. + // For even parity, the result will be 0, for odd + // parity the result will be the same as the input value. + Register ParityRegister = MRI.createVirtualRegister(DstRegClass); + + auto ParityReg = + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_AND_B32), ParityRegister) + .addReg(NewAccumulator->getOperand(0).getReg()) + .addImm(1); + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg) + .addReg(SrcReg) + .addReg(ParityReg->getOperand(0).getReg()); + break; + } + case AMDGPU::S_SUB_I32: { + Register NegatedVal = MRI.createVirtualRegister(DstRegClass); + + // Take the negation of the source operand. + auto InvertedValReg = + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), NegatedVal) + .addImm(-1) + .addReg(SrcReg); + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg) + .addReg(InvertedValReg->getOperand(0).getReg()) + .addReg(NewAccumulator->getOperand(0).getReg()); + break; + } + case AMDGPU::S_ADD_I32: { + BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg) + .addReg(SrcReg) + .addReg(NewAccumulator->getOperand(0).getReg()); + break; + } + } + RetBB = &BB; + } + } } else { // TODO: Implement DPP Strategy and switch based on immediate strategy // operand. For now, for all the cases (default, Iterative and DPP we use @@ -4990,16 +5203,16 @@ static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI, Register NewActiveBitsReg = MRI.createVirtualRegister(WaveMaskRegClass); Register FF1Reg = MRI.createVirtualRegister(DstRegClass); - Register LaneValueReg = MRI.createVirtualRegister(DstRegClass); + Register LaneValueReg = + MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); bool IsWave32 = ST.isWave32(); unsigned MovOpc = IsWave32 ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64; unsigned ExecReg = IsWave32 ? AMDGPU::EXEC_LO : AMDGPU::EXEC; - // Create initail values of induction variable from Exec, Accumulator and - // insert branch instr to newly created ComputeBlockk - uint32_t InitalValue = - (Opc == AMDGPU::S_MIN_U32) ? std::numeric_limits<uint32_t>::max() : 0; + // Create initial values of induction variable from Exec, Accumulator and + // insert branch instr to newly created ComputeBlock + uint32_t InitalValue = getIdentityValueForWaveReduction(Opc); auto TmpSReg = BuildMI(BB, I, DL, TII->get(MovOpc), LoopIterator).addReg(ExecReg); BuildMI(BB, I, DL, TII->get(AMDGPU::S_MOV_B32), InitalValReg) @@ -5071,8 +5284,22 @@ SITargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, switch (MI.getOpcode()) { case AMDGPU::WAVE_REDUCE_UMIN_PSEUDO_U32: return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MIN_U32); + case AMDGPU::WAVE_REDUCE_MIN_PSEUDO_I32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MIN_I32); case AMDGPU::WAVE_REDUCE_UMAX_PSEUDO_U32: return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MAX_U32); + case AMDGPU::WAVE_REDUCE_MAX_PSEUDO_I32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MAX_I32); + case AMDGPU::WAVE_REDUCE_ADD_PSEUDO_I32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_ADD_I32); + case AMDGPU::WAVE_REDUCE_SUB_PSEUDO_I32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_SUB_I32); + case AMDGPU::WAVE_REDUCE_AND_PSEUDO_B32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_AND_B32); + case AMDGPU::WAVE_REDUCE_OR_PSEUDO_B32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_OR_B32); + case AMDGPU::WAVE_REDUCE_XOR_PSEUDO_B32: + return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_XOR_B32); case AMDGPU::S_UADDO_PSEUDO: case AMDGPU::S_USUBO_PSEUDO: { const DebugLoc &DL = MI.getDebugLoc(); @@ -5162,7 +5389,7 @@ SITargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineOperand &Src0 = MI.getOperand(1); MachineOperand &Src1 = MI.getOperand(2); - if (IsAdd && ST.hasLshlAddB64()) { + if (IsAdd && ST.hasLshlAddU64Inst()) { auto Add = BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_LSHL_ADD_U64_e64), Dest.getReg()) .add(Src0) @@ -5249,18 +5476,18 @@ SITargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32; if (Src0.isReg() && TRI->isVectorRegister(MRI, Src0.getReg())) { - Register RegOp0 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass); + Register RegOp0 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp0) .addReg(Src0.getReg()); Src0.setReg(RegOp0); } if (Src1.isReg() && TRI->isVectorRegister(MRI, Src1.getReg())) { - Register RegOp1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass); + Register RegOp1 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp1) .addReg(Src1.getReg()); Src1.setReg(RegOp1); } - Register RegOp2 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass); + Register RegOp2 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); if (TRI->isVectorRegister(MRI, Src2.getReg())) { BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp2) .addReg(Src2.getReg()); @@ -5316,12 +5543,22 @@ SITargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, return BB; } case AMDGPU::SI_INIT_M0: { + MachineOperand &M0Init = MI.getOperand(0); BuildMI(*BB, MI.getIterator(), MI.getDebugLoc(), - TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0) - .add(MI.getOperand(0)); + TII->get(M0Init.isReg() ? AMDGPU::COPY : AMDGPU::S_MOV_B32), + AMDGPU::M0) + .add(M0Init); MI.eraseFromParent(); return BB; } + case AMDGPU::S_BARRIER_SIGNAL_ISFIRST_IMM: { + // Set SCC to true, in case the barrier instruction gets converted to a NOP. + BuildMI(*BB, MI.getIterator(), MI.getDebugLoc(), + TII->get(AMDGPU::S_CMP_EQ_U32)) + .addImm(0) + .addImm(0); + return BB; + } case AMDGPU::GET_GROUPSTATICSIZE: { assert(getTargetMachine().getTargetTriple().getOS() == Triple::AMDHSA || getTargetMachine().getTargetTriple().getOS() == Triple::AMDPAL); @@ -5751,35 +5988,6 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return false; } -// Refer to comments added to the MIR variant of isFMAFasterThanFMulAndFAdd for -// specific details. -bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const Function &F, - Type *Ty) const { - switch (Ty->getScalarSizeInBits()) { - case 16: { - SIModeRegisterDefaults Mode = SIModeRegisterDefaults(F, *Subtarget); - return Subtarget->has16BitInsts() && - Mode.FP64FP16Denormals != DenormalMode::getPreserveSign(); - } - case 32: { - if (!Subtarget->hasMadMacF32Insts()) - return Subtarget->hasFastFMAF32(); - - SIModeRegisterDefaults Mode = SIModeRegisterDefaults(F, *Subtarget); - if (Mode.FP32Denormals != DenormalMode::getPreserveSign()) - return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts(); - - return Subtarget->hasFastFMAF32() && Subtarget->hasDLInsts(); - } - case 64: - return true; - default: - break; - } - - return false; -} - bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const { if (!Ty.isScalar()) return false; @@ -5839,10 +6047,12 @@ SDValue SITargetLowering::splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); EVT VT = Op.getValueType(); - assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4f32 || - VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v16i16 || - VT == MVT::v16f16 || VT == MVT::v8f32 || VT == MVT::v16f32 || - VT == MVT::v32f32 || VT == MVT::v32i16 || VT == MVT::v32f16); + assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16 || + VT == MVT::v4f32 || VT == MVT::v8i16 || VT == MVT::v8f16 || + VT == MVT::v8bf16 || VT == MVT::v16i16 || VT == MVT::v16f16 || + VT == MVT::v16bf16 || VT == MVT::v8f32 || VT == MVT::v16f32 || + VT == MVT::v32f32 || VT == MVT::v32i16 || VT == MVT::v32f16 || + VT == MVT::v32bf16); auto [Lo0, Hi0] = DAG.SplitVectorOperand(Op.getNode(), 0); auto [Lo1, Hi1] = DAG.SplitVectorOperand(Op.getNode(), 1); @@ -5963,6 +6173,12 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::FMINNUM: case ISD::FMAXNUM: return lowerFMINNUM_FMAXNUM(Op, DAG); + case ISD::FMINIMUMNUM: + case ISD::FMAXIMUMNUM: + return lowerFMINIMUMNUM_FMAXIMUMNUM(Op, DAG); + case ISD::FMINIMUM: + case ISD::FMAXIMUM: + return lowerFMINIMUM_FMAXIMUM(Op, DAG); case ISD::FLDEXP: case ISD::STRICT_FLDEXP: return lowerFLDEXP(Op, DAG); @@ -5984,15 +6200,13 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::FMUL: case ISD::FMINNUM_IEEE: case ISD::FMAXNUM_IEEE: - case ISD::FMINIMUM: - case ISD::FMAXIMUM: - case ISD::FMINIMUMNUM: - case ISD::FMAXIMUMNUM: case ISD::UADDSAT: case ISD::USUBSAT: case ISD::SADDSAT: case ISD::SSUBSAT: return splitBinaryVectorOp(Op, DAG); + case ISD::FCOPYSIGN: + return lowerFCOPYSIGN(Op, DAG); case ISD::MUL: return lowerMUL(Op, DAG); case ISD::SMULO: @@ -6053,7 +6267,7 @@ static SDValue adjustLoadValueTypeImpl(SDValue Result, EVT LoadVT, // Pad illegal v1i16/v3fi6 to v4i16 if ((LoadVT.getVectorNumElements() % 2) == 1) - Elts.push_back(DAG.getUNDEF(MVT::i16)); + Elts.push_back(DAG.getPOISON(MVT::i16)); Result = DAG.getBuildVector(IntLoadVT, DL, Elts); @@ -6145,7 +6359,7 @@ static SDValue lowerICMPIntrinsic(const SITargetLowering &TLI, SDNode *N, EVT VT = N->getValueType(0); unsigned CondCode = N->getConstantOperandVal(3); if (!ICmpInst::isIntPredicate(static_cast<ICmpInst::Predicate>(CondCode))) - return DAG.getUNDEF(VT); + return DAG.getPOISON(VT); ICmpInst::Predicate IcInput = static_cast<ICmpInst::Predicate>(CondCode); @@ -6180,7 +6394,7 @@ static SDValue lowerFCMPIntrinsic(const SITargetLowering &TLI, SDNode *N, unsigned CondCode = N->getConstantOperandVal(3); if (!FCmpInst::isFPPredicate(static_cast<FCmpInst::Predicate>(CondCode))) - return DAG.getUNDEF(VT); + return DAG.getPOISON(VT); SDValue Src0 = N->getOperand(1); SDValue Src1 = N->getOperand(2); @@ -6543,6 +6757,11 @@ void SITargetLowering::ReplaceNodeResults(SDNode *N, Results.push_back(LoadVal); return; } + case Intrinsic::amdgcn_dead: { + for (unsigned I = 0, E = N->getNumValues(); I < E; ++I) + Results.push_back(DAG.getPOISON(N->getValueType(I))); + return; + } } break; } @@ -6800,24 +7019,72 @@ SDValue SITargetLowering::getFPExtOrFPRound(SelectionDAG &DAG, SDValue Op, DAG.getTargetConstant(0, DL, MVT::i32)); } -SDValue SITargetLowering::lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const { - assert(Op.getValueType() == MVT::f16 && - "Do not know how to custom lower FP_ROUND for non-f16 type"); +SDValue SITargetLowering::splitFP_ROUNDVectorOp(SDValue Op, + SelectionDAG &DAG) const { + EVT DstVT = Op.getValueType(); + unsigned NumElts = DstVT.getVectorNumElements(); + assert(NumElts > 2 && isPowerOf2_32(NumElts)); + + auto [Lo, Hi] = DAG.SplitVectorOperand(Op.getNode(), 0); + + SDLoc DL(Op); + unsigned Opc = Op.getOpcode(); + SDValue Flags = Op.getOperand(1); + EVT HalfDstVT = + EVT::getVectorVT(*DAG.getContext(), DstVT.getScalarType(), NumElts / 2); + SDValue OpLo = DAG.getNode(Opc, DL, HalfDstVT, Lo, Flags); + SDValue OpHi = DAG.getNode(Opc, DL, HalfDstVT, Hi, Flags); + return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, OpLo, OpHi); +} + +SDValue SITargetLowering::lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); - if (SrcVT != MVT::f64) - return Op; + EVT DstVT = Op.getValueType(); - // TODO: Handle strictfp - if (Op.getOpcode() != ISD::FP_ROUND) + if (DstVT.isVector() && DstVT.getScalarType() == MVT::f16) { + assert(Subtarget->hasCvtPkF16F32Inst() && "support v_cvt_pk_f16_f32"); + if (SrcVT.getScalarType() != MVT::f32) + return SDValue(); + return SrcVT == MVT::v2f32 ? Op : splitFP_ROUNDVectorOp(Op, DAG); + } + + if (SrcVT.getScalarType() != MVT::f64) return Op; SDLoc DL(Op); + if (DstVT == MVT::f16) { + // TODO: Handle strictfp + if (Op.getOpcode() != ISD::FP_ROUND) + return Op; - SDValue FpToFp16 = DAG.getNode(ISD::FP_TO_FP16, DL, MVT::i32, Src); - SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16); - return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc); + if (!Subtarget->has16BitInsts()) { + SDValue FpToFp16 = DAG.getNode(ISD::FP_TO_FP16, DL, MVT::i32, Src); + SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16); + return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc); + } + if (getTargetMachine().Options.UnsafeFPMath) { + SDValue Flags = Op.getOperand(1); + SDValue Src32 = DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, Src, Flags); + return DAG.getNode(ISD::FP_ROUND, DL, MVT::f16, Src32, Flags); + } + SDValue FpToFp16 = LowerF64ToF16Safe(Src, DL, DAG); + SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16); + return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc); + } + + assert(DstVT.getScalarType() == MVT::bf16 && + "custom lower FP_ROUND for f16 or bf16"); + assert(Subtarget->hasBF16ConversionInsts() && "f32 -> bf16 is legal"); + + // Round-inexact-to-odd f64 to f32, then do the final rounding using the + // hardware f32 -> bf16 instruction. + EVT F32VT = SrcVT.isVector() ? SrcVT.changeVectorElementType(MVT::f32) : + MVT::f32; + SDValue Rod = expandRoundInexactToOdd(F32VT, Src, DL, DAG); + return DAG.getNode(ISD::FP_ROUND, DL, DstVT, Rod, + DAG.getTargetConstant(0, DL, MVT::i32)); } SDValue SITargetLowering::lowerFMINNUM_FMAXNUM(SDValue Op, @@ -6840,6 +7107,52 @@ SDValue SITargetLowering::lowerFMINNUM_FMAXNUM(SDValue Op, return Op; } +SDValue +SITargetLowering::lowerFMINIMUMNUM_FMAXIMUMNUM(SDValue Op, + SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + const MachineFunction &MF = DAG.getMachineFunction(); + const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); + bool IsIEEEMode = Info->getMode().IEEE; + + if (IsIEEEMode) + return expandFMINIMUMNUM_FMAXIMUMNUM(Op.getNode(), DAG); + + if (VT == MVT::v4f16 || VT == MVT::v8f16 || VT == MVT::v16f16 || + VT == MVT::v16bf16) + return splitBinaryVectorOp(Op, DAG); + return Op; +} + +SDValue SITargetLowering::lowerFMINIMUM_FMAXIMUM(SDValue Op, + SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + if (VT.isVector()) + return splitBinaryVectorOp(Op, DAG); + + assert(!Subtarget->hasIEEEMinimumMaximumInsts() && + !Subtarget->hasMinimum3Maximum3F16() && + Subtarget->hasMinimum3Maximum3PKF16() && VT == MVT::f16 && + "should not need to widen f16 minimum/maximum to v2f16"); + + // Widen f16 operation to v2f16 + + // fminimum f16:x, f16:y -> + // extract_vector_elt (fminimum (v2f16 (scalar_to_vector x)) + // (v2f16 (scalar_to_vector y))), 0 + SDLoc SL(Op); + SDValue WideSrc0 = + DAG.getNode(ISD::SCALAR_TO_VECTOR, SL, MVT::v2f16, Op.getOperand(0)); + SDValue WideSrc1 = + DAG.getNode(ISD::SCALAR_TO_VECTOR, SL, MVT::v2f16, Op.getOperand(1)); + + SDValue Widened = + DAG.getNode(Op.getOpcode(), SL, MVT::v2f16, WideSrc0, WideSrc1); + + return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::f16, Widened, + DAG.getConstant(0, SL, MVT::i32)); +} + SDValue SITargetLowering::lowerFLDEXP(SDValue Op, SelectionDAG &DAG) const { bool IsStrict = Op.getOpcode() == ISD::STRICT_FLDEXP; EVT VT = Op.getValueType(); @@ -6960,6 +7273,31 @@ SDValue SITargetLowering::promoteUniformOpToI32(SDValue Op, return DAG.getZExtOrTrunc(NewVal, DL, OpTy); } +SDValue SITargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { + SDValue Mag = Op.getOperand(0); + EVT MagVT = Mag.getValueType(); + + if (MagVT.getVectorNumElements() > 2) + return splitBinaryVectorOp(Op, DAG); + + SDValue Sign = Op.getOperand(1); + EVT SignVT = Sign.getValueType(); + + if (MagVT == SignVT) + return Op; + + // fcopysign v2f16:mag, v2f32:sign -> + // fcopysign v2f16:mag, bitcast (trunc (bitcast sign to v2i32) to v2i16) + + SDLoc SL(Op); + SDValue SignAsInt32 = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, Sign); + SDValue SignAsInt16 = DAG.getNode(ISD::TRUNCATE, SL, MVT::v2i16, SignAsInt32); + + SDValue SignAsHalf16 = DAG.getNode(ISD::BITCAST, SL, MagVT, SignAsInt16); + + return DAG.getNode(ISD::FCOPYSIGN, SL, MagVT, Mag, SignAsHalf16); +} + // Custom lowering for vector multiplications and s_mul_u64. SDValue SITargetLowering::lowerMUL(SDValue Op, SelectionDAG &DAG) const { EVT VT = Op.getValueType(); @@ -7158,11 +7496,10 @@ SDValue SITargetLowering::lowerDEBUGTRAP(SDValue Op, SelectionDAG &DAG) const { if (!Subtarget->isTrapHandlerEnabled() || Subtarget->getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) { - DiagnosticInfoUnsupported NoTrap(MF.getFunction(), - "debugtrap handler not supported", - Op.getDebugLoc(), DS_Warning); LLVMContext &Ctx = MF.getFunction().getContext(); - Ctx.diagnose(NoTrap); + Ctx.diagnose(DiagnosticInfoUnsupported(MF.getFunction(), + "debugtrap handler not supported", + Op.getDebugLoc(), DS_Warning)); return Chain; } @@ -7218,7 +7555,7 @@ SDValue SITargetLowering::getSegmentAperture(unsigned AS, const SDLoc &DL, if (UserSGPR == AMDGPU::NoRegister) { // We probably are in a function incorrectly marked with // amdgpu-no-queue-ptr. This is undefined. - return DAG.getUNDEF(MVT::i32); + return DAG.getPOISON(MVT::i32); } SDValue QueuePtr = @@ -7245,8 +7582,7 @@ SDValue SITargetLowering::getSegmentAperture(unsigned AS, const SDLoc &DL, /// not necessary. static bool isKnownNonNull(SDValue Val, SelectionDAG &DAG, const AMDGPUTargetMachine &TM, unsigned AddrSpace) { - if (isa<FrameIndexSDNode>(Val) || isa<GlobalAddressSDNode>(Val) || - isa<BasicBlockSDNode>(Val)) + if (isa<FrameIndexSDNode, GlobalAddressSDNode, BasicBlockSDNode>(Val)) return true; if (auto *ConstVal = dyn_cast<ConstantSDNode>(Val)) @@ -7340,12 +7676,8 @@ SDValue SITargetLowering::lowerADDRSPACECAST(SDValue Op, // global <-> flat are no-ops and never emitted. - const MachineFunction &MF = DAG.getMachineFunction(); - DiagnosticInfoUnsupported InvalidAddrSpaceCast( - MF.getFunction(), "invalid addrspacecast", SL.getDebugLoc()); - DAG.getContext()->diagnose(InvalidAddrSpaceCast); - - return DAG.getUNDEF(Op->getValueType(0)); + // Invalid casts are poison. + return DAG.getPOISON(Op->getValueType(0)); } // This lowers an INSERT_SUBVECTOR by extracting the individual elements from @@ -7687,7 +8019,7 @@ SDValue SITargetLowering::lowerVECTOR_SHUFFLE(SDValue Op, NewMaskIdx1 += NewSrcNumElts; Result1 = SubVec1; } else { - Result1 = DAG.getUNDEF(PackVT); + Result1 = DAG.getPOISON(PackVT); } SDValue Shuf = DAG.getVectorShuffle(PackVT, SL, Result0, Result1, @@ -7720,7 +8052,7 @@ SDValue SITargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op, SDValue SVal = Op.getOperand(0); EVT ResultVT = Op.getValueType(); EVT SValVT = SVal.getValueType(); - SDValue UndefVal = DAG.getUNDEF(SValVT); + SDValue UndefVal = DAG.getPOISON(SValVT); SDLoc SL(Op); SmallVector<SDValue, 8> VElts; @@ -7940,20 +8272,18 @@ SDValue SITargetLowering::lowerImplicitZextParam(SelectionDAG &DAG, SDValue Op, static SDValue emitNonHSAIntrinsicError(SelectionDAG &DAG, const SDLoc &DL, EVT VT) { - DiagnosticInfoUnsupported BadIntrin(DAG.getMachineFunction().getFunction(), - "non-hsa intrinsic with hsa target", - DL.getDebugLoc()); - DAG.getContext()->diagnose(BadIntrin); - return DAG.getUNDEF(VT); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + DAG.getMachineFunction().getFunction(), + "non-hsa intrinsic with hsa target", DL.getDebugLoc())); + return DAG.getPOISON(VT); } static SDValue emitRemovedIntrinsicError(SelectionDAG &DAG, const SDLoc &DL, EVT VT) { - DiagnosticInfoUnsupported BadIntrin(DAG.getMachineFunction().getFunction(), - "intrinsic not supported on subtarget", - DL.getDebugLoc()); - DAG.getContext()->diagnose(BadIntrin); - return DAG.getUNDEF(VT); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + DAG.getMachineFunction().getFunction(), + "intrinsic not supported on subtarget", DL.getDebugLoc())); + return DAG.getPOISON(VT); } static SDValue getBuildDwordsVector(SelectionDAG &DAG, SDLoc DL, @@ -7978,7 +8308,7 @@ static SDValue getBuildDwordsVector(SelectionDAG &DAG, SDLoc DL, VecElts[i] = Elt; } for (unsigned i = Elts.size(); i < NumElts; ++i) - VecElts[i] = DAG.getUNDEF(MVT::f32); + VecElts[i] = DAG.getPOISON(MVT::f32); if (NumElts == 1) return VecElts[0]; @@ -7996,7 +8326,7 @@ static SDValue padEltsToUndef(SelectionDAG &DAG, const SDLoc &DL, EVT CastVT, else Elts.push_back(Src); - SDValue Undef = DAG.getUNDEF(SrcVT.getScalarType()); + SDValue Undef = DAG.getPOISON(SrcVT.getScalarType()); while (ExtraElts--) Elts.push_back(Undef); @@ -8247,7 +8577,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op, // occupies full 32-bit. SDValue Bias = DAG.getBuildVector( MVT::v2f16, DL, - {Op.getOperand(ArgOffset + I), DAG.getUNDEF(MVT::f16)}); + {Op.getOperand(ArgOffset + I), DAG.getPOISON(MVT::f16)}); VAddrs.push_back(Bias); } else { assert((!IsA16 || Intr->NumBiasArgs == 0 || I != Intr->BiasIndex) && @@ -8377,7 +8707,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op, // type if (DMaskLanes == 0 && !BaseOpcode->Store) { // This is a no-op load. This can be eliminated - SDValue Undef = DAG.getUNDEF(Op.getValueType()); + SDValue Undef = DAG.getPOISON(Op.getValueType()); if (isa<MemSDNode>(Op)) return DAG.getMergeValues({Undef, Op.getOperand(0)}, DL); return Undef; @@ -8436,11 +8766,15 @@ SDValue SITargetLowering::lowerImage(SDValue Op, : False); if (IsGFX10Plus) Ops.push_back(IsA16 ? True : False); - if (!Subtarget->hasGFX90AInsts()) { + + if (!Subtarget->hasGFX90AInsts()) Ops.push_back(TFE); // tfe - } else if (TFE->getAsZExtVal()) { - report_fatal_error("TFE is not supported on this GPU"); + else if (TFE->getAsZExtVal()) { + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + DAG.getMachineFunction().getFunction(), + "TFE is not supported on this GPU", DL.getDebugLoc())); } + if (!IsGFX12Plus || BaseOpcode->Sampler || BaseOpcode->MSAA) Ops.push_back(LWE); // lwe if (!IsGFX10Plus) @@ -8471,9 +8805,23 @@ SDValue SITargetLowering::lowerImage(SDValue Op, 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"); + if (Opcode == -1) { + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + DAG.getMachineFunction().getFunction(), + "requested image instruction is not supported on this GPU", + DL.getDebugLoc())); + + unsigned Idx = 0; + SmallVector<SDValue, 3> RetValues(OrigResultTypes.size()); + for (EVT VT : OrigResultTypes) { + if (VT == MVT::Other) + RetValues[Idx++] = Op.getOperand(0); // Chain + else + RetValues[Idx++] = DAG.getPOISON(VT); + } + + return DAG.getMergeValues(RetValues, DL); + } } if (Opcode == -1 && Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) @@ -8579,7 +8927,7 @@ SDValue SITargetLowering::lowerSBuffer(EVT VT, SDLoc DL, SDValue Rsrc, LoadVT = MVT::getVectorVT(LoadVT.getScalarType(), 4); } - SDVTList VTList = DAG.getVTList({LoadVT, MVT::Glue}); + SDVTList VTList = DAG.getVTList({LoadVT, MVT::Other}); // Use the alignment to ensure that the required offsets will fit into the // immediate offsets. @@ -8619,6 +8967,11 @@ SDValue SITargetLowering::lowerWorkitemID(SelectionDAG &DAG, SDValue Op, if (MaxID == 0) return DAG.getConstant(0, SL, MVT::i32); + // It's undefined behavior if a function marked with the amdgpu-no-* + // attributes uses the corresponding intrinsic. + if (!Arg) + return DAG.getPOISON(Op->getValueType(0)); + SDValue Val = loadInputValue(DAG, &AMDGPU::VGPR_32RegClass, MVT::i32, SDLoc(DAG.getEntryNode()), Arg); @@ -8656,11 +9009,10 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::amdgcn_dispatch_ptr: case Intrinsic::amdgcn_queue_ptr: { if (!Subtarget->isAmdHsaOrMesa(MF.getFunction())) { - DiagnosticInfoUnsupported BadIntrin( + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( MF.getFunction(), "unsupported hsa intrinsic without hsa target", - DL.getDebugLoc()); - DAG.getContext()->diagnose(BadIntrin); - return DAG.getUNDEF(VT); + DL.getDebugLoc())); + return DAG.getPOISON(VT); } auto RegID = IntrinsicID == Intrinsic::amdgcn_dispatch_ptr @@ -8733,27 +9085,6 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(), SI::KernelInputOffsets::NGROUPS_Z, Align(4), false); - case Intrinsic::r600_read_global_size_x: - if (Subtarget->isAmdHsaOS()) - return emitNonHSAIntrinsicError(DAG, DL, VT); - - return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(), - SI::KernelInputOffsets::GLOBAL_SIZE_X, - Align(4), false); - case Intrinsic::r600_read_global_size_y: - if (Subtarget->isAmdHsaOS()) - return emitNonHSAIntrinsicError(DAG, DL, VT); - - return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(), - SI::KernelInputOffsets::GLOBAL_SIZE_Y, - Align(4), false); - case Intrinsic::r600_read_global_size_z: - if (Subtarget->isAmdHsaOS()) - return emitNonHSAIntrinsicError(DAG, DL, VT); - - return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(), - SI::KernelInputOffsets::GLOBAL_SIZE_Z, - Align(4), false); case Intrinsic::r600_read_local_size_x: if (Subtarget->isAmdHsaOS()) return emitNonHSAIntrinsicError(DAG, DL, VT); @@ -9010,6 +9341,12 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::amdgcn_mov_dpp8: case Intrinsic::amdgcn_update_dpp: return lowerLaneOp(*this, Op.getNode(), DAG); + case Intrinsic::amdgcn_dead: { + SmallVector<SDValue, 8> Poisons; + for (const EVT ValTy : Op.getNode()->values()) + Poisons.push_back(DAG.getPOISON(ValTy)); + return DAG.getMergeValues(Poisons, SDLoc(Op)); + } default: if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr = AMDGPU::getImageDimIntrinsicInfo(IntrinsicID)) @@ -9109,16 +9446,27 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, IndexOperand &= ~(0xf << 24); if (CountDw < 1 || CountDw > 4) { - report_fatal_error( - "ds_ordered_count: dword count must be between 1 and 4"); + const Function &Fn = DAG.getMachineFunction().getFunction(); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + Fn, "ds_ordered_count: dword count must be between 1 and 4", + DL.getDebugLoc())); + CountDw = 1; } } - if (IndexOperand) - report_fatal_error("ds_ordered_count: bad index operand"); + if (IndexOperand) { + const Function &Fn = DAG.getMachineFunction().getFunction(); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + Fn, "ds_ordered_count: bad index operand", DL.getDebugLoc())); + } - if (WaveDone && !WaveRelease) - report_fatal_error("ds_ordered_count: wave_done requires wave_release"); + if (WaveDone && !WaveRelease) { + // TODO: Move this to IR verifier + const Function &Fn = DAG.getMachineFunction().getFunction(); + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( + Fn, "ds_ordered_count: wave_done requires wave_release", + DL.getDebugLoc())); + } unsigned Instruction = IntrID == Intrinsic::amdgcn_ds_ordered_add ? 0 : 1; unsigned ShaderType = @@ -9402,6 +9750,51 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, Op->getVTList(), Ops, VT, M->getMemOperand()); } + case Intrinsic::amdgcn_image_bvh_dual_intersect_ray: + case Intrinsic::amdgcn_image_bvh8_intersect_ray: { + MemSDNode *M = cast<MemSDNode>(Op); + SDValue NodePtr = M->getOperand(2); + SDValue RayExtent = M->getOperand(3); + SDValue InstanceMask = M->getOperand(4); + SDValue RayOrigin = M->getOperand(5); + SDValue RayDir = M->getOperand(6); + SDValue Offsets = M->getOperand(7); + SDValue TDescr = M->getOperand(8); + + assert(NodePtr.getValueType() == MVT::i64); + assert(RayDir.getValueType() == MVT::v3f32); + + if (!Subtarget->hasBVHDualAndBVH8Insts()) { + emitRemovedIntrinsicError(DAG, DL, Op.getValueType()); + return SDValue(); + } + + bool IsBVH8 = IntrID == Intrinsic::amdgcn_image_bvh8_intersect_ray; + const unsigned NumVDataDwords = 10; + const unsigned NumVAddrDwords = IsBVH8 ? 11 : 12; + int Opcode = AMDGPU::getMIMGOpcode( + IsBVH8 ? AMDGPU::IMAGE_BVH8_INTERSECT_RAY + : AMDGPU::IMAGE_BVH_DUAL_INTERSECT_RAY, + AMDGPU::MIMGEncGfx12, NumVDataDwords, NumVAddrDwords); + assert(Opcode != -1); + + SmallVector<SDValue, 7> Ops; + Ops.push_back(NodePtr); + Ops.push_back(DAG.getBuildVector( + MVT::v2i32, DL, + {DAG.getBitcast(MVT::i32, RayExtent), + DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, InstanceMask)})); + Ops.push_back(RayOrigin); + Ops.push_back(RayDir); + Ops.push_back(Offsets); + Ops.push_back(TDescr); + Ops.push_back(M->getChain()); + + auto *NewNode = DAG.getMachineNode(Opcode, DL, M->getVTList(), Ops); + MachineMemOperand *MemRef = M->getMemOperand(); + DAG.setNodeMemRefs(NewNode, {MemRef}); + return SDValue(NewNode, 0); + } case Intrinsic::amdgcn_image_bvh_intersect_ray: { MemSDNode *M = cast<MemSDNode>(Op); SDValue NodePtr = M->getOperand(2); @@ -9511,7 +9904,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, if (!UseNSA) { // Build a single vector containing all the operands so far prepared. if (NumVAddrDwords > 12) { - SDValue Undef = DAG.getUNDEF(MVT::i32); + SDValue Undef = DAG.getPOISON(MVT::i32); Ops.append(16 - Ops.size(), Undef); } assert(Ops.size() >= 8 && Ops.size() <= 12); @@ -9697,13 +10090,13 @@ SDValue SITargetLowering::handleD16VData(SDValue VData, SelectionDAG &DAG, // Handle v3i16 unsigned I = Elts.size() / 2; SDValue Pair = DAG.getBuildVector(MVT::v2i16, DL, - {Elts[I * 2], DAG.getUNDEF(MVT::i16)}); + {Elts[I * 2], DAG.getPOISON(MVT::i16)}); SDValue IntPair = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Pair); PackedElts.push_back(IntPair); } // Pad using UNDEF - PackedElts.resize(Elts.size(), DAG.getUNDEF(MVT::i32)); + PackedElts.resize(Elts.size(), DAG.getPOISON(MVT::i32)); // Build final vector EVT VecVT = @@ -9738,10 +10131,9 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, switch (IntrinsicID) { case Intrinsic::amdgcn_exp_compr: { if (!Subtarget->hasCompressedExport()) { - DiagnosticInfoUnsupported BadIntrin( + DAG.getContext()->diagnose(DiagnosticInfoUnsupported( DAG.getMachineFunction().getFunction(), - "intrinsic not supported on subtarget", DL.getDebugLoc()); - DAG.getContext()->diagnose(BadIntrin); + "intrinsic not supported on subtarget", DL.getDebugLoc())); } SDValue Src0 = Op.getOperand(4); SDValue Src1 = Op.getOperand(5); @@ -9750,7 +10142,7 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, return SDValue(); const ConstantSDNode *Done = cast<ConstantSDNode>(Op.getOperand(6)); - SDValue Undef = DAG.getUNDEF(MVT::f32); + SDValue Undef = DAG.getPOISON(MVT::f32); const SDValue Ops[] = { Op.getOperand(2), // tgt DAG.getNode(ISD::BITCAST, DL, MVT::f32, Src0), // src0 @@ -9963,7 +10355,8 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, case Intrinsic::amdgcn_raw_ptr_buffer_load_lds: case Intrinsic::amdgcn_struct_buffer_load_lds: case Intrinsic::amdgcn_struct_ptr_buffer_load_lds: { - assert(!AMDGPU::isGFX12Plus(*Subtarget)); + if (!Subtarget->hasVMemToLDSLoad()) + return SDValue(); unsigned Opc; bool HasVIndex = IntrinsicID == Intrinsic::amdgcn_struct_buffer_load_lds || @@ -10069,7 +10462,14 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, return SDValue(Load, 0); } + // Buffers are handled by LowerBufferFatPointers, and we're going to go + // for "trust me" that the remaining cases are global pointers until + // such time as we can put two mem operands on an intrinsic. + case Intrinsic::amdgcn_load_to_lds: case Intrinsic::amdgcn_global_load_lds: { + if (!Subtarget->hasVMemToLDSLoad()) + return SDValue(); + unsigned Opc; unsigned Size = Op->getConstantOperandVal(4); switch (Size) { @@ -10096,7 +10496,6 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, break; } - auto *M = cast<MemSDNode>(Op); SDValue M0Val = copyToM0(DAG, Chain, DL, Op.getOperand(3)); SmallVector<SDValue, 6> Ops; @@ -10136,6 +10535,7 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, Ops.push_back(M0Val.getValue(0)); // Chain Ops.push_back(M0Val.getValue(1)); // Glue + auto *M = cast<MemSDNode>(Op); MachineMemOperand *LoadMMO = M->getMemOperand(); MachinePointerInfo LoadPtrI = LoadMMO->getPointerInfo(); LoadPtrI.Offset = Op->getConstantOperandVal(5); @@ -10162,7 +10562,6 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, return SDValue(DAG.getMachineNode(AMDGPU::SI_END_CF, DL, MVT::Other, Op->getOperand(2), Chain), 0); - case Intrinsic::amdgcn_s_barrier_init: case Intrinsic::amdgcn_s_barrier_signal_var: { // these two intrinsics have two operands: barrier pointer and member count SDValue Chain = Op->getOperand(0); @@ -10170,9 +10569,6 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, SDValue BarOp = Op->getOperand(2); SDValue CntOp = Op->getOperand(3); SDValue M0Val; - unsigned Opc = IntrinsicID == Intrinsic::amdgcn_s_barrier_init - ? AMDGPU::S_BARRIER_INIT_M0 - : AMDGPU::S_BARRIER_SIGNAL_M0; // extract the BarrierID from bits 4-9 of BarOp SDValue BarID; BarID = DAG.getNode(ISD::SRL, DL, MVT::i32, BarOp, @@ -10196,40 +10592,8 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0)); - auto *NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops); - return SDValue(NewMI, 0); - } - case Intrinsic::amdgcn_s_barrier_join: { - // these three intrinsics have one operand: barrier pointer - SDValue Chain = Op->getOperand(0); - SmallVector<SDValue, 2> Ops; - SDValue BarOp = Op->getOperand(2); - unsigned Opc; - - if (isa<ConstantSDNode>(BarOp)) { - uint64_t BarVal = cast<ConstantSDNode>(BarOp)->getZExtValue(); - Opc = AMDGPU::S_BARRIER_JOIN_IMM; - - // extract the BarrierID from bits 4-9 of the immediate - unsigned BarID = (BarVal >> 4) & 0x3F; - SDValue K = DAG.getTargetConstant(BarID, DL, MVT::i32); - Ops.push_back(K); - Ops.push_back(Chain); - } else { - Opc = AMDGPU::S_BARRIER_JOIN_M0; - - // extract the BarrierID from bits 4-9 of BarOp, copy to M0[5:0] - SDValue M0Val; - M0Val = DAG.getNode(ISD::SRL, DL, MVT::i32, BarOp, - DAG.getShiftAmountConstant(4, MVT::i32, DL)); - M0Val = - SDValue(DAG.getMachineNode(AMDGPU::S_AND_B32, DL, MVT::i32, M0Val, - DAG.getTargetConstant(0x3F, DL, MVT::i32)), - 0); - Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0)); - } - - auto *NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops); + auto *NewMI = DAG.getMachineNode(AMDGPU::S_BARRIER_SIGNAL_M0, DL, + Op->getVTList(), Ops); return SDValue(NewMI, 0); } case Intrinsic::amdgcn_s_prefetch_data: { @@ -10260,6 +10624,11 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, } } +bool SITargetLowering::shouldPreservePtrArith(const Function &F, + EVT PtrVT) const { + return UseSelectionDAGPTRADD && PtrVT == MVT::i64; +} + // The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args: // offset (the offset that is included in bounds checking and swizzling, to be // split between the instruction's voffset and immoffset fields) and soffset @@ -10626,7 +10995,7 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const { (AS == AMDGPUAS::GLOBAL_ADDRESS && Subtarget->getScalarizeGlobalBehavior() && Load->isSimple() && isMemOpHasNoClobberedMemOperand(Load))) { - if ((!Op->isDivergent() || AMDGPUInstrInfo::isUniformMMO(MMO)) && + if ((!Op->isDivergent() || AMDGPU::isUniformMMO(MMO)) && Alignment >= Align(4) && NumElements < 32) { if (MemVT.isPow2VectorType() || (Subtarget->hasScalarDwordx3Loads() && NumElements == 3)) @@ -11057,9 +11426,10 @@ SDValue SITargetLowering::LowerFDIV32(SDValue Op, SelectionDAG &DAG) const { const SDValue DisableDenormValue = getSPDenormModeValue( FP_DENORM_FLUSH_IN_FLUSH_OUT, DAG, Info, Subtarget); + SDVTList BindParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); DisableDenorm = - DAG.getNode(AMDGPUISD::DENORM_MODE, SL, MVT::Other, Fma4.getValue(1), - DisableDenormValue, Fma4.getValue(2)) + DAG.getNode(AMDGPUISD::DENORM_MODE, SL, BindParamVTs, + Fma4.getValue(1), DisableDenormValue, Fma4.getValue(2)) .getNode(); } else { assert(HasDynamicDenormals == (bool)SavedDenormMode); @@ -11568,29 +11938,64 @@ SDValue SITargetLowering::performFCopySignCombine(SDNode *N, DAGCombinerInfo &DCI) const { SDValue MagnitudeOp = N->getOperand(0); SDValue SignOp = N->getOperand(1); + + // The generic combine for fcopysign + fp cast is too conservative with + // vectors, and also gets confused by the splitting we will perform here, so + // peek through FP casts. + if (SignOp.getOpcode() == ISD::FP_EXTEND || + SignOp.getOpcode() == ISD::FP_ROUND) + SignOp = SignOp.getOperand(0); + SelectionDAG &DAG = DCI.DAG; SDLoc DL(N); + EVT SignVT = SignOp.getValueType(); // f64 fcopysign is really an f32 copysign on the high bits, so replace the // lower half with a copy. // fcopysign f64:x, _:y -> x.lo32, (fcopysign (f32 x.hi32), _:y) - if (MagnitudeOp.getValueType() == MVT::f64) { - SDValue MagAsVector = - DAG.getNode(ISD::BITCAST, DL, MVT::v2f32, MagnitudeOp); - SDValue MagLo = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, - MagAsVector, DAG.getConstant(0, DL, MVT::i32)); - SDValue MagHi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, - MagAsVector, DAG.getConstant(1, DL, MVT::i32)); + EVT MagVT = MagnitudeOp.getValueType(); + + unsigned NumElts = MagVT.isVector() ? MagVT.getVectorNumElements() : 1; - SDValue HiOp = DAG.getNode(ISD::FCOPYSIGN, DL, MVT::f32, MagHi, SignOp); + if (MagVT.getScalarType() == MVT::f64) { + EVT F32VT = MagVT.isVector() + ? EVT::getVectorVT(*DAG.getContext(), MVT::f32, 2 * NumElts) + : MVT::v2f32; - SDValue Vector = - DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2f32, MagLo, HiOp); + SDValue MagAsVector = DAG.getNode(ISD::BITCAST, DL, F32VT, MagnitudeOp); - return DAG.getNode(ISD::BITCAST, DL, MVT::f64, Vector); + SmallVector<SDValue, 8> NewElts; + for (unsigned I = 0; I != NumElts; ++I) { + SDValue MagLo = + DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, MagAsVector, + DAG.getConstant(2 * I, DL, MVT::i32)); + SDValue MagHi = + DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, MagAsVector, + DAG.getConstant(2 * I + 1, DL, MVT::i32)); + + SDValue SignOpElt = + MagVT.isVector() + ? DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, SignVT.getScalarType(), + SignOp, DAG.getConstant(I, DL, MVT::i32)) + : SignOp; + + SDValue HiOp = + DAG.getNode(ISD::FCOPYSIGN, DL, MVT::f32, MagHi, SignOpElt); + + SDValue Vector = + DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2f32, MagLo, HiOp); + + SDValue NewElt = DAG.getNode(ISD::BITCAST, DL, MVT::f64, Vector); + NewElts.push_back(NewElt); + } + + if (NewElts.size() == 1) + return NewElts[0]; + + return DAG.getNode(ISD::BUILD_VECTOR, DL, MagVT, NewElts); } - if (SignOp.getValueType() != MVT::f64) + if (SignVT.getScalarType() != MVT::f64) return SDValue(); // Reduce width of sign operand, we only need the highest bit. @@ -11598,13 +12003,31 @@ SDValue SITargetLowering::performFCopySignCombine(SDNode *N, // fcopysign f64:x, f64:y -> // fcopysign f64:x, (extract_vector_elt (bitcast f64:y to v2f32), 1) // TODO: In some cases it might make sense to go all the way to f16. - SDValue SignAsVector = DAG.getNode(ISD::BITCAST, DL, MVT::v2f32, SignOp); - SDValue SignAsF32 = - DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, SignAsVector, - DAG.getConstant(1, DL, MVT::i32)); + + EVT F32VT = MagVT.isVector() + ? EVT::getVectorVT(*DAG.getContext(), MVT::f32, 2 * NumElts) + : MVT::v2f32; + + SDValue SignAsVector = DAG.getNode(ISD::BITCAST, DL, F32VT, SignOp); + + SmallVector<SDValue, 8> F32Signs; + for (unsigned I = 0; I != NumElts; ++I) { + // Take sign from odd elements of cast vector + SDValue SignAsF32 = + DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, SignAsVector, + DAG.getConstant(2 * I + 1, DL, MVT::i32)); + F32Signs.push_back(SignAsF32); + } + + SDValue NewSign = + NumElts == 1 + ? F32Signs.back() + : DAG.getNode(ISD::BUILD_VECTOR, DL, + EVT::getVectorVT(*DAG.getContext(), MVT::f32, NumElts), + F32Signs); return DAG.getNode(ISD::FCOPYSIGN, DL, N->getValueType(0), N->getOperand(0), - SignAsF32); + NewSign); } // (shl (add x, c1), c2) -> add (shl x, c2), (shl c1, c2) @@ -11691,7 +12114,6 @@ static unsigned getBasePtrIndex(const MemSDNode *N) { SDValue SITargetLowering::performMemSDNodeCombine(MemSDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; - SDLoc SL(N); unsigned PtrIdx = getBasePtrIndex(N); SDValue Ptr = N->getOperand(PtrIdx); @@ -11733,6 +12155,11 @@ SDValue SITargetLowering::splitBinaryBitConstantOp( if ((bitOpWithConstantIsReducible(Opc, ValLo) || bitOpWithConstantIsReducible(Opc, ValHi)) || (CRHS->hasOneUse() && !TII->isInlineConstant(CRHS->getAPIntValue()))) { + // We have 64-bit scalar and/or/xor, but do not have vector forms. + if (Subtarget->has64BitLiterals() && CRHS->hasOneUse() && + !CRHS->user_begin()->isDivergent()) + return SDValue(); + // If we need to materialize a 64-bit immediate, it will be split up later // anyway. Avoid creating the harder to understand 64-bit immediate // materialization. @@ -11749,12 +12176,32 @@ bool llvm::isBoolSGPR(SDValue V) { default: break; case ISD::SETCC: + case ISD::IS_FPCLASS: case AMDGPUISD::FP_CLASS: return true; case ISD::AND: case ISD::OR: case ISD::XOR: return isBoolSGPR(V.getOperand(0)) && isBoolSGPR(V.getOperand(1)); + case ISD::SADDO: + case ISD::UADDO: + case ISD::SSUBO: + case ISD::USUBO: + case ISD::SMULO: + case ISD::UMULO: + return V.getResNo() == 1; + case ISD::INTRINSIC_WO_CHAIN: { + unsigned IntrinsicID = V.getConstantOperandVal(0); + switch (IntrinsicID) { + case Intrinsic::amdgcn_is_shared: + case Intrinsic::amdgcn_is_private: + return true; + default: + return false; + } + + return false; + } } return false; } @@ -13008,6 +13455,8 @@ bool SITargetLowering::isCanonicalized(SelectionDAG &DAG, SDValue Op, case ISD::FMAXNUM_IEEE: case ISD::FMINIMUM: case ISD::FMAXIMUM: + case ISD::FMINIMUMNUM: + case ISD::FMAXIMUMNUM: case AMDGPUISD::CLAMP: case AMDGPUISD::FMED3: case AMDGPUISD::FMAX3: @@ -13172,7 +13621,9 @@ bool SITargetLowering::isCanonicalized(Register Reg, const MachineFunction &MF, case AMDGPU::G_FMINNUM_IEEE: case AMDGPU::G_FMAXNUM_IEEE: case AMDGPU::G_FMINIMUM: - case AMDGPU::G_FMAXIMUM: { + case AMDGPU::G_FMAXIMUM: + case AMDGPU::G_FMINIMUMNUM: + case AMDGPU::G_FMAXIMUMNUM: { if (Subtarget->supportsMinMaxDenormModes() || // FIXME: denormalsEnabledForType is broken for dynamic denormalsEnabledForType(MRI.getType(Reg), MF)) @@ -13214,6 +13665,7 @@ bool SITargetLowering::isCanonicalized(Register Reg, const MachineFunction &MF, case Intrinsic::amdgcn_frexp_mant: case Intrinsic::amdgcn_fdot2: case Intrinsic::amdgcn_trig_preop: + case Intrinsic::amdgcn_tanh: return true; default: break; @@ -13342,6 +13794,7 @@ static unsigned minMaxOpcToMin3Max3Opc(unsigned Opc) { switch (Opc) { case ISD::FMAXNUM: case ISD::FMAXNUM_IEEE: + case ISD::FMAXIMUMNUM: return AMDGPUISD::FMAX3; case ISD::FMAXIMUM: return AMDGPUISD::FMAXIMUM3; @@ -13351,6 +13804,7 @@ static unsigned minMaxOpcToMin3Max3Opc(unsigned Opc) { return AMDGPUISD::UMAX3; case ISD::FMINNUM: case ISD::FMINNUM_IEEE: + case ISD::FMINIMUMNUM: return AMDGPUISD::FMIN3; case ISD::FMINIMUM: return AMDGPUISD::FMINIMUM3; @@ -13428,10 +13882,34 @@ SDValue SITargetLowering::performFPMed3ImmCombine(SelectionDAG &DAG, if (K0->getValueAPF() > K1->getValueAPF()) return SDValue(); + // med3 with a nan input acts like + // v_min_f32(v_min_f32(S0.f32, S1.f32), S2.f32) + // + // So the result depends on whether the IEEE mode bit is enabled or not with a + // signaling nan input. + // ieee=1 + // s0 snan: yields s2 + // s1 snan: yields s2 + // s2 snan: qnan + + // s0 qnan: min(s1, s2) + // s1 qnan: min(s0, s2) + // s2 qnan: min(s0, s1) + + // ieee=0 + // s0 snan: min(s1, s2) + // s1 snan: min(s0, s2) + // s2 snan: qnan + + // s0 qnan: min(s1, s2) + // s1 qnan: min(s0, s2) + // s2 qnan: min(s0, s1) const MachineFunction &MF = DAG.getMachineFunction(); const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); - // TODO: Check IEEE bit enabled? + // TODO: Check IEEE bit enabled. We can form fmed3 with IEEE=0 regardless of + // whether the input is a signaling nan if op0 is fmaximum or fmaximumnum. We + // can only form if op0 is fmaxnum_ieee if IEEE=1. EVT VT = Op0.getValueType(); if (Info->getMode().DX10Clamp) { // If dx10_clamp is enabled, NaNs clamp to 0.0. This is the same as the @@ -13472,13 +13950,16 @@ static bool supportsMin3Max3(const GCNSubtarget &Subtarget, unsigned Opc, case ISD::FMAXNUM: case ISD::FMINNUM_IEEE: case ISD::FMAXNUM_IEEE: + case ISD::FMINIMUMNUM: + case ISD::FMAXIMUMNUM: case AMDGPUISD::FMIN_LEGACY: case AMDGPUISD::FMAX_LEGACY: return (VT == MVT::f32) || (VT == MVT::f16 && Subtarget.hasMin3Max3_16()); case ISD::FMINIMUM: case ISD::FMAXIMUM: return (VT == MVT::f32 && Subtarget.hasMinimum3Maximum3F32()) || - (VT == MVT::f16 && Subtarget.hasMinimum3Maximum3F16()); + (VT == MVT::f16 && Subtarget.hasMinimum3Maximum3F16()) || + (VT == MVT::v2f16 && Subtarget.hasMinimum3Maximum3PKF16()); case ISD::SMAX: case ISD::SMIN: case ISD::UMAX: @@ -13546,9 +14027,14 @@ SDValue SITargetLowering::performMinMaxCombine(SDNode *N, return Med3; } - // fminnum(fmaxnum(x, K0), K1), K0 < K1 && !is_snan(x) -> fmed3(x, K0, K1) + // if !is_snan(x): + // fminnum(fmaxnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1) + // fminnum_ieee(fmaxnum_ieee(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1) + // fminnumnum(fmaxnumnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1) + // fmin_legacy(fmax_legacy(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1) if (((Opc == ISD::FMINNUM && Op0.getOpcode() == ISD::FMAXNUM) || (Opc == ISD::FMINNUM_IEEE && Op0.getOpcode() == ISD::FMAXNUM_IEEE) || + (Opc == ISD::FMINIMUMNUM && Op0.getOpcode() == ISD::FMAXIMUMNUM) || (Opc == AMDGPUISD::FMIN_LEGACY && Op0.getOpcode() == AMDGPUISD::FMAX_LEGACY)) && (VT == MVT::f32 || VT == MVT::f64 || @@ -13559,6 +14045,17 @@ SDValue SITargetLowering::performMinMaxCombine(SDNode *N, return Res; } + // Prefer fminnum_ieee over fminimum. For gfx950, minimum/maximum are legal + // for some types, but at a higher cost since it's implemented with a 3 + // operand form. + const SDNodeFlags Flags = N->getFlags(); + if ((Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM) && + !Subtarget->hasIEEEMinimumMaximumInsts() && Flags.hasNoNaNs()) { + unsigned NewOpc = + Opc == ISD::FMINIMUM ? ISD::FMINNUM_IEEE : ISD::FMAXNUM_IEEE; + return DAG.getNode(NewOpc, SDLoc(N), VT, Op0, Op1, Flags); + } + return SDValue(); } @@ -14623,6 +15120,49 @@ SDValue SITargetLowering::performAddCombine(SDNode *N, return SDValue(); } +SDValue SITargetLowering::performPtrAddCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDLoc DL(N); + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + if (N1.getOpcode() == ISD::ADD) { + // (ptradd x, (add y, z)) -> (ptradd (ptradd x, y), z) if z is a constant, + // y is not, and (add y, z) is used only once. + // (ptradd x, (add y, z)) -> (ptradd (ptradd x, z), y) if y is a constant, + // z is not, and (add y, z) is used only once. + // The goal is to move constant offsets to the outermost ptradd, to create + // more opportunities to fold offsets into memory instructions. + // Together with the generic combines in DAGCombiner.cpp, this also + // implements (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y)). + // + // This transform is here instead of in the general DAGCombiner as it can + // turn in-bounds pointer arithmetic out-of-bounds, which is problematic for + // AArch64's CPA. + SDValue X = N0; + SDValue Y = N1.getOperand(0); + SDValue Z = N1.getOperand(1); + if (N1.hasOneUse()) { + bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y); + bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z); + if (ZIsConstant != YIsConstant) { + // If both additions in the original were NUW, the new ones are as well. + SDNodeFlags Flags = + (N->getFlags() & N1->getFlags()) & SDNodeFlags::NoUnsignedWrap; + if (YIsConstant) + std::swap(Y, Z); + + SDValue Inner = DAG.getMemBasePlusOffset(X, Y, DL, Flags); + DCI.AddToWorklist(Inner.getNode()); + return DAG.getMemBasePlusOffset(Inner, Z, DL, Flags); + } + } + } + + return SDValue(); +} + SDValue SITargetLowering::performSubCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -14827,6 +15367,12 @@ SDValue SITargetLowering::performFMulCombine(SDNode *N, EVT ScalarVT = VT.getScalarType(); EVT IntVT = VT.changeElementType(MVT::i32); + if (!N->isDivergent() && getSubtarget()->hasSALUFloatInsts() && + (ScalarVT == MVT::f32 || ScalarVT == MVT::f16)) { + // Prefer to use s_mul_f16/f32 instead of v_ldexp_f16/f32. + return SDValue(); + } + SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); @@ -15155,6 +15701,8 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N, switch (N->getOpcode()) { case ISD::ADD: return performAddCombine(N, DCI); + case ISD::PTRADD: + return performPtrAddCombine(N, DCI); case ISD::SUB: return performSubCombine(N, DCI); case ISD::UADDO_CARRY: @@ -15176,6 +15724,8 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N, case ISD::FMINNUM_IEEE: case ISD::FMAXIMUM: case ISD::FMINIMUM: + case ISD::FMAXIMUMNUM: + case ISD::FMINIMUMNUM: case ISD::SMAX: case ISD::SMIN: case ISD::UMAX: @@ -15315,10 +15865,8 @@ SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node, unsigned NewDmask = 0; unsigned TFEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::tfe) - 1; unsigned LWEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::lwe) - 1; - bool UsesTFC = ((int(TFEIdx) >= 0 && Node->getConstantOperandVal(TFEIdx)) || - (int(LWEIdx) >= 0 && Node->getConstantOperandVal(LWEIdx))) - ? true - : false; + bool UsesTFC = (int(TFEIdx) >= 0 && Node->getConstantOperandVal(TFEIdx)) || + (int(LWEIdx) >= 0 && Node->getConstantOperandVal(LWEIdx)); unsigned TFCLane = 0; bool HasChain = Node->getNumValues() > 1; @@ -15408,9 +15956,9 @@ SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node, // Adjust the writemask in the node SmallVector<SDValue, 12> Ops; - Ops.insert(Ops.end(), Node->op_begin(), Node->op_begin() + DmaskIdx); + llvm::append_range(Ops, Node->ops().take_front(DmaskIdx)); Ops.push_back(DAG.getTargetConstant(NewDmask, SDLoc(Node), MVT::i32)); - Ops.insert(Ops.end(), Node->op_begin() + DmaskIdx + 1, Node->op_end()); + llvm::append_range(Ops, Node->ops().drop_front(DmaskIdx + 1)); MVT SVT = Node->getValueType(0).getVectorElementType().getSimpleVT(); @@ -15894,7 +16442,8 @@ SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI_, case 'v': switch (BitWidth) { case 16: - RC = &AMDGPU::VGPR_32RegClass; + RC = Subtarget->useRealTrue16Insts() ? &AMDGPU::VGPR_16RegClass + : &AMDGPU::VGPR_32RegClass; break; default: RC = TRI->getVGPRClassForBitWidth(BitWidth); @@ -16296,16 +16845,18 @@ void SITargetLowering::computeKnownBitsForFrameIndex( Known.Zero.setHighBits(getSubtarget()->getKnownHighZeroBitsForFrameIndex()); } -static void knownBitsForWorkitemID(const GCNSubtarget &ST, GISelKnownBits &KB, - KnownBits &Known, unsigned Dim) { +static void knownBitsForWorkitemID(const GCNSubtarget &ST, + GISelValueTracking &VT, KnownBits &Known, + unsigned Dim) { unsigned MaxValue = - ST.getMaxWorkitemID(KB.getMachineFunction().getFunction(), Dim); + ST.getMaxWorkitemID(VT.getMachineFunction().getFunction(), Dim); Known.Zero.setHighBits(llvm::countl_zero(MaxValue)); } void SITargetLowering::computeKnownBitsForTargetInstr( - GISelKnownBits &KB, Register R, KnownBits &Known, const APInt &DemandedElts, - const MachineRegisterInfo &MRI, unsigned Depth) const { + GISelValueTracking &VT, Register R, KnownBits &Known, + const APInt &DemandedElts, const MachineRegisterInfo &MRI, + unsigned Depth) const { const MachineInstr *MI = MRI.getVRegDef(R); switch (MI->getOpcode()) { case AMDGPU::G_INTRINSIC: @@ -16313,13 +16864,13 @@ void SITargetLowering::computeKnownBitsForTargetInstr( Intrinsic::ID IID = cast<GIntrinsic>(MI)->getIntrinsicID(); switch (IID) { case Intrinsic::amdgcn_workitem_id_x: - knownBitsForWorkitemID(*getSubtarget(), KB, Known, 0); + knownBitsForWorkitemID(*getSubtarget(), VT, Known, 0); break; case Intrinsic::amdgcn_workitem_id_y: - knownBitsForWorkitemID(*getSubtarget(), KB, Known, 1); + knownBitsForWorkitemID(*getSubtarget(), VT, Known, 1); break; case Intrinsic::amdgcn_workitem_id_z: - knownBitsForWorkitemID(*getSubtarget(), KB, Known, 2); + knownBitsForWorkitemID(*getSubtarget(), VT, Known, 2); break; case Intrinsic::amdgcn_mbcnt_lo: case Intrinsic::amdgcn_mbcnt_hi: { @@ -16329,7 +16880,7 @@ void SITargetLowering::computeKnownBitsForTargetInstr( ? getSubtarget()->getWavefrontSizeLog2() : 5); KnownBits Known2; - KB.computeKnownBitsImpl(MI->getOperand(3).getReg(), Known2, DemandedElts, + VT.computeKnownBitsImpl(MI->getOperand(3).getReg(), Known2, DemandedElts, Depth + 1); Known = KnownBits::add(Known, Known2); break; @@ -16356,17 +16907,17 @@ void SITargetLowering::computeKnownBitsForTargetInstr( auto [Dst, Src0, Src1, Src2] = MI->getFirst4Regs(); KnownBits Known2; - KB.computeKnownBitsImpl(Src2, Known2, DemandedElts, Depth + 1); + VT.computeKnownBitsImpl(Src2, Known2, DemandedElts, Depth + 1); if (Known2.isUnknown()) break; KnownBits Known1; - KB.computeKnownBitsImpl(Src1, Known1, DemandedElts, Depth + 1); + VT.computeKnownBitsImpl(Src1, Known1, DemandedElts, Depth + 1); if (Known1.isUnknown()) break; KnownBits Known0; - KB.computeKnownBitsImpl(Src0, Known0, DemandedElts, Depth + 1); + VT.computeKnownBitsImpl(Src0, Known0, DemandedElts, Depth + 1); if (Known0.isUnknown()) break; @@ -16379,15 +16930,16 @@ void SITargetLowering::computeKnownBitsForTargetInstr( } Align SITargetLowering::computeKnownAlignForTargetInstr( - GISelKnownBits &KB, Register R, const MachineRegisterInfo &MRI, + GISelValueTracking &VT, Register R, const MachineRegisterInfo &MRI, unsigned Depth) const { const MachineInstr *MI = MRI.getVRegDef(R); if (auto *GI = dyn_cast<GIntrinsic>(MI)) { // FIXME: Can this move to generic code? What about the case where the call // site specifies a lower alignment? Intrinsic::ID IID = GI->getIntrinsicID(); - LLVMContext &Ctx = KB.getMachineFunction().getFunction().getContext(); - AttributeList Attrs = Intrinsic::getAttributes(Ctx, IID); + LLVMContext &Ctx = VT.getMachineFunction().getFunction().getContext(); + AttributeList Attrs = + Intrinsic::getAttributes(Ctx, IID, Intrinsic::getType(Ctx, IID)); if (MaybeAlign RetAlign = Attrs.getRetAlignment()) return *RetAlign; } @@ -16568,6 +17120,7 @@ bool SITargetLowering::denormalsEnabledForType( } bool SITargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, + const APInt &DemandedElts, const SelectionDAG &DAG, bool SNaN, unsigned Depth) const { @@ -16580,8 +17133,8 @@ bool SITargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, return DAG.isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1); } - return AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(Op, DAG, SNaN, - Depth); + return AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(Op, DemandedElts, + DAG, SNaN, Depth); } // On older subtargets, global FP atomic instructions have a hardcoded FP mode @@ -16603,8 +17156,8 @@ static bool atomicIgnoresDenormalModeOrFPModeIsFTZ(const AtomicRMWInst *RMW) { static OptimizationRemark emitAtomicRMWLegalRemark(const AtomicRMWInst *RMW) { LLVMContext &Ctx = RMW->getContext(); - StringRef SS = Ctx.getSyncScopeName(RMW->getSyncScopeID()).value_or(""); - StringRef MemScope = SS.empty() ? StringRef("system") : SS; + StringRef MemScope = + Ctx.getSyncScopeName(RMW->getSyncScopeID()).value_or("system"); return OptimizationRemark(DEBUG_TYPE, "Passed", RMW) << "Hardware instruction generated for atomic " @@ -16820,39 +17373,39 @@ SITargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const { // safe. The message phrasing also should be better. if (globalMemoryFPAtomicIsLegal(*Subtarget, RMW, HasSystemScope)) { if (AS == AMDGPUAS::FLAT_ADDRESS) { - // gfx940, gfx12 + // gfx942, gfx12 if (Subtarget->hasAtomicFlatPkAdd16Insts() && isV2F16OrV2BF16(Ty)) return ReportUnsafeHWInst(AtomicExpansionKind::None); } else if (AMDGPU::isExtendedGlobalAddrSpace(AS)) { - // gfx90a, gfx940, gfx12 + // gfx90a, gfx942, gfx12 if (Subtarget->hasAtomicBufferGlobalPkAddF16Insts() && isV2F16(Ty)) return ReportUnsafeHWInst(AtomicExpansionKind::None); - // gfx940, gfx12 + // gfx942, gfx12 if (Subtarget->hasAtomicGlobalPkAddBF16Inst() && isV2BF16(Ty)) return ReportUnsafeHWInst(AtomicExpansionKind::None); } else if (AS == AMDGPUAS::BUFFER_FAT_POINTER) { - // gfx90a, gfx940, gfx12 + // gfx90a, gfx942, gfx12 if (Subtarget->hasAtomicBufferGlobalPkAddF16Insts() && isV2F16(Ty)) return ReportUnsafeHWInst(AtomicExpansionKind::None); - // While gfx90a/gfx940 supports v2bf16 for global/flat, it does not for + // While gfx90a/gfx942 supports v2bf16 for global/flat, it does not for // buffer. gfx12 does have the buffer version. if (Subtarget->hasAtomicBufferPkAddBF16Inst() && isV2BF16(Ty)) return ReportUnsafeHWInst(AtomicExpansionKind::None); } - // global and flat atomic fadd f64: gfx90a, gfx940. + // global and flat atomic fadd f64: gfx90a, gfx942. if (Subtarget->hasFlatBufferGlobalAtomicFaddF64Inst() && Ty->isDoubleTy()) return ReportUnsafeHWInst(AtomicExpansionKind::None); if (AS != AMDGPUAS::FLAT_ADDRESS) { if (Ty->isFloatTy()) { - // global/buffer atomic fadd f32 no-rtn: gfx908, gfx90a, gfx940, + // global/buffer atomic fadd f32 no-rtn: gfx908, gfx90a, gfx942, // gfx11+. if (RMW->use_empty() && Subtarget->hasAtomicFaddNoRtnInsts()) return ReportUnsafeHWInst(AtomicExpansionKind::None); - // global/buffer atomic fadd f32 rtn: gfx90a, gfx940, gfx11+. + // global/buffer atomic fadd f32 rtn: gfx90a, gfx942, gfx11+. if (!RMW->use_empty() && Subtarget->hasAtomicFaddRtnInsts()) return ReportUnsafeHWInst(AtomicExpansionKind::None); } else { @@ -16864,7 +17417,7 @@ SITargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const { } } - // flat atomic fadd f32: gfx940, gfx11+. + // flat atomic fadd f32: gfx942, gfx11+. if (AS == AMDGPUAS::FLAT_ADDRESS && Ty->isFloatTy()) { if (Subtarget->hasFlatAtomicFaddF32Inst()) return ReportUnsafeHWInst(AtomicExpansionKind::None); @@ -16903,7 +17456,7 @@ SITargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const { // float, double restored in gfx10. // double removed again in gfx11, so only f32 for gfx11/gfx12. // - // For gfx9, gfx90a and gfx940 support f64 for global (same as fadd), but + // For gfx9, gfx90a and gfx942 support f64 for global (same as fadd), but // no f32. if (AS == AMDGPUAS::FLAT_ADDRESS) { if (Subtarget->hasAtomicFMinFMaxF32FlatInsts() && Ty->isFloatTy()) @@ -17115,7 +17668,7 @@ SITargetLowering::getTargetMMOFlags(const Instruction &I) const { bool SITargetLowering::checkForPhysRegDependency( SDNode *Def, SDNode *User, unsigned Op, const TargetRegisterInfo *TRI, - const TargetInstrInfo *TII, unsigned &PhysReg, int &Cost) const { + const TargetInstrInfo *TII, MCRegister &PhysReg, int &Cost) const { if (User->getOpcode() != ISD::CopyToReg) return false; if (!Def->isMachineOpcode()) @@ -17138,33 +17691,6 @@ bool SITargetLowering::checkForPhysRegDependency( return false; } -/// Check if it is profitable to hoist instruction in then/else to if. -bool SITargetLowering::isProfitableToHoist(Instruction *I) const { - if (!I->hasOneUse()) - return true; - - Instruction *User = I->user_back(); - // TODO: Add more patterns that are not profitable to hoist and - // handle modifiers such as fabs and fneg - switch (I->getOpcode()) { - case Instruction::FMul: { - if (User->getOpcode() != Instruction::FSub && - User->getOpcode() != Instruction::FAdd) - return true; - - const TargetOptions &Options = getTargetMachine().Options; - - return ((!I->hasAllowContract() || !User->hasAllowContract()) && - Options.AllowFPOpFusion != FPOpFusion::Fast && - !Options.UnsafeFPMath) || - !isFMAFasterThanFMulAndFAdd(*I->getFunction(), User->getType()); - } - default: - return true; - } - return true; -} - void SITargetLowering::emitExpandAtomicAddrSpacePredicate( Instruction *AI) const { // Given: atomicrmw fadd ptr %addr, float %val ordering @@ -17237,9 +17763,11 @@ void SITargetLowering::emitExpandAtomicAddrSpacePredicate( // where we only insert a check for private and still use the flat instruction // for global and shared. - bool FullFlatEmulation = RMW && RMW->getOperation() == AtomicRMWInst::FAdd && - Subtarget->hasAtomicFaddInsts() && - RMW->getType()->isFloatTy(); + bool FullFlatEmulation = + RMW && RMW->getOperation() == AtomicRMWInst::FAdd && + ((Subtarget->hasAtomicFaddInsts() && RMW->getType()->isFloatTy()) || + (Subtarget->hasFlatBufferGlobalAtomicFaddF64Inst() && + RMW->getType()->isDoubleTy())); // If the return value isn't used, do not introduce a false use in the phi. bool ReturnValueIsUsed = !AI->use_empty(); @@ -17267,8 +17795,8 @@ void SITargetLowering::emitExpandAtomicAddrSpacePredicate( Value *LoadedShared = nullptr; if (FullFlatEmulation) { - CallInst *IsShared = Builder.CreateIntrinsic( - Intrinsic::amdgcn_is_shared, {}, {Addr}, nullptr, "is.shared"); + CallInst *IsShared = Builder.CreateIntrinsic(Intrinsic::amdgcn_is_shared, + {Addr}, nullptr, "is.shared"); Builder.CreateCondBr(IsShared, SharedBB, CheckPrivateBB); Builder.SetInsertPoint(SharedBB); Value *CastToLocal = Builder.CreateAddrSpaceCast( @@ -17283,8 +17811,8 @@ void SITargetLowering::emitExpandAtomicAddrSpacePredicate( Builder.SetInsertPoint(CheckPrivateBB); } - CallInst *IsPrivate = Builder.CreateIntrinsic( - Intrinsic::amdgcn_is_private, {}, {Addr}, nullptr, "is.private"); + CallInst *IsPrivate = Builder.CreateIntrinsic(Intrinsic::amdgcn_is_private, + {Addr}, nullptr, "is.private"); Builder.CreateCondBr(IsPrivate, PrivateBB, GlobalBB); Builder.SetInsertPoint(PrivateBB); |
