aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp')
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp495
1 files changed, 338 insertions, 157 deletions
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index cca9fa72d0ca..3414fe758eff 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -19,7 +19,7 @@
#include "AMDGPUMemoryUtils.h"
#include "SIMachineFunctionInfo.h"
#include "llvm/CodeGen/Analysis.h"
-#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
+#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/IntrinsicsAMDGPU.h"
@@ -423,6 +423,11 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction({ISD::FLOG10, ISD::FLOG, ISD::FEXP, ISD::FEXP10}, MVT::f16,
Custom);
+ setOperationAction(ISD::FCANONICALIZE, {MVT::f32, MVT::f64}, Legal);
+ if (Subtarget->has16BitInsts()) {
+ setOperationAction(ISD::FCANONICALIZE, MVT::f16, Legal);
+ }
+
// FIXME: These IS_FPCLASS vector fp types are marked custom so it reaches
// scalarization code. Can be removed when IS_FPCLASS expand isn't called by
// default unless marked custom/legal.
@@ -661,6 +666,8 @@ static bool fnegFoldsIntoOpcode(unsigned Opc) {
case ISD::FMAXNUM_IEEE:
case ISD::FMINIMUM:
case ISD::FMAXIMUM:
+ case ISD::FMINIMUMNUM:
+ case ISD::FMAXIMUMNUM:
case ISD::SELECT:
case ISD::FSIN:
case ISD::FTRUNC:
@@ -796,8 +803,8 @@ EVT AMDGPUTargetLowering::getTypeForExtReturn(LLVMContext &Context, EVT VT,
return EVT::getIntegerVT(Context, 32 * ((Size + 31) / 32));
}
-MVT AMDGPUTargetLowering::getVectorIdxTy(const DataLayout &) const {
- return MVT::i32;
+unsigned AMDGPUTargetLowering::getVectorIdxWidth(const DataLayout &) const {
+ return 32;
}
bool AMDGPUTargetLowering::isSelectSupported(SelectSupportKind SelType) const {
@@ -819,11 +826,11 @@ bool AMDGPUTargetLowering::ShouldShrinkFPConstant(EVT VT) const {
return (ScalarVT != MVT::f32 && ScalarVT != MVT::f64);
}
-bool AMDGPUTargetLowering::shouldReduceLoadWidth(SDNode *N,
- ISD::LoadExtType ExtTy,
- EVT NewVT) const {
+bool AMDGPUTargetLowering::shouldReduceLoadWidth(
+ SDNode *N, ISD::LoadExtType ExtTy, EVT NewVT,
+ std::optional<unsigned> ByteOffset) const {
// TODO: This may be worth removing. Check regression tests for diffs.
- if (!TargetLoweringBase::shouldReduceLoadWidth(N, ExtTy, NewVT))
+ if (!TargetLoweringBase::shouldReduceLoadWidth(N, ExtTy, NewVT, ByteOffset))
return false;
unsigned NewSize = NewVT.getStoreSizeInBits();
@@ -846,7 +853,7 @@ bool AMDGPUTargetLowering::shouldReduceLoadWidth(SDNode *N,
AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||
(isa<LoadSDNode>(N) && AS == AMDGPUAS::GLOBAL_ADDRESS &&
MN->isInvariant())) &&
- AMDGPUInstrInfo::isUniformMMO(MN->getMemOperand()))
+ AMDGPU::isUniformMMO(MN->getMemOperand()))
return false;
// Don't produce extloads from sub 32-bit types. SI doesn't have scalar
@@ -1040,8 +1047,12 @@ bool AMDGPUTargetLowering::isNarrowingProfitable(SDNode *N, EVT SrcVT,
case ISD::MUL:
case ISD::SETCC:
case ISD::SELECT:
+ case ISD::SMIN:
+ case ISD::SMAX:
+ case ISD::UMIN:
+ case ISD::UMAX:
if (Subtarget->has16BitInsts() &&
- (DestVT.isVector() ? !Subtarget->hasVOP3PInsts() : true)) {
+ (!DestVT.isVector() || !Subtarget->hasVOP3PInsts())) {
// Don't narrow back down to i16 if promoted to i32 already.
if (!N->isDivergent() && DestVT.isInteger() &&
DestVT.getScalarSizeInBits() > 1 &&
@@ -1136,7 +1147,7 @@ CCAssignFn *AMDGPUCallLowering::CCAssignFnForCall(CallingConv::ID CC,
case CallingConv::AMDGPU_KERNEL:
case CallingConv::SPIR_KERNEL:
default:
- report_fatal_error("Unsupported calling convention for call");
+ reportFatalUsageError("unsupported calling convention for call");
}
}
@@ -1163,7 +1174,7 @@ CCAssignFn *AMDGPUCallLowering::CCAssignFnForReturn(CallingConv::ID CC,
case CallingConv::Cold:
return RetCC_AMDGPU_Func;
default:
- report_fatal_error("Unsupported calling convention.");
+ reportFatalUsageError("unsupported calling convention");
}
}
@@ -1383,13 +1394,12 @@ SDValue AMDGPUTargetLowering::lowerUnhandledCall(CallLoweringInfo &CLI,
else if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
FuncName = G->getGlobal()->getName();
- DiagnosticInfoUnsupported NoCalls(
- Fn, Reason + FuncName, CLI.DL.getDebugLoc());
- DAG.getContext()->diagnose(NoCalls);
+ DAG.getContext()->diagnose(
+ DiagnosticInfoUnsupported(Fn, Reason + FuncName, CLI.DL.getDebugLoc()));
if (!CLI.IsTailCall) {
for (ISD::InputArg &Arg : CLI.Ins)
- InVals.push_back(DAG.getUNDEF(Arg.VT));
+ InVals.push_back(DAG.getPOISON(Arg.VT));
}
return DAG.getEntryNode();
@@ -1404,9 +1414,8 @@ SDValue AMDGPUTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
const Function &Fn = DAG.getMachineFunction().getFunction();
- DiagnosticInfoUnsupported NoDynamicAlloca(Fn, "unsupported dynamic alloca",
- SDLoc(Op).getDebugLoc());
- DAG.getContext()->diagnose(NoDynamicAlloca);
+ DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+ Fn, "unsupported dynamic alloca", SDLoc(Op).getDebugLoc()));
auto Ops = {DAG.getConstant(0, SDLoc(), Op.getValueType()), Op.getOperand(0)};
return DAG.getMergeValues(Ops, SDLoc());
}
@@ -1521,10 +1530,9 @@ SDValue AMDGPUTargetLowering::LowerGlobalAddress(AMDGPUMachineFunction* MFI,
!AMDGPU::isNamedBarrier(*cast<GlobalVariable>(GV))) {
SDLoc DL(Op);
const Function &Fn = DAG.getMachineFunction().getFunction();
- DiagnosticInfoUnsupported BadLDSDecl(
- Fn, "local memory global used by non-kernel function",
- DL.getDebugLoc(), DS_Warning);
- DAG.getContext()->diagnose(BadLDSDecl);
+ DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+ Fn, "local memory global used by non-kernel function",
+ DL.getDebugLoc(), DS_Warning));
// We currently don't have a way to correctly allocate LDS objects that
// aren't directly associated with a kernel. We do force inlining of
@@ -1535,7 +1543,7 @@ SDValue AMDGPUTargetLowering::LowerGlobalAddress(AMDGPUMachineFunction* MFI,
SDValue OutputChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other,
Trap, DAG.getRoot());
DAG.setRoot(OutputChain);
- return DAG.getUNDEF(Op.getValueType());
+ return DAG.getPOISON(Op.getValueType());
}
// XXX: What does the value of G->getOffset() mean?
@@ -1857,7 +1865,7 @@ SDValue AMDGPUTargetLowering::SplitVectorLoad(const SDValue Op,
// This is the case that the vector is power of two so was evenly split.
Join = DAG.getNode(ISD::CONCAT_VECTORS, SL, VT, LoLoad, HiLoad);
} else {
- Join = DAG.getNode(ISD::INSERT_SUBVECTOR, SL, VT, DAG.getUNDEF(VT), LoLoad,
+ Join = DAG.getNode(ISD::INSERT_SUBVECTOR, SL, VT, DAG.getPOISON(VT), LoLoad,
DAG.getVectorIdxConstant(0, SL));
Join = DAG.getNode(
HiVT.isVector() ? ISD::INSERT_SUBVECTOR : ISD::INSERT_VECTOR_ELT, SL,
@@ -2971,7 +2979,8 @@ SDValue AMDGPUTargetLowering::lowerFEXP10Unsafe(SDValue X, const SDLoc &SL,
SelectionDAG &DAG,
SDNodeFlags Flags) const {
const EVT VT = X.getValueType();
- const unsigned Exp2Op = VT == MVT::f32 ? AMDGPUISD::EXP : ISD::FEXP2;
+ const unsigned Exp2Op = VT == MVT::f32 ? static_cast<unsigned>(AMDGPUISD::EXP)
+ : static_cast<unsigned>(ISD::FEXP2);
if (VT != MVT::f32 || !needsDenormHandlingF32(DAG, X, Flags)) {
// exp2(x * 0x1.a92000p+1f) * exp2(x * 0x1.4f0978p-11f);
@@ -3578,15 +3587,22 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) con
return SDValue();
}
- assert(N0.getSimpleValueType() == MVT::f64);
+ return LowerF64ToF16Safe(N0, DL, DAG);
+}
+
+// return node in i32
+SDValue AMDGPUTargetLowering::LowerF64ToF16Safe(SDValue Src, const SDLoc &DL,
+ SelectionDAG &DAG) const {
+ assert(Src.getSimpleValueType() == MVT::f64);
// f64 -> f16 conversion using round-to-nearest-even rounding mode.
+ // TODO: We can generate better code for True16.
const unsigned ExpMask = 0x7ff;
const unsigned ExpBiasf64 = 1023;
const unsigned ExpBiasf16 = 15;
SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
SDValue One = DAG.getConstant(1, DL, MVT::i32);
- SDValue U = DAG.getNode(ISD::BITCAST, DL, MVT::i64, N0);
+ SDValue U = DAG.getNode(ISD::BITCAST, DL, MVT::i64, Src);
SDValue UH = DAG.getNode(ISD::SRL, DL, MVT::i64, U,
DAG.getConstant(32, DL, MVT::i64));
UH = DAG.getZExtOrTrunc(UH, DL, MVT::i32);
@@ -3660,8 +3676,7 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) con
Sign = DAG.getNode(ISD::AND, DL, MVT::i32, Sign,
DAG.getConstant(0x8000, DL, MVT::i32));
- V = DAG.getNode(ISD::OR, DL, MVT::i32, Sign, V);
- return DAG.getZExtOrTrunc(V, DL, Op.getValueType());
+ return DAG.getNode(ISD::OR, DL, MVT::i32, Sign, V);
}
SDValue AMDGPUTargetLowering::LowerFP_TO_INT(const SDValue Op,
@@ -3843,7 +3858,7 @@ bool AMDGPUTargetLowering::shouldCombineMemoryType(EVT VT) const {
return true;
}
-// Replace load of an illegal type with a store of a bitcast to a friendlier
+// Replace load of an illegal type with a bitcast from a load of a friendlier
// type.
SDValue AMDGPUTargetLowering::performLoadCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
@@ -3991,7 +4006,8 @@ SDValue AMDGPUTargetLowering::performIntrinsicWOChainCombine(
case Intrinsic::amdgcn_rsq:
case Intrinsic::amdgcn_rcp_legacy:
case Intrinsic::amdgcn_rsq_legacy:
- case Intrinsic::amdgcn_rsq_clamp: {
+ case Intrinsic::amdgcn_rsq_clamp:
+ case Intrinsic::amdgcn_tanh: {
// FIXME: This is probably wrong. If src is an sNaN, it won't be quieted
SDValue Src = N->getOperand(1);
return Src.isUndef() ? Src : SDValue();
@@ -4040,152 +4056,308 @@ SDValue AMDGPUTargetLowering::splitBinaryBitConstantOpImpl(
SDValue AMDGPUTargetLowering::performShlCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
EVT VT = N->getValueType(0);
-
- ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (!RHS)
- return SDValue();
-
SDValue LHS = N->getOperand(0);
- unsigned RHSVal = RHS->getZExtValue();
- if (!RHSVal)
- return LHS;
-
+ SDValue RHS = N->getOperand(1);
+ ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);
SDLoc SL(N);
SelectionDAG &DAG = DCI.DAG;
- switch (LHS->getOpcode()) {
- default:
- break;
- case ISD::ZERO_EXTEND:
- case ISD::SIGN_EXTEND:
- case ISD::ANY_EXTEND: {
- SDValue X = LHS->getOperand(0);
+ unsigned RHSVal;
+ if (CRHS) {
+ RHSVal = CRHS->getZExtValue();
+ if (!RHSVal)
+ return LHS;
- if (VT == MVT::i32 && RHSVal == 16 && X.getValueType() == MVT::i16 &&
- isOperationLegal(ISD::BUILD_VECTOR, MVT::v2i16)) {
- // Prefer build_vector as the canonical form if packed types are legal.
- // (shl ([asz]ext i16:x), 16 -> build_vector 0, x
- SDValue Vec = DAG.getBuildVector(MVT::v2i16, SL,
- { DAG.getConstant(0, SL, MVT::i16), LHS->getOperand(0) });
- return DAG.getNode(ISD::BITCAST, SL, MVT::i32, Vec);
- }
-
- // shl (ext x) => zext (shl x), if shift does not overflow int
- if (VT != MVT::i64)
- break;
- KnownBits Known = DAG.computeKnownBits(X);
- unsigned LZ = Known.countMinLeadingZeros();
- if (LZ < RHSVal)
+ switch (LHS->getOpcode()) {
+ default:
break;
- EVT XVT = X.getValueType();
- SDValue Shl = DAG.getNode(ISD::SHL, SL, XVT, X, SDValue(RHS, 0));
- return DAG.getZExtOrTrunc(Shl, SL, VT);
- }
+ case ISD::ZERO_EXTEND:
+ case ISD::SIGN_EXTEND:
+ case ISD::ANY_EXTEND: {
+ SDValue X = LHS->getOperand(0);
+
+ if (VT == MVT::i32 && RHSVal == 16 && X.getValueType() == MVT::i16 &&
+ isOperationLegal(ISD::BUILD_VECTOR, MVT::v2i16)) {
+ // Prefer build_vector as the canonical form if packed types are legal.
+ // (shl ([asz]ext i16:x), 16 -> build_vector 0, x
+ SDValue Vec = DAG.getBuildVector(
+ MVT::v2i16, SL,
+ {DAG.getConstant(0, SL, MVT::i16), LHS->getOperand(0)});
+ return DAG.getNode(ISD::BITCAST, SL, MVT::i32, Vec);
+ }
+
+ // shl (ext x) => zext (shl x), if shift does not overflow int
+ if (VT != MVT::i64)
+ break;
+ KnownBits Known = DAG.computeKnownBits(X);
+ unsigned LZ = Known.countMinLeadingZeros();
+ if (LZ < RHSVal)
+ break;
+ EVT XVT = X.getValueType();
+ SDValue Shl = DAG.getNode(ISD::SHL, SL, XVT, X, SDValue(CRHS, 0));
+ return DAG.getZExtOrTrunc(Shl, SL, VT);
+ }
+ }
}
- if (VT != MVT::i64)
+ if (VT.getScalarType() != MVT::i64)
return SDValue();
- // i64 (shl x, C) -> (build_pair 0, (shl x, C -32))
+ // i64 (shl x, C) -> (build_pair 0, (shl x, C - 32))
// On some subtargets, 64-bit shift is a quarter rate instruction. In the
// common case, splitting this into a move and a 32-bit shift is faster and
// the same code size.
- if (RHSVal < 32)
+ KnownBits Known = DAG.computeKnownBits(RHS);
+
+ EVT ElementType = VT.getScalarType();
+ EVT TargetScalarType = ElementType.getHalfSizedIntegerVT(*DAG.getContext());
+ EVT TargetType = VT.isVector() ? VT.changeVectorElementType(TargetScalarType)
+ : TargetScalarType;
+
+ if (Known.getMinValue().getZExtValue() < TargetScalarType.getSizeInBits())
return SDValue();
+ SDValue ShiftAmt;
- SDValue ShiftAmt = DAG.getConstant(RHSVal - 32, SL, MVT::i32);
+ if (CRHS) {
+ ShiftAmt = DAG.getConstant(RHSVal - TargetScalarType.getSizeInBits(), SL,
+ TargetType);
+ } else {
+ SDValue TruncShiftAmt = DAG.getNode(ISD::TRUNCATE, SL, TargetType, RHS);
+ const SDValue ShiftMask =
+ DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
+ // This AND instruction will clamp out of bounds shift values.
+ // It will also be removed during later instruction selection.
+ ShiftAmt = DAG.getNode(ISD::AND, SL, TargetType, TruncShiftAmt, ShiftMask);
+ }
- SDValue Lo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, LHS);
- SDValue NewShift = DAG.getNode(ISD::SHL, SL, MVT::i32, Lo, ShiftAmt);
+ SDValue Lo = DAG.getNode(ISD::TRUNCATE, SL, TargetType, LHS);
+ SDValue NewShift =
+ DAG.getNode(ISD::SHL, SL, TargetType, Lo, ShiftAmt, N->getFlags());
- const SDValue Zero = DAG.getConstant(0, SL, MVT::i32);
+ const SDValue Zero = DAG.getConstant(0, SL, TargetScalarType);
+ SDValue Vec;
- SDValue Vec = DAG.getBuildVector(MVT::v2i32, SL, {Zero, NewShift});
- return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Vec);
+ if (VT.isVector()) {
+ EVT ConcatType = TargetType.getDoubleNumVectorElementsVT(*DAG.getContext());
+ unsigned NElts = TargetType.getVectorNumElements();
+ SmallVector<SDValue, 8> HiOps;
+ SmallVector<SDValue, 16> HiAndLoOps(NElts * 2, Zero);
+
+ DAG.ExtractVectorElements(NewShift, HiOps, 0, NElts);
+ for (unsigned I = 0; I != NElts; ++I)
+ HiAndLoOps[2 * I + 1] = HiOps[I];
+ Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, ConcatType, HiAndLoOps);
+ } else {
+ EVT ConcatType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
+ Vec = DAG.getBuildVector(ConcatType, SL, {Zero, NewShift});
+ }
+ return DAG.getNode(ISD::BITCAST, SL, VT, Vec);
}
SDValue AMDGPUTargetLowering::performSraCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
- if (N->getValueType(0) != MVT::i64)
+ SDValue RHS = N->getOperand(1);
+ ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);
+ EVT VT = N->getValueType(0);
+ SDValue LHS = N->getOperand(0);
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc SL(N);
+
+ if (VT.getScalarType() != MVT::i64)
return SDValue();
- const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (!RHS)
+ // For C >= 32
+ // i64 (sra x, C) -> (build_pair (sra hi_32(x), C - 32), sra hi_32(x), 31))
+
+ // On some subtargets, 64-bit shift is a quarter rate instruction. In the
+ // common case, splitting this into a move and a 32-bit shift is faster and
+ // the same code size.
+ KnownBits Known = DAG.computeKnownBits(RHS);
+
+ EVT ElementType = VT.getScalarType();
+ EVT TargetScalarType = ElementType.getHalfSizedIntegerVT(*DAG.getContext());
+ EVT TargetType = VT.isVector() ? VT.changeVectorElementType(TargetScalarType)
+ : TargetScalarType;
+
+ if (Known.getMinValue().getZExtValue() < TargetScalarType.getSizeInBits())
return SDValue();
- SelectionDAG &DAG = DCI.DAG;
- SDLoc SL(N);
- unsigned RHSVal = RHS->getZExtValue();
+ SDValue ShiftFullAmt =
+ DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
+ SDValue ShiftAmt;
+ if (CRHS) {
+ unsigned RHSVal = CRHS->getZExtValue();
+ ShiftAmt = DAG.getConstant(RHSVal - TargetScalarType.getSizeInBits(), SL,
+ TargetType);
+ } else if (Known.getMinValue().getZExtValue() ==
+ (ElementType.getSizeInBits() - 1)) {
+ ShiftAmt = ShiftFullAmt;
+ } else {
+ SDValue truncShiftAmt = DAG.getNode(ISD::TRUNCATE, SL, TargetType, RHS);
+ const SDValue ShiftMask =
+ DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
+ // This AND instruction will clamp out of bounds shift values.
+ // It will also be removed during later instruction selection.
+ ShiftAmt = DAG.getNode(ISD::AND, SL, TargetType, truncShiftAmt, ShiftMask);
+ }
- // (sra i64:x, 32) -> build_pair x, (sra hi_32(x), 31)
- if (RHSVal == 32) {
- SDValue Hi = getHiHalf64(N->getOperand(0), DAG);
- SDValue NewShift = DAG.getNode(ISD::SRA, SL, MVT::i32, Hi,
- DAG.getConstant(31, SL, MVT::i32));
+ EVT ConcatType;
+ SDValue Hi;
+ SDLoc LHSSL(LHS);
+ // Bitcast LHS into ConcatType so hi-half of source can be extracted into Hi
+ if (VT.isVector()) {
+ unsigned NElts = TargetType.getVectorNumElements();
+ ConcatType = TargetType.getDoubleNumVectorElementsVT(*DAG.getContext());
+ SDValue SplitLHS = DAG.getNode(ISD::BITCAST, LHSSL, ConcatType, LHS);
+ SmallVector<SDValue, 8> HiOps(NElts);
+ SmallVector<SDValue, 16> HiAndLoOps;
- SDValue BuildVec = DAG.getBuildVector(MVT::v2i32, SL, {Hi, NewShift});
- return DAG.getNode(ISD::BITCAST, SL, MVT::i64, BuildVec);
+ DAG.ExtractVectorElements(SplitLHS, HiAndLoOps, 0, NElts * 2);
+ for (unsigned I = 0; I != NElts; ++I) {
+ HiOps[I] = HiAndLoOps[2 * I + 1];
+ }
+ Hi = DAG.getNode(ISD::BUILD_VECTOR, LHSSL, TargetType, HiOps);
+ } else {
+ const SDValue One = DAG.getConstant(1, LHSSL, TargetScalarType);
+ ConcatType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
+ SDValue SplitLHS = DAG.getNode(ISD::BITCAST, LHSSL, ConcatType, LHS);
+ Hi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, LHSSL, TargetType, SplitLHS, One);
}
- // (sra i64:x, 63) -> build_pair (sra hi_32(x), 31), (sra hi_32(x), 31)
- if (RHSVal == 63) {
- SDValue Hi = getHiHalf64(N->getOperand(0), DAG);
- SDValue NewShift = DAG.getNode(ISD::SRA, SL, MVT::i32, Hi,
- DAG.getConstant(31, SL, MVT::i32));
- SDValue BuildVec = DAG.getBuildVector(MVT::v2i32, SL, {NewShift, NewShift});
- return DAG.getNode(ISD::BITCAST, SL, MVT::i64, BuildVec);
+ KnownBits KnownLHS = DAG.computeKnownBits(LHS);
+ SDValue HiShift;
+ if (KnownLHS.isNegative()) {
+ HiShift = DAG.getAllOnesConstant(SL, TargetType);
+ } else {
+ Hi = DAG.getFreeze(Hi);
+ HiShift = DAG.getNode(ISD::SRA, SL, TargetType, Hi, ShiftFullAmt);
}
+ SDValue NewShift =
+ DAG.getNode(ISD::SRA, SL, TargetType, Hi, ShiftAmt, N->getFlags());
- return SDValue();
+ SDValue Vec;
+ if (VT.isVector()) {
+ unsigned NElts = TargetType.getVectorNumElements();
+ SmallVector<SDValue, 8> HiOps;
+ SmallVector<SDValue, 8> LoOps;
+ SmallVector<SDValue, 16> HiAndLoOps(NElts * 2);
+
+ DAG.ExtractVectorElements(HiShift, HiOps, 0, NElts);
+ DAG.ExtractVectorElements(NewShift, LoOps, 0, NElts);
+ for (unsigned I = 0; I != NElts; ++I) {
+ HiAndLoOps[2 * I + 1] = HiOps[I];
+ HiAndLoOps[2 * I] = LoOps[I];
+ }
+ Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, ConcatType, HiAndLoOps);
+ } else {
+ Vec = DAG.getBuildVector(ConcatType, SL, {NewShift, HiShift});
+ }
+ return DAG.getNode(ISD::BITCAST, SL, VT, Vec);
}
SDValue AMDGPUTargetLowering::performSrlCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
- auto *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (!RHS)
- return SDValue();
-
+ SDValue RHS = N->getOperand(1);
+ ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);
EVT VT = N->getValueType(0);
SDValue LHS = N->getOperand(0);
- unsigned ShiftAmt = RHS->getZExtValue();
SelectionDAG &DAG = DCI.DAG;
SDLoc SL(N);
+ unsigned RHSVal;
- // fold (srl (and x, c1 << c2), c2) -> (and (srl(x, c2), c1)
- // this improves the ability to match BFE patterns in isel.
- if (LHS.getOpcode() == ISD::AND) {
- if (auto *Mask = dyn_cast<ConstantSDNode>(LHS.getOperand(1))) {
- unsigned MaskIdx, MaskLen;
- if (Mask->getAPIntValue().isShiftedMask(MaskIdx, MaskLen) &&
- MaskIdx == ShiftAmt) {
- return DAG.getNode(
- ISD::AND, SL, VT,
- DAG.getNode(ISD::SRL, SL, VT, LHS.getOperand(0), N->getOperand(1)),
- DAG.getNode(ISD::SRL, SL, VT, LHS.getOperand(1), N->getOperand(1)));
+ if (CRHS) {
+ RHSVal = CRHS->getZExtValue();
+
+ // fold (srl (and x, c1 << c2), c2) -> (and (srl(x, c2), c1)
+ // this improves the ability to match BFE patterns in isel.
+ if (LHS.getOpcode() == ISD::AND) {
+ if (auto *Mask = dyn_cast<ConstantSDNode>(LHS.getOperand(1))) {
+ unsigned MaskIdx, MaskLen;
+ if (Mask->getAPIntValue().isShiftedMask(MaskIdx, MaskLen) &&
+ MaskIdx == RHSVal) {
+ return DAG.getNode(ISD::AND, SL, VT,
+ DAG.getNode(ISD::SRL, SL, VT, LHS.getOperand(0),
+ N->getOperand(1)),
+ DAG.getNode(ISD::SRL, SL, VT, LHS.getOperand(1),
+ N->getOperand(1)));
+ }
}
}
}
- if (VT != MVT::i64)
+ if (VT.getScalarType() != MVT::i64)
return SDValue();
- if (ShiftAmt < 32)
+ // for C >= 32
+ // i64 (srl x, C) -> (build_pair (srl hi_32(x), C - 32), 0)
+
+ // On some subtargets, 64-bit shift is a quarter rate instruction. In the
+ // common case, splitting this into a move and a 32-bit shift is faster and
+ // the same code size.
+ KnownBits Known = DAG.computeKnownBits(RHS);
+
+ EVT ElementType = VT.getScalarType();
+ EVT TargetScalarType = ElementType.getHalfSizedIntegerVT(*DAG.getContext());
+ EVT TargetType = VT.isVector() ? VT.changeVectorElementType(TargetScalarType)
+ : TargetScalarType;
+
+ if (Known.getMinValue().getZExtValue() < TargetScalarType.getSizeInBits())
return SDValue();
- // srl i64:x, C for C >= 32
- // =>
- // build_pair (srl hi_32(x), C - 32), 0
- SDValue Zero = DAG.getConstant(0, SL, MVT::i32);
+ SDValue ShiftAmt;
+ if (CRHS) {
+ ShiftAmt = DAG.getConstant(RHSVal - TargetScalarType.getSizeInBits(), SL,
+ TargetType);
+ } else {
+ SDValue TruncShiftAmt = DAG.getNode(ISD::TRUNCATE, SL, TargetType, RHS);
+ const SDValue ShiftMask =
+ DAG.getConstant(TargetScalarType.getSizeInBits() - 1, SL, TargetType);
+ // This AND instruction will clamp out of bounds shift values.
+ // It will also be removed during later instruction selection.
+ ShiftAmt = DAG.getNode(ISD::AND, SL, TargetType, TruncShiftAmt, ShiftMask);
+ }
- SDValue Hi = getHiHalf64(LHS, DAG);
+ const SDValue Zero = DAG.getConstant(0, SL, TargetScalarType);
+ EVT ConcatType;
+ SDValue Hi;
+ SDLoc LHSSL(LHS);
+ // Bitcast LHS into ConcatType so hi-half of source can be extracted into Hi
+ if (VT.isVector()) {
+ unsigned NElts = TargetType.getVectorNumElements();
+ ConcatType = TargetType.getDoubleNumVectorElementsVT(*DAG.getContext());
+ SDValue SplitLHS = DAG.getNode(ISD::BITCAST, LHSSL, ConcatType, LHS);
+ SmallVector<SDValue, 8> HiOps(NElts);
+ SmallVector<SDValue, 16> HiAndLoOps;
+
+ DAG.ExtractVectorElements(SplitLHS, HiAndLoOps, /*Start=*/0, NElts * 2);
+ for (unsigned I = 0; I != NElts; ++I)
+ HiOps[I] = HiAndLoOps[2 * I + 1];
+ Hi = DAG.getNode(ISD::BUILD_VECTOR, LHSSL, TargetType, HiOps);
+ } else {
+ const SDValue One = DAG.getConstant(1, LHSSL, TargetScalarType);
+ ConcatType = EVT::getVectorVT(*DAG.getContext(), TargetType, 2);
+ SDValue SplitLHS = DAG.getNode(ISD::BITCAST, LHSSL, ConcatType, LHS);
+ Hi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, LHSSL, TargetType, SplitLHS, One);
+ }
- SDValue NewConst = DAG.getConstant(ShiftAmt - 32, SL, MVT::i32);
- SDValue NewShift = DAG.getNode(ISD::SRL, SL, MVT::i32, Hi, NewConst);
+ SDValue NewShift =
+ DAG.getNode(ISD::SRL, SL, TargetType, Hi, ShiftAmt, N->getFlags());
- SDValue BuildPair = DAG.getBuildVector(MVT::v2i32, SL, {NewShift, Zero});
+ SDValue Vec;
+ if (VT.isVector()) {
+ unsigned NElts = TargetType.getVectorNumElements();
+ SmallVector<SDValue, 8> LoOps;
+ SmallVector<SDValue, 16> HiAndLoOps(NElts * 2, Zero);
- return DAG.getNode(ISD::BITCAST, SL, MVT::i64, BuildPair);
+ DAG.ExtractVectorElements(NewShift, LoOps, 0, NElts);
+ for (unsigned I = 0; I != NElts; ++I)
+ HiAndLoOps[2 * I] = LoOps[I];
+ Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, ConcatType, HiAndLoOps);
+ } else {
+ Vec = DAG.getBuildVector(ConcatType, SL, {NewShift, Zero});
+ }
+ return DAG.getNode(ISD::BITCAST, SL, VT, Vec);
}
SDValue AMDGPUTargetLowering::performTruncateCombine(
@@ -4217,18 +4389,21 @@ SDValue AMDGPUTargetLowering::performTruncateCombine(
// trunc (srl (bitcast (build_vector x, y))), 16 -> trunc (bitcast y)
if (Src.getOpcode() == ISD::SRL && !VT.isVector()) {
if (auto *K = isConstOrConstSplat(Src.getOperand(1))) {
- if (2 * K->getZExtValue() == Src.getValueType().getScalarSizeInBits()) {
- SDValue BV = stripBitcast(Src.getOperand(0));
- if (BV.getOpcode() == ISD::BUILD_VECTOR &&
- BV.getValueType().getVectorNumElements() == 2) {
- SDValue SrcElt = BV.getOperand(1);
- EVT SrcEltVT = SrcElt.getValueType();
- if (SrcEltVT.isFloatingPoint()) {
- SrcElt = DAG.getNode(ISD::BITCAST, SL,
- SrcEltVT.changeTypeToInteger(), SrcElt);
- }
+ SDValue BV = stripBitcast(Src.getOperand(0));
+ if (BV.getOpcode() == ISD::BUILD_VECTOR) {
+ EVT SrcEltVT = BV.getOperand(0).getValueType();
+ unsigned SrcEltSize = SrcEltVT.getSizeInBits();
+ unsigned BitIndex = K->getZExtValue();
+ unsigned PartIndex = BitIndex / SrcEltSize;
- return DAG.getNode(ISD::TRUNCATE, SL, VT, SrcElt);
+ if (PartIndex * SrcEltSize == BitIndex &&
+ PartIndex < BV.getNumOperands()) {
+ if (SrcEltVT.getSizeInBits() == VT.getSizeInBits()) {
+ SDValue SrcElt =
+ DAG.getNode(ISD::BITCAST, SL, SrcEltVT.changeTypeToInteger(),
+ BV.getOperand(PartIndex));
+ return DAG.getNode(ISD::TRUNCATE, SL, VT, SrcElt);
+ }
}
}
}
@@ -4763,10 +4938,14 @@ static unsigned inverseMinMax(unsigned Opc) {
return ISD::FMINIMUM;
case ISD::FMINIMUM:
return ISD::FMAXIMUM;
+ case ISD::FMAXIMUMNUM:
+ return ISD::FMINIMUMNUM;
+ case ISD::FMINIMUMNUM:
+ return ISD::FMAXIMUMNUM;
case AMDGPUISD::FMAX_LEGACY:
return AMDGPUISD::FMIN_LEGACY;
case AMDGPUISD::FMIN_LEGACY:
- return AMDGPUISD::FMAX_LEGACY;
+ return AMDGPUISD::FMAX_LEGACY;
default:
llvm_unreachable("invalid min/max opcode");
}
@@ -4888,6 +5067,8 @@ SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N,
case ISD::FMINNUM_IEEE:
case ISD::FMINIMUM:
case ISD::FMAXIMUM:
+ case ISD::FMINIMUMNUM:
+ case ISD::FMAXIMUMNUM:
case AMDGPUISD::FMAX_LEGACY:
case AMDGPUISD::FMIN_LEGACY: {
// fneg (fmaxnum x, y) -> fminnum (fneg x), (fneg y)
@@ -5161,24 +5342,23 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
break;
}
- case ISD::SHL: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
- break;
-
- return performShlCombine(N, DCI);
- }
+ case ISD::SHL:
+ case ISD::SRA:
case ISD::SRL: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
+ // Range metadata can be invalidated when loads are converted to legal types
+ // (e.g. v2i64 -> v4i32).
+ // Try to convert vector shl/sra/srl before type legalization so that range
+ // metadata can be utilized.
+ if (!(N->getValueType(0).isVector() &&
+ DCI.getDAGCombineLevel() == BeforeLegalizeTypes) &&
+ DCI.getDAGCombineLevel() < AfterLegalizeDAG)
break;
-
+ if (N->getOpcode() == ISD::SHL)
+ return performShlCombine(N, DCI);
+ if (N->getOpcode() == ISD::SRA)
+ return performSraCombine(N, DCI);
return performSrlCombine(N, DCI);
}
- case ISD::SRA: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
- break;
-
- return performSraCombine(N, DCI);
- }
case ISD::TRUNCATE:
return performTruncateCombine(N, DCI);
case ISD::MUL:
@@ -5472,6 +5652,7 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(TC_RETURN)
NODE_NAME_CASE(TC_RETURN_GFX)
NODE_NAME_CASE(TC_RETURN_CHAIN)
+ NODE_NAME_CASE(TC_RETURN_CHAIN_DVGPR)
NODE_NAME_CASE(TRAP)
NODE_NAME_CASE(RET_GLUE)
NODE_NAME_CASE(WAVE_ADDRESS)
@@ -5893,9 +6074,8 @@ unsigned AMDGPUTargetLowering::ComputeNumSignBitsForTargetNode(
}
unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr(
- GISelKnownBits &Analysis, Register R,
- const APInt &DemandedElts, const MachineRegisterInfo &MRI,
- unsigned Depth) const {
+ GISelValueTracking &Analysis, Register R, const APInt &DemandedElts,
+ const MachineRegisterInfo &MRI, unsigned Depth) const {
const MachineInstr *MI = MRI.getVRegDef(R);
if (!MI)
return 1;
@@ -5929,10 +6109,9 @@ unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr(
}
}
-bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,
- const SelectionDAG &DAG,
- bool SNaN,
- unsigned Depth) const {
+bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(
+ SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, bool SNaN,
+ unsigned Depth) const {
unsigned Opcode = Op.getOpcode();
switch (Opcode) {
case AMDGPUISD::FMIN_LEGACY:
@@ -6000,6 +6179,7 @@ bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,
// TODO: Handle more intrinsics
switch (IntrinsicID) {
case Intrinsic::amdgcn_cubeid:
+ case Intrinsic::amdgcn_cvt_off_f32_i4:
return true;
case Intrinsic::amdgcn_frexp_mant: {
@@ -6017,7 +6197,8 @@ bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,
case Intrinsic::amdgcn_rsq:
case Intrinsic::amdgcn_rcp_legacy:
case Intrinsic::amdgcn_rsq_legacy:
- case Intrinsic::amdgcn_rsq_clamp: {
+ case Intrinsic::amdgcn_rsq_clamp:
+ case Intrinsic::amdgcn_tanh: {
if (SNaN)
return true;