123 changes: 75 additions & 48 deletions llvm/include/llvm/IR/IntrinsicsAMDGPU.td

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(uwtable);
KEYWORD(writeonly);
KEYWORD(zeroext);
KEYWORD(immarg);

KEYWORD(type);
KEYWORD(opaque);
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_immarg:
HaveError |=
Error(Lex.getLoc(),
"invalid use of parameter-only attribute on a function");
Expand Down Expand Up @@ -1603,6 +1604,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
case lltok::kw_immarg: B.addAttribute(Attribute::ImmArg); break;

case lltok::kw_alignstack:
case lltok::kw_alwaysinline:
Expand Down Expand Up @@ -1697,6 +1699,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_immarg:
HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
break;

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ enum Kind {
kw_uwtable,
kw_writeonly,
kw_zeroext,
kw_immarg,

kw_type,
kw_opaque,
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,8 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
case Attribute::ShadowCallStack: return 1ULL << 59;
case Attribute::SpeculativeLoadHardening:
return 1ULL << 60;
case Attribute::ImmArg:
return 1ULL << 61;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
Expand Down Expand Up @@ -1424,6 +1426,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::WriteOnly;
case bitc::ATTR_KIND_Z_EXT:
return Attribute::ZExt;
case bitc::ATTR_KIND_IMMARG:
return Attribute::ImmArg;
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_WRITEONLY;
case Attribute::ZExt:
return bitc::ATTR_KIND_Z_EXT;
case Attribute::ImmArg:
return bitc::ATTR_KIND_IMMARG;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "zeroext";
if (hasAttribute(Attribute::Cold))
return "cold";
if (hasAttribute(Attribute::ImmArg))
return "immarg";

// FIXME: These should be output like this:
//
Expand Down
117 changes: 50 additions & 67 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
const Value *V);
void verifyParameterAttrs(AttributeSet Attrs, Type *Ty, const Value *V);
void verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
const Value *V);
const Value *V, bool IsIntrinsic);
void verifyFunctionMetadata(ArrayRef<std::pair<unsigned, MDNode *>> MDs);

void visitConstantExprsRecursively(const Constant *EntryC);
Expand Down Expand Up @@ -1562,6 +1562,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,

verifyAttributeTypes(Attrs, /*IsFunction=*/false, V);

if (Attrs.hasAttribute(Attribute::ImmArg)) {
Assert(Attrs.getNumAttributes() == 1,
"Attribute 'immarg' is incompatible with other attributes", V);
}

// Check for mutually incompatible attributes. Only inreg is compatible with
// sret.
unsigned AttrCount = 0;
Expand Down Expand Up @@ -1649,7 +1654,7 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
// Check parameter attributes against a function type.
// The value V is printed in error messages.
void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
const Value *V) {
const Value *V, bool IsIntrinsic) {
if (Attrs.isEmpty())
return;

Expand Down Expand Up @@ -1686,6 +1691,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
Type *Ty = FT->getParamType(i);
AttributeSet ArgAttrs = Attrs.getParamAttributes(i);

if (!IsIntrinsic) {
Assert(!ArgAttrs.hasAttribute(Attribute::ImmArg),
"immarg attribute only applies to intrinsics",V);
}

verifyParameterAttrs(ArgAttrs, Ty, V);

if (ArgAttrs.hasAttribute(Attribute::Nest)) {
Expand Down Expand Up @@ -1904,16 +1914,8 @@ void Verifier::verifyStatepoint(const CallBase &Call) {
"reordering restrictions required by safepoint semantics",
Call);

const Value *IDV = Call.getArgOperand(0);
Assert(isa<ConstantInt>(IDV), "gc.statepoint ID must be a constant integer",
Call);

const Value *NumPatchBytesV = Call.getArgOperand(1);
Assert(isa<ConstantInt>(NumPatchBytesV),
"gc.statepoint number of patchable bytes must be a constant integer",
Call);
const int64_t NumPatchBytes =
cast<ConstantInt>(NumPatchBytesV)->getSExtValue();
cast<ConstantInt>(Call.getArgOperand(1))->getSExtValue();
assert(isInt<32>(NumPatchBytes) && "NumPatchBytesV is an i32!");
Assert(NumPatchBytes >= 0,
"gc.statepoint number of patchable bytes must be "
Expand All @@ -1926,12 +1928,7 @@ void Verifier::verifyStatepoint(const CallBase &Call) {
"gc.statepoint callee must be of function pointer type", Call, Target);
FunctionType *TargetFuncType = cast<FunctionType>(PT->getElementType());

const Value *NumCallArgsV = Call.getArgOperand(3);
Assert(isa<ConstantInt>(NumCallArgsV),
"gc.statepoint number of arguments to underlying call "
"must be constant integer",
Call);
const int NumCallArgs = cast<ConstantInt>(NumCallArgsV)->getZExtValue();
const int NumCallArgs = cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue();
Assert(NumCallArgs >= 0,
"gc.statepoint number of arguments to underlying call "
"must be positive",
Expand All @@ -1950,10 +1947,8 @@ void Verifier::verifyStatepoint(const CallBase &Call) {
Assert(NumCallArgs == NumParams,
"gc.statepoint mismatch in number of call args", Call);

const Value *FlagsV = Call.getArgOperand(4);
Assert(isa<ConstantInt>(FlagsV),
"gc.statepoint flags must be constant integer", Call);
const uint64_t Flags = cast<ConstantInt>(FlagsV)->getZExtValue();
const uint64_t Flags
= cast<ConstantInt>(Call.getArgOperand(4))->getZExtValue();
Assert((Flags & ~(uint64_t)StatepointFlags::MaskAll) == 0,
"unknown flag used in gc.statepoint flags argument", Call);

Expand Down Expand Up @@ -2130,8 +2125,11 @@ void Verifier::visitFunction(const Function &F) {
Assert(verifyAttributeCount(Attrs, FT->getNumParams()),
"Attribute after last parameter!", &F);

bool isLLVMdotName = F.getName().size() >= 5 &&
F.getName().substr(0, 5) == "llvm.";

// Check function attributes.
verifyFunctionAttrs(FT, Attrs, &F);
verifyFunctionAttrs(FT, Attrs, &F, isLLVMdotName);

// On function declarations/definitions, we do not support the builtin
// attribute. We do not check this in VerifyFunctionAttrs since that is
Expand Down Expand Up @@ -2170,9 +2168,6 @@ void Verifier::visitFunction(const Function &F) {
break;
}

bool isLLVMdotName = F.getName().size() >= 5 &&
F.getName().substr(0, 5) == "llvm.";

// Check that the argument values match the function type for this function...
unsigned i = 0;
for (const Argument &Arg : F.args()) {
Expand Down Expand Up @@ -2800,17 +2795,21 @@ void Verifier::visitCallBase(CallBase &Call) {
Assert(verifyAttributeCount(Attrs, Call.arg_size()),
"Attribute after last parameter!", Call);

bool IsIntrinsic = Call.getCalledFunction() &&
Call.getCalledFunction()->getName().startswith("llvm.");

Function *Callee
= dyn_cast<Function>(Call.getCalledValue()->stripPointerCasts());

if (Attrs.hasAttribute(AttributeList::FunctionIndex, Attribute::Speculatable)) {
// Don't allow speculatable on call sites, unless the underlying function
// declaration is also speculatable.
Function *Callee =
dyn_cast<Function>(Call.getCalledValue()->stripPointerCasts());
Assert(Callee && Callee->isSpeculatable(),
"speculatable attribute may not apply to call sites", Call);
}

// Verify call attributes.
verifyFunctionAttrs(FTy, Attrs, &Call);
verifyFunctionAttrs(FTy, Attrs, &Call, IsIntrinsic);

// Conservatively check the inalloca argument.
// We have a bug if we can find that there is an underlying alloca without
Expand All @@ -2825,7 +2824,7 @@ void Verifier::visitCallBase(CallBase &Call) {
// For each argument of the callsite, if it has the swifterror argument,
// make sure the underlying alloca/parameter it comes from has a swifterror as
// well.
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) {
if (Call.paramHasAttr(i, Attribute::SwiftError)) {
Value *SwiftErrorArg = Call.getArgOperand(i);
if (auto AI = dyn_cast<AllocaInst>(SwiftErrorArg->stripInBoundsOffsets())) {
Expand All @@ -2842,6 +2841,21 @@ void Verifier::visitCallBase(CallBase &Call) {
Call);
}

if (Attrs.hasParamAttribute(i, Attribute::ImmArg)) {
// Don't allow immarg on call sites, unless the underlying declaration
// also has the matching immarg.
Assert(Callee && Callee->hasParamAttribute(i, Attribute::ImmArg),
"immarg may not apply only to call sites",
Call.getArgOperand(i), Call);
}

if (Call.paramHasAttr(i, Attribute::ImmArg)) {
Value *ArgVal = Call.getArgOperand(i);
Assert(isa<ConstantInt>(ArgVal) || isa<ConstantFP>(ArgVal),
"immarg operand has non-immediate parameter", ArgVal, Call);
}
}

if (FTy->isVarArg()) {
// FIXME? is 'nest' even legal here?
bool SawNest = false;
Expand Down Expand Up @@ -2891,8 +2905,7 @@ void Verifier::visitCallBase(CallBase &Call) {
}

// Verify that there's no metadata unless it's a direct call to an intrinsic.
if (!Call.getCalledFunction() ||
!Call.getCalledFunction()->getName().startswith("llvm.")) {
if (!IsIntrinsic) {
for (Type *ParamTy : FTy->params()) {
Assert(!ParamTy->isMetadataTy(),
"Function has metadata parameter but isn't an intrinsic", Call);
Expand Down Expand Up @@ -4181,13 +4194,6 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"an array");
break;
}
case Intrinsic::ctlz: // llvm.ctlz
case Intrinsic::cttz: // llvm.cttz
Assert(isa<ConstantInt>(Call.getArgOperand(1)),
"is_zero_undef argument of bit counting intrinsics must be a "
"constant int",
Call);
break;
case Intrinsic::experimental_constrained_fadd:
case Intrinsic::experimental_constrained_fsub:
case Intrinsic::experimental_constrained_fmul:
Expand Down Expand Up @@ -4243,9 +4249,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"alignment of arg 1 of memory intrinsic must be 0 or a power of 2",
Call);
}
Assert(isa<ConstantInt>(Call.getArgOperand(3)),
"isvolatile argument of memory intrinsics must be a constant int",
Call);

break;
}
case Intrinsic::memcpy_element_unordered_atomic:
Expand All @@ -4254,11 +4258,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
const auto *AMI = cast<AtomicMemIntrinsic>(&Call);

ConstantInt *ElementSizeCI =
dyn_cast<ConstantInt>(AMI->getRawElementSizeInBytes());
Assert(ElementSizeCI,
"element size of the element-wise unordered atomic memory "
"intrinsic must be a constant int",
Call);
cast<ConstantInt>(AMI->getRawElementSizeInBytes());
const APInt &ElementSizeVal = ElementSizeCI->getValue();
Assert(ElementSizeVal.isPowerOf2(),
"element size of the element-wise atomic memory intrinsic "
Expand Down Expand Up @@ -4313,28 +4313,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Call);
break;
case Intrinsic::prefetch:
Assert(isa<ConstantInt>(Call.getArgOperand(1)) &&
isa<ConstantInt>(Call.getArgOperand(2)) &&
cast<ConstantInt>(Call.getArgOperand(1))->getZExtValue() < 2 &&
cast<ConstantInt>(Call.getArgOperand(2))->getZExtValue() < 4,
Assert(cast<ConstantInt>(Call.getArgOperand(1))->getZExtValue() < 2 &&
cast<ConstantInt>(Call.getArgOperand(2))->getZExtValue() < 4,
"invalid arguments to llvm.prefetch", Call);
break;
case Intrinsic::stackprotector:
Assert(isa<AllocaInst>(Call.getArgOperand(1)->stripPointerCasts()),
"llvm.stackprotector parameter #2 must resolve to an alloca.", Call);
break;
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::invariant_start:
Assert(isa<ConstantInt>(Call.getArgOperand(0)),
"size argument of memory use markers must be a constant integer",
Call);
break;
case Intrinsic::invariant_end:
Assert(isa<ConstantInt>(Call.getArgOperand(1)),
"llvm.invariant.end parameter #2 must be a constant integer", Call);
break;

case Intrinsic::localescape: {
BasicBlock *BB = Call.getParent();
Assert(BB == &BB->getParent()->front(),
Expand All @@ -4359,9 +4345,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"llvm.localrecover first "
"argument must be function defined in this module",
Call);
auto *IdxArg = dyn_cast<ConstantInt>(Call.getArgOperand(2));
Assert(IdxArg, "idx argument of llvm.localrecover must be a constant int",
Call);
auto *IdxArg = cast<ConstantInt>(Call.getArgOperand(2));
auto &Entry = FrameEscapeInfo[Fn];
Entry.second = unsigned(
std::max(uint64_t(Entry.second), IdxArg->getLimitedValue(~0U) + 1));
Expand Down Expand Up @@ -4606,8 +4590,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
"second operand of [us]mul_fix must be an int type or vector "
"of ints");

auto *Op3 = dyn_cast<ConstantInt>(Call.getArgOperand(2));
Assert(Op3, "third argument of [us]mul_fix must be a constant integer");
auto *Op3 = cast<ConstantInt>(Call.getArgOperand(2));
Assert(Op3->getType()->getBitWidth() <= 32,
"third argument of [us]mul_fix must fit within 32 bits");

Expand Down
38 changes: 11 additions & 27 deletions llvm/lib/Target/AMDGPU/SIISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,8 +920,8 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.align = 0;
Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore;

const ConstantInt *Vol = dyn_cast<ConstantInt>(CI.getOperand(4));
if (!Vol || !Vol->isZero())
const ConstantInt *Vol = cast<ConstantInt>(CI.getOperand(4));
if (!Vol->isZero())
Info.flags |= MachineMemOperand::MOVolatile;

return true;
Expand All @@ -934,8 +934,8 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.align = 0;
Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore;

const ConstantInt *Vol = dyn_cast<ConstantInt>(CI.getOperand(1));
if (!Vol || !Vol->isZero())
const ConstantInt *Vol = cast<ConstantInt>(CI.getOperand(1));
if (!Vol->isZero())
Info.flags |= MachineMemOperand::MOVolatile;

return true;
Expand Down Expand Up @@ -3741,10 +3741,7 @@ SDValue SITargetLowering::adjustLoadValueType(unsigned Opcode,
static SDValue lowerICMPIntrinsic(const SITargetLowering &TLI,
SDNode *N, SelectionDAG &DAG) {
EVT VT = N->getValueType(0);
const auto *CD = dyn_cast<ConstantSDNode>(N->getOperand(3));
if (!CD)
return DAG.getUNDEF(VT);

const auto *CD = cast<ConstantSDNode>(N->getOperand(3));
int CondCode = CD->getSExtValue();
if (CondCode < ICmpInst::Predicate::FIRST_ICMP_PREDICATE ||
CondCode > ICmpInst::Predicate::LAST_ICMP_PREDICATE)
Expand Down Expand Up @@ -3775,9 +3772,7 @@ static SDValue lowerICMPIntrinsic(const SITargetLowering &TLI,
static SDValue lowerFCMPIntrinsic(const SITargetLowering &TLI,
SDNode *N, SelectionDAG &DAG) {
EVT VT = N->getValueType(0);
const auto *CD = dyn_cast<ConstantSDNode>(N->getOperand(3));
if (!CD)
return DAG.getUNDEF(VT);
const auto *CD = cast<ConstantSDNode>(N->getOperand(3));

int CondCode = CD->getSExtValue();
if (CondCode < FCmpInst::Predicate::FIRST_FCMP_PREDICATE ||
Expand Down Expand Up @@ -4618,9 +4613,7 @@ static SDValue getBuildDwordsVector(SelectionDAG &DAG, SDLoc DL,

static bool parseCachePolicy(SDValue CachePolicy, SelectionDAG &DAG,
SDValue *GLC, SDValue *SLC) {
auto CachePolicyConst = dyn_cast<ConstantSDNode>(CachePolicy.getNode());
if (!CachePolicyConst)
return false;
auto CachePolicyConst = cast<ConstantSDNode>(CachePolicy.getNode());

uint64_t Value = CachePolicyConst->getZExtValue();
SDLoc DL(CachePolicy);
Expand Down Expand Up @@ -4721,9 +4714,7 @@ static SDValue constructRetValue(SelectionDAG &DAG,

static bool parseTexFail(SDValue TexFailCtrl, SelectionDAG &DAG, SDValue *TFE,
SDValue *LWE, bool &IsTexFail) {
auto TexFailCtrlConst = dyn_cast<ConstantSDNode>(TexFailCtrl.getNode());
if (!TexFailCtrlConst)
return false;
auto TexFailCtrlConst = cast<ConstantSDNode>(TexFailCtrl.getNode());

uint64_t Value = TexFailCtrlConst->getZExtValue();
if (Value) {
Expand Down Expand Up @@ -4786,9 +4777,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
}
} else {
unsigned DMaskIdx = BaseOpcode->Store ? 3 : isa<MemSDNode>(Op) ? 2 : 1;
auto DMaskConst = dyn_cast<ConstantSDNode>(Op.getOperand(DMaskIdx));
if (!DMaskConst)
return Op;
auto DMaskConst = cast<ConstantSDNode>(Op.getOperand(DMaskIdx));
DMask = DMaskConst->getZExtValue();
DMaskLanes = BaseOpcode->Gather4 ? 4 : countPopulation(DMask);

Expand Down Expand Up @@ -4902,9 +4891,7 @@ SDValue SITargetLowering::lowerImage(SDValue Op,
CtrlIdx = AddrIdx + NumVAddrs + 1;
} else {
auto UnormConst =
dyn_cast<ConstantSDNode>(Op.getOperand(AddrIdx + NumVAddrs + 2));
if (!UnormConst)
return Op;
cast<ConstantSDNode>(Op.getOperand(AddrIdx + NumVAddrs + 2));

Unorm = UnormConst->getZExtValue() ? True : False;
CtrlIdx = AddrIdx + NumVAddrs + 3;
Expand Down Expand Up @@ -5357,10 +5344,7 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(AMDGPUISD::TRIG_PREOP, DL, VT,
Op.getOperand(1), Op.getOperand(2));
case Intrinsic::amdgcn_div_scale: {
// 3rd parameter required to be a constant.
const ConstantSDNode *Param = dyn_cast<ConstantSDNode>(Op.getOperand(3));
if (!Param)
return DAG.getMergeValues({ DAG.getUNDEF(VT), DAG.getUNDEF(MVT::i1) }, DL);
const ConstantSDNode *Param = cast<ConstantSDNode>(Op.getOperand(3));

// Translate to the operands expected by the machine instruction. The
// first parameter must be the same as the first instruction.
Expand Down
19 changes: 6 additions & 13 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3576,10 +3576,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
}
case Intrinsic::amdgcn_exp:
case Intrinsic::amdgcn_exp_compr: {
ConstantInt *En = dyn_cast<ConstantInt>(II->getArgOperand(1));
if (!En) // Illegal.
break;

ConstantInt *En = cast<ConstantInt>(II->getArgOperand(1));
unsigned EnBits = En->getZExtValue();
if (EnBits == 0xf)
break; // All inputs enabled.
Expand Down Expand Up @@ -3669,10 +3666,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
}
case Intrinsic::amdgcn_icmp:
case Intrinsic::amdgcn_fcmp: {
const ConstantInt *CC = dyn_cast<ConstantInt>(II->getArgOperand(2));
if (!CC)
break;

const ConstantInt *CC = cast<ConstantInt>(II->getArgOperand(2));
// Guard against invalid arguments.
int64_t CCVal = CC->getZExtValue();
bool IsInteger = II->getIntrinsicID() == Intrinsic::amdgcn_icmp;
Expand Down Expand Up @@ -3822,11 +3816,10 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
case Intrinsic::amdgcn_update_dpp: {
Value *Old = II->getArgOperand(0);

auto BC = dyn_cast<ConstantInt>(II->getArgOperand(5));
auto RM = dyn_cast<ConstantInt>(II->getArgOperand(3));
auto BM = dyn_cast<ConstantInt>(II->getArgOperand(4));
if (!BC || !RM || !BM ||
BC->isZeroValue() ||
auto BC = cast<ConstantInt>(II->getArgOperand(5));
auto RM = cast<ConstantInt>(II->getArgOperand(3));
auto BM = cast<ConstantInt>(II->getArgOperand(4));
if (BC->isZeroValue() ||
RM->getZExtValue() != 0xF ||
BM->getZExtValue() != 0xF ||
isa<UndefValue>(Old))
Expand Down
14 changes: 4 additions & 10 deletions llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,10 +982,7 @@ Value *InstCombiner::simplifyAMDGCNMemoryIntrinsicDemanded(IntrinsicInst *II,
// below.
DemandedElts = (1 << DemandedElts.getActiveBits()) - 1;
} else {
ConstantInt *DMask = dyn_cast<ConstantInt>(II->getArgOperand(DMaskIdx));
if (!DMask)
return nullptr; // non-constant dmask is not supported by codegen

ConstantInt *DMask = cast<ConstantInt>(II->getArgOperand(DMaskIdx));
unsigned DMaskVal = DMask->getZExtValue() & 0xf;

// Mask off values that are undefined because the dmask doesn't cover them
Expand Down Expand Up @@ -1639,12 +1636,9 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts,
return simplifyAMDGCNMemoryIntrinsicDemanded(II, DemandedElts);
default: {
if (getAMDGPUImageDMaskIntrinsic(II->getIntrinsicID())) {
LLVM_DEBUG(
Value *TFC = II->getArgOperand(II->getNumOperands() - 2);
assert(!isa<ConstantInt>(TFC) ||
dyn_cast<ConstantInt>(TFC)->getZExtValue() == 0);
);

assert(cast<ConstantInt>(
II->getArgOperand(
II->getNumOperands() - 2))->getZExtValue() == 0);
return simplifyAMDGCNMemoryIntrinsicDemanded(II, DemandedElts, 0);
}

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::SwiftSelf:
case Attribute::WriteOnly:
case Attribute::ZExt:
case Attribute::ImmArg:
case Attribute::EndAttrKinds:
continue;
// Those attributes should be safe to propagate to the extracted function.
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Assembler/auto_upgrade_intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,5 @@ define void @tests.lifetime.start.end() {
; CHECK: declare i32 @llvm.objectsize.i32.p0i8


; CHECK: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
; CHECK: declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
; CHECK: declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
; CHECK: declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
15 changes: 15 additions & 0 deletions llvm/test/Assembler/autoupgrade-invalid-mem-intrinsics.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

; Check that remangling code doesn't fail on an intrinsic with wrong signature

; CHECK: Attribute after last parameter!
; CHECK-NEXT: void (i8*, i8, i64)* @llvm.memset.i64
declare void @llvm.memset.i64(i8* nocapture, i8, i64) nounwind

; CHECK: Attribute after last parameter!
; CHECK-NEXT: void (i8*, i8, i64)* @llvm.memcpy.i64
declare void @llvm.memcpy.i64(i8* nocapture, i8, i64) nounwind

; CHECK: Attribute after last parameter!
; CHECK-NEXT: void (i8*, i8, i64)* @llvm.memmove.i64
declare void @llvm.memmove.i64(i8* nocapture, i8, i64) nounwind
39 changes: 39 additions & 0 deletions llvm/test/Assembler/immarg-param-attribute.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s

; CHECK: declare void @llvm.test.immarg.intrinsic.i32(i32 immarg)
declare void @llvm.test.immarg.intrinsic.i32(i32 immarg)

; CHECK: declare void @llvm.test.immarg.intrinsic.f32(float immarg)
declare void @llvm.test.immarg.intrinsic.f32(float immarg)

; CHECK-LABEL: @call_llvm.test.immarg.intrinsic.i32(
define void @call_llvm.test.immarg.intrinsic.i32() {
; CHECK: call void @llvm.test.immarg.intrinsic.i32(i32 0)
call void @llvm.test.immarg.intrinsic.i32(i32 0)

; CHECK: call void @llvm.test.immarg.intrinsic.i32(i32 0)
call void @llvm.test.immarg.intrinsic.i32(i32 0)

; CHECK call void @llvm.test.immarg.intrinsic.i32(i32 1)
call void @llvm.test.immarg.intrinsic.i32(i32 1)

; CHECK: call void @llvm.test.immarg.intrinsic.i32(i32 5)
call void @llvm.test.immarg.intrinsic.i32(i32 add (i32 2, i32 3))

; CHECK: call void @llvm.test.immarg.intrinsic.i32(i32 0)
call void @llvm.test.immarg.intrinsic.i32(i32 ptrtoint (i32* null to i32))
ret void
}

; CHECK-LABEL: @call_llvm.test.immarg.intrinsic.f32(
define void @call_llvm.test.immarg.intrinsic.f32() {
; CHECK: call void @llvm.test.immarg.intrinsic.f32(float 1.000000e+00)
call void @llvm.test.immarg.intrinsic.f32(float 1.0)
ret void
}

define void @on_callsite_and_declaration() {
; CHECK: call void @llvm.test.immarg.intrinsic.i32(i32 immarg 0)
call void @llvm.test.immarg.intrinsic.i32(i32 immarg 0)
ret void
}
34 changes: 34 additions & 0 deletions llvm/test/Assembler/invalid-immarg.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.byval(i32* byval immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.inalloca(i32* inalloca immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.inreg(i32 inreg immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.nest(i32* nest immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.sret(i32* sret immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.zeroext(i32 zeroext immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.signext(i32 signext immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.returned(i32 returned immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.noalias(i32* noalias immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.readnone(i32* readnone immarg)

; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.readonly(i32* readonly immarg)
4 changes: 4 additions & 0 deletions llvm/test/Assembler/invalid-immarg2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

; CHECK: error: invalid use of parameter-only attribute on a function
declare void @llvm.immarg.func() immarg
4 changes: 4 additions & 0 deletions llvm/test/Assembler/invalid-immarg3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

; CHECK: error: invalid use of parameter-only attribute
declare immarg i32 @llvm.immarg.retattr(i32)
4 changes: 4 additions & 0 deletions llvm/test/Bitcode/compatibility.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,10 @@ define i8** @constexpr() {
ret i8** getelementptr inbounds ({ [4 x i8*], [4 x i8*] }, { [4 x i8*], [4 x i8*] }* null, i32 0, inrange i32 1, i32 2)
}

; immarg attribute
declare void @llvm.test.immarg.intrinsic(i32 immarg)
; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)

; CHECK: attributes #0 = { alignstack=4 }
; CHECK: attributes #1 = { alignstack=8 }
; CHECK: attributes #2 = { alwaysinline }
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Bitcode/objectsize-upgrade-7.0.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ define void @callit(i8* %ptr) {
}

declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1)
; CHECK: declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1)
; CHECK: declare i64 @llvm.objectsize.i64.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg)
6 changes: 3 additions & 3 deletions llvm/test/Bitcode/upgrade-memory-intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ define void @test2(i8* %p1, i8* %p2, i8* %p3) {
ret void
}

; CHECK: declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
; CHECK: declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)
; CHECK: declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1)
; CHECK: declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg)
; CHECK: declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg)
; CHECK: declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1 immarg)
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly , i8* nocapture readonly, i64, i32, i1)
declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AMDGPU/bitcast-vector-extract.ll
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ define amdgpu_kernel void @store_bitcast_constant_v8i32_to_v16i16(<8 x float> ad

; GCN-LABEL: {{^}}store_value_lowered_to_undef_bitcast_source:
; GCN-NOT: store_dword
define amdgpu_kernel void @store_value_lowered_to_undef_bitcast_source(<2 x i32> addrspace(1)* %out, i64 %a, i64 %b, i32 %c) #0 {
%undef = call i64 @llvm.amdgcn.icmp.i64(i64 %a, i64 %b, i32 %c) #1
define amdgpu_kernel void @store_value_lowered_to_undef_bitcast_source(<2 x i32> addrspace(1)* %out, i64 %a, i64 %b) #0 {
%undef = call i64 @llvm.amdgcn.icmp.i64(i64 %a, i64 %b, i32 999) #1
%bc = bitcast i64 %undef to <2 x i32>
store volatile <2 x i32> %bc, <2 x i32> addrspace(1)* %out
ret void
}

; GCN-LABEL: {{^}}store_value_lowered_to_undef_bitcast_source_extractelt:
; GCN-NOT: store_dword
define amdgpu_kernel void @store_value_lowered_to_undef_bitcast_source_extractelt(i32 addrspace(1)* %out, i64 %a, i64 %b, i32 %c) #0 {
%undef = call i64 @llvm.amdgcn.icmp.i64(i64 %a, i64 %b, i32 %c) #1
define amdgpu_kernel void @store_value_lowered_to_undef_bitcast_source_extractelt(i32 addrspace(1)* %out, i64 %a, i64 %b) #0 {
%undef = call i64 @llvm.amdgcn.icmp.i64(i64 %a, i64 %b, i32 9999) #1
%bc = bitcast i64 %undef to <2 x i32>
%elt1 = extractelement <2 x i32> %bc, i32 1
store volatile i32 %elt1, i32 addrspace(1)* %out
Expand Down
28 changes: 0 additions & 28 deletions llvm/test/CodeGen/AMDGPU/llvm.amdgcn.atomic.dec.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,6 @@ declare i64 @llvm.amdgcn.atomic.dec.i64.p0i64(i64* nocapture, i64, i32, i32, i1)

declare i32 @llvm.amdgcn.workitem.id.x() #1

; Make sure no crash on invalid non-constant
; GCN-LABEL: {{^}}invalid_variable_order_lds_atomic_dec_ret_i32:
; CIVI-DAG: s_mov_b32 m0
; GFX9-NOT: m0
define amdgpu_kernel void @invalid_variable_order_lds_atomic_dec_ret_i32(i32 addrspace(1)* %out, i32 addrspace(3)* %ptr, i32 %order.var) #0 {
%result = call i32 @llvm.amdgcn.atomic.dec.i32.p3i32(i32 addrspace(3)* %ptr, i32 42, i32 %order.var, i32 0, i1 false)
store i32 %result, i32 addrspace(1)* %out
ret void
}

; Make sure no crash on invalid non-constant
; GCN-LABEL: {{^}}invalid_variable_scope_lds_atomic_dec_ret_i32:
; CIVI-DAG: s_mov_b32 m0
; GFX9-NOT: m0
define amdgpu_kernel void @invalid_variable_scope_lds_atomic_dec_ret_i32(i32 addrspace(1)* %out, i32 addrspace(3)* %ptr, i32 %scope.var) #0 {
%result = call i32 @llvm.amdgcn.atomic.dec.i32.p3i32(i32 addrspace(3)* %ptr, i32 42, i32 0, i32 %scope.var, i1 false)
store i32 %result, i32 addrspace(1)* %out
ret void
}

; Make sure no crash on invalid non-constant
; GCN-LABEL: {{^}}invalid_variable_volatile_lds_atomic_dec_ret_i32:
define amdgpu_kernel void @invalid_variable_volatile_lds_atomic_dec_ret_i32(i32 addrspace(1)* %out, i32 addrspace(3)* %ptr, i1 %volatile.var) #0 {
%result = call i32 @llvm.amdgcn.atomic.dec.i32.p3i32(i32 addrspace(3)* %ptr, i32 42, i32 0, i32 0, i1 %volatile.var)
store i32 %result, i32 addrspace(1)* %out
ret void
}

; GCN-LABEL: {{^}}lds_atomic_dec_ret_i32:
; CIVI-DAG: s_mov_b32 m0
; GFX9-NOT: m0
Expand Down
35 changes: 0 additions & 35 deletions llvm/test/CodeGen/AMDGPU/llvm.amdgcn.div.scale.ll
Original file line number Diff line number Diff line change
Expand Up @@ -395,41 +395,6 @@ define amdgpu_kernel void @test_div_scale_f32_undef_undef_val(float addrspace(1)
ret void
}

; Undefined selector gets deleted
; SI-LABEL: {{^}}test_div_scale_f32_val_undef_undef:
; SI-NOT: v_div_scale
define amdgpu_kernel void @test_div_scale_f32_val_undef_undef(float addrspace(1)* %out) #0 {
%result = call { float, i1 } @llvm.amdgcn.div.scale.f32(float 8.0, float undef, i1 undef)
%result0 = extractvalue { float, i1 } %result, 0
store float %result0, float addrspace(1)* %out, align 4
ret void
}

; SI-LABEL: {{^}}test_div_scale_f32_undef_undef_undef:
; SI-NOT: v_div_scale
define amdgpu_kernel void @test_div_scale_f32_undef_undef_undef(float addrspace(1)* %out) #0 {
%result = call { float, i1 } @llvm.amdgcn.div.scale.f32(float undef, float undef, i1 undef)
%result0 = extractvalue { float, i1 } %result, 0
store float %result0, float addrspace(1)* %out, align 4
ret void
}

; SI-LABEL: {{^}}test_div_scale_f32_val_val_undef:
; SI-NOT: v_div_scale
define amdgpu_kernel void @test_div_scale_f32_val_val_undef(float addrspace(1)* %out, float addrspace(1)* %in) #0 {
%tid = call i32 @llvm.amdgcn.workitem.id.x() nounwind readnone
%gep.0 = getelementptr float, float addrspace(1)* %in, i32 %tid
%gep.1 = getelementptr float, float addrspace(1)* %gep.0, i32 1

%a = load volatile float, float addrspace(1)* %gep.0, align 4
%b = load volatile float, float addrspace(1)* %gep.1, align 4

%result = call { float, i1 } @llvm.amdgcn.div.scale.f32(float %a, float %b, i1 undef)
%result0 = extractvalue { float, i1 } %result, 0
store float %result0, float addrspace(1)* %out, align 4
ret void
}

; SI-LABEL: {{^}}test_div_scale_f64_val_undef_val:
; SI-DAG: s_mov_b32 s[[K_LO:[0-9]+]], 0{{$}}
; SI-DAG: s_mov_b32 s[[K_HI:[0-9]+]], 0x40200000
Expand Down
8 changes: 0 additions & 8 deletions llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fcmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ declare float @llvm.fabs.f32(float) #0
declare i64 @llvm.amdgcn.fcmp.f16(half, half, i32) #0
declare half @llvm.fabs.f16(half) #0

; GCN-LABEL: {{^}}v_fcmp_f32_dynamic_cc:
; GCN: s_endpgm
define amdgpu_kernel void @v_fcmp_f32_dynamic_cc(i64 addrspace(1)* %out, float %src0, float %src1, i32 %cc) {
%result = call i64 @llvm.amdgcn.fcmp.f32(float %src0, float %src1, i32 %cc)
store i64 %result, i64 addrspace(1)* %out
ret void
}

; GCN-LABEL: {{^}}v_fcmp_f32_oeq_with_fabs:
; GCN: v_cmp_eq_f32_e64 {{s\[[0-9]+:[0-9]+\]}}, {{s[0-9]+}}, |{{v[0-9]+}}|
define amdgpu_kernel void @v_fcmp_f32_oeq_with_fabs(i64 addrspace(1)* %out, float %src, float %a) {
Expand Down
18 changes: 0 additions & 18 deletions llvm/test/CodeGen/AMDGPU/llvm.amdgcn.icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ declare i64 @llvm.amdgcn.icmp.i64(i64, i64, i32) #0
declare i64 @llvm.amdgcn.icmp.i16(i16, i16, i32) #0
declare i64 @llvm.amdgcn.icmp.i1(i1, i1, i32) #0

; No crash on invalid input
; GCN-LABEL: {{^}}v_icmp_i32_dynamic_cc:
; GCN: s_endpgm
define amdgpu_kernel void @v_icmp_i32_dynamic_cc(i64 addrspace(1)* %out, i32 %src, i32 %cc) {
%result = call i64 @llvm.amdgcn.icmp.i32(i32 %src, i32 100, i32 %cc)
store i64 %result, i64 addrspace(1)* %out
ret void
}

; GCN-LABEL: {{^}}v_icmp_i32_eq:
; GCN: v_cmp_eq_u32_e64
define amdgpu_kernel void @v_icmp_i32_eq(i64 addrspace(1)* %out, i32 %src) {
Expand Down Expand Up @@ -181,15 +172,6 @@ define amdgpu_kernel void @v_icmp_i64_sle(i64 addrspace(1)* %out, i64 %src) {
ret void
}

; GCN-LABEL: {{^}}v_icmp_i16_dynamic_cc:
; GCN: s_endpgm
define amdgpu_kernel void @v_icmp_i16_dynamic_cc(i64 addrspace(1)* %out, i16 %src, i32 %cc) {
%result = call i64 @llvm.amdgcn.icmp.i16(i16 %src, i16 100, i32 %cc)
store i64 %result, i64 addrspace(1)* %out
ret void
}

; GCN-LABEL: {{^}}v_icmp_i16_eq:
; VI: v_cmp_eq_u16_e64

; SI-DAG: v_mov_b32_e32 [[K:v[0-9]+]], 0x64
Expand Down
3 changes: 0 additions & 3 deletions llvm/test/CodeGen/AMDGPU/llvm.amdgcn.raw.tbuffer.store.ll
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ declare void @llvm.amdgcn.raw.tbuffer.store.i32(i32, <4 x i32>, i32, i32, i32, i
declare void @llvm.amdgcn.raw.tbuffer.store.v2i32(<2 x i32>, <4 x i32>, i32, i32, i32, i32) #0
declare void @llvm.amdgcn.raw.tbuffer.store.v4i32(<4 x i32>, <4 x i32>, i32, i32, i32, i32) #0
declare void @llvm.amdgcn.raw.tbuffer.store.v4f32(<4 x float>, <4 x i32>, i32, i32, i32, i32) #0
declare <4 x float> @llvm.amdgcn.buffer.load.format.v4f32(<4 x i32>, i32, i1, i1) #1

attributes #0 = { nounwind }
attributes #1 = { nounwind readonly }


3 changes: 0 additions & 3 deletions llvm/test/DebugInfo/MIR/X86/kill-after-spill.mir
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@

declare i8* @memset(i8*, i32, i64) local_unnamed_addr

; Function Attrs: nounwind readnone speculatable
declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1) #1

; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #1

Expand Down
3 changes: 0 additions & 3 deletions llvm/test/LTO/X86/remangle_intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,3 @@ define void @foo(%struct.rtx_def* %a, i8 %b, i32 %c) {
}

declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i1)

; Check that remangling code doesn't fail on an intrinsic with wrong signature
declare void @llvm.memset.i64(i8* nocapture, i8, i64) nounwind
9 changes: 0 additions & 9 deletions llvm/test/Transforms/InferAddressSpaces/AMDGPU/intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,6 @@ define i64 @volatile_atomicdec_group_to_flat_i64(i64 addrspace(3)* %group.ptr, i
ret i64 %ret
}

; CHECK-LABEL: @invalid_variable_volatile_atomicinc_group_to_flat_i64(
; CHECK-NEXT: %1 = addrspacecast i64 addrspace(3)* %group.ptr to i64*
; CHECK-NEXT: %ret = call i64 @llvm.amdgcn.atomic.inc.i64.p0i64(i64* %1, i64 %y, i32 0, i32 0, i1 %volatile.var)
define i64 @invalid_variable_volatile_atomicinc_group_to_flat_i64(i64 addrspace(3)* %group.ptr, i64 %y, i1 %volatile.var) #0 {
%cast = addrspacecast i64 addrspace(3)* %group.ptr to i64*
%ret = call i64 @llvm.amdgcn.atomic.inc.i64.p0i64(i64* %cast, i64 %y, i32 0, i32 0, i1 %volatile.var)
ret i64 %ret
}

declare i32 @llvm.objectsize.i32.p0i8(i8*, i1, i1, i1) #1
declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) #1
declare i32 @llvm.amdgcn.atomic.inc.i32.p0i32(i32* nocapture, i32, i32, i32, i1) #2
Expand Down
593 changes: 288 additions & 305 deletions llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-demanded-vector-elts.ll

Large diffs are not rendered by default.

47 changes: 6 additions & 41 deletions llvm/test/Transforms/InstCombine/AMDGPU/amdgcn-intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1078,17 +1078,7 @@ define i64 @sbfe_offset_32_width_32_i64(i64 %src) {
; llvm.amdgcn.exp
; --------------------------------------------------------------------

declare void @llvm.amdgcn.exp.f32(i32, i32, float, float, float, float, i1, i1) nounwind inaccessiblememonly

; Make sure no crashing on invalid variable params
; CHECK-LABEL: @exp_invalid_inputs(
; CHECK: call void @llvm.amdgcn.exp.f32(i32 0, i32 %en, float 1.000000e+00, float 2.000000e+00, float 5.000000e-01, float 4.000000e+00, i1 true, i1 false)
; CHECK: call void @llvm.amdgcn.exp.f32(i32 %tgt, i32 15, float 1.000000e+00, float 2.000000e+00, float 5.000000e-01, float 4.000000e+00, i1 true, i1 false)
define void @exp_invalid_inputs(i32 %tgt, i32 %en) {
call void @llvm.amdgcn.exp.f32(i32 0, i32 %en, float 1.0, float 2.0, float 0.5, float 4.0, i1 true, i1 false)
call void @llvm.amdgcn.exp.f32(i32 %tgt, i32 15, float 1.0, float 2.0, float 0.5, float 4.0, i1 true, i1 false)
ret void
}
declare void @llvm.amdgcn.exp.f32(i32 immarg, i32 immarg, float, float, float, float, i1 immarg, i1 immarg) nounwind inaccessiblememonly

; CHECK-LABEL: @exp_disabled_inputs_to_undef(
; CHECK: call void @llvm.amdgcn.exp.f32(i32 0, i32 1, float 1.000000e+00, float undef, float undef, float undef, i1 true, i1 false)
Expand Down Expand Up @@ -1136,16 +1126,7 @@ define void @exp_disabled_inputs_to_undef(float %x, float %y, float %z, float %w
; llvm.amdgcn.exp.compr
; --------------------------------------------------------------------

declare void @llvm.amdgcn.exp.compr.v2f16(i32, i32, <2 x half>, <2 x half>, i1, i1) nounwind inaccessiblememonly

; CHECK-LABEL: @exp_compr_invalid_inputs(
; CHECK: call void @llvm.amdgcn.exp.compr.v2f16(i32 0, i32 %en, <2 x half> <half 0xH3C00, half 0xH4000>, <2 x half> <half 0xH3800, half 0xH4400>, i1 true, i1 false)
; CHECK: call void @llvm.amdgcn.exp.compr.v2f16(i32 %tgt, i32 5, <2 x half> <half 0xH3C00, half 0xH4000>, <2 x half> <half 0xH3800, half 0xH4400>, i1 true, i1 false)
define void @exp_compr_invalid_inputs(i32 %tgt, i32 %en) {
call void @llvm.amdgcn.exp.compr.v2f16(i32 0, i32 %en, <2 x half> <half 1.0, half 2.0>, <2 x half> <half 0.5, half 4.0>, i1 true, i1 false)
call void @llvm.amdgcn.exp.compr.v2f16(i32 %tgt, i32 5, <2 x half> <half 1.0, half 2.0>, <2 x half> <half 0.5, half 4.0>, i1 true, i1 false)
ret void
}
declare void @llvm.amdgcn.exp.compr.v2f16(i32 immarg, i32 immarg, <2 x half>, <2 x half>, i1 immarg, i1 immarg) nounwind inaccessiblememonly

; CHECK-LABEL: @exp_compr_disabled_inputs_to_undef(
; CHECK: call void @llvm.amdgcn.exp.compr.v2f16(i32 0, i32 0, <2 x half> undef, <2 x half> undef, i1 true, i1 false)
Expand Down Expand Up @@ -1404,17 +1385,9 @@ define float @fmed3_0_1_undef_f32() {
; llvm.amdgcn.icmp
; --------------------------------------------------------------------

declare i64 @llvm.amdgcn.icmp.i32(i32, i32, i32) nounwind readnone convergent
declare i64 @llvm.amdgcn.icmp.i64(i64, i64, i32) nounwind readnone convergent
declare i64 @llvm.amdgcn.icmp.i1(i1, i1, i32) nounwind readnone convergent

; Make sure there's no crash for invalid input
; CHECK-LABEL: @invalid_nonconstant_icmp_code(
; CHECK: call i64 @llvm.amdgcn.icmp.i32(i32 %a, i32 %b, i32 %c)
define i64 @invalid_nonconstant_icmp_code(i32 %a, i32 %b, i32 %c) {
%result = call i64 @llvm.amdgcn.icmp.i32(i32 %a, i32 %b, i32 %c)
ret i64 %result
}
declare i64 @llvm.amdgcn.icmp.i32(i32, i32, i32 immarg) nounwind readnone convergent
declare i64 @llvm.amdgcn.icmp.i64(i64, i64, i32 immarg) nounwind readnone convergent
declare i64 @llvm.amdgcn.icmp.i1(i1, i1, i32 immarg) nounwind readnone convergent

; CHECK-LABEL: @invalid_icmp_code(
; CHECK: %under = call i64 @llvm.amdgcn.icmp.i32(i32 %a, i32 %b, i32 31)
Expand Down Expand Up @@ -2012,15 +1985,7 @@ define i64 @fold_icmp_i1_ne_0_icmp_ult_i16(i16 %a, i16 %b) {
; llvm.amdgcn.fcmp
; --------------------------------------------------------------------

declare i64 @llvm.amdgcn.fcmp.f32(float, float, i32) nounwind readnone convergent

; Make sure there's no crash for invalid input
; CHECK-LABEL: @invalid_nonconstant_fcmp_code(
; CHECK: call i64 @llvm.amdgcn.fcmp.f32(float %a, float %b, i32 %c)
define i64 @invalid_nonconstant_fcmp_code(float %a, float %b, i32 %c) {
%result = call i64 @llvm.amdgcn.fcmp.f32(float %a, float %b, i32 %c)
ret i64 %result
}
declare i64 @llvm.amdgcn.fcmp.f32(float, float, i32 immarg) nounwind readnone convergent

; CHECK-LABEL: @invalid_fcmp_code(
; CHECK: %under = call i64 @llvm.amdgcn.fcmp.f32(float %a, float %b, i32 -1)
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/LowerExpectIntrinsic/PR33346.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ bb:
store i64 %arg, i64* %tmp, align 8
%tmp1 = load i64, i64* %tmp, align 8
%tmp2 = load i64, i64* %tmp, align 8
%tmp3 = call i64 @llvm.expect.i64(i64 %tmp1, i64 %tmp2)
%tmp3 = call i64 @llvm.expect.i64(i64 %tmp1, i64 123)
ret i64 %tmp3
}

; Function Attrs: nounwind readnone
declare i64 @llvm.expect.i64(i64, i64)
declare i64 @llvm.expect.i64(i64, i64 immarg)


!llvm.module.flags = !{!0}
Expand Down
552 changes: 552 additions & 0 deletions llvm/test/Verifier/AMDGPU/intrinsic-immarg.ll

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions llvm/test/Verifier/AMDGPU/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if not 'AMDGPU' in config.root.targets:
config.unsupported = True
6 changes: 4 additions & 2 deletions llvm/test/Verifier/cttz-undef-arg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ declare i32 @llvm.cttz.i32(i32, i1)

define void @f(i32 %x, i1 %is_not_zero) {
entry:
; CHECK: is_zero_undef argument of bit counting intrinsics must be a constant int
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %is_not_zero
; CHECK-NEXT: @llvm.ctlz.i32
call i32 @llvm.ctlz.i32(i32 %x, i1 %is_not_zero)

; CHECK: is_zero_undef argument of bit counting intrinsics must be a constant int
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %is_not_zero
; CHECK-NEXT: @llvm.cttz.i32
call i32 @llvm.cttz.i32(i32 %x, i1 %is_not_zero)
ret void
Expand Down
17 changes: 14 additions & 3 deletions llvm/test/Verifier/element-wise-atomic-memory-intrinsics.ll
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
; RUN: not opt -verify < %s 2>&1 | FileCheck %s

define void @test_memcpy(i8* %P, i8* %Q, i32 %A, i32 %E) {
; CHECK: element size of the element-wise unordered atomic memory intrinsic must be a constant int
; CHECK: immarg operand has non-immediate parameter
; CHECK: i32 %E
; CHECK-NEXT: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 %E)
call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 %E)

; CHECK: element size of the element-wise atomic memory intrinsic must be a power of 2
call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 3)

Expand All @@ -21,11 +24,15 @@ define void @test_memcpy(i8* %P, i8* %Q, i32 %A, i32 %E) {

ret void
}

declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind

define void @test_memmove(i8* %P, i8* %Q, i32 %A, i32 %E) {
; CHECK: element size of the element-wise unordered atomic memory intrinsic must be a constant int
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %E
; CHECK-NEXT: call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 %E)
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 %E)

; CHECK: element size of the element-wise atomic memory intrinsic must be a power of 2
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 3)

Expand All @@ -44,11 +51,15 @@ define void @test_memmove(i8* %P, i8* %Q, i32 %A, i32 %E) {

ret void
}

declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind

define void @test_memset(i8* %P, i8 %V, i32 %A, i32 %E) {
; CHECK: element size of the element-wise unordered atomic memory intrinsic must be a constant int
; CHECK: immarg operand has non-immediate parameter
; CHECK: i32 %E
; CHECK: call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %P, i8 %V, i32 1, i32 %E)
call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %P, i8 %V, i32 1, i32 %E)

; CHECK: element size of the element-wise atomic memory intrinsic must be a power of 2
call void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* align 4 %P, i8 %V, i32 1, i32 3)

Expand Down
5 changes: 4 additions & 1 deletion llvm/test/Verifier/frameescape.ll
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ define internal void @k(i32 %n) {
call i8* @llvm.localrecover(i8* bitcast(void()* @f to i8*), i8* null, i32 %n)
ret void
}
; CHECK: idx argument of llvm.localrecover must be a constant int

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %n
; CHECK-NEXT: %1 = call i8* @llvm.localrecover(i8* bitcast (void ()* @f to i8*), i8* null, i32 %n)

define internal void @l(i8* %b) {
%a = alloca i8
Expand Down
107 changes: 107 additions & 0 deletions llvm/test/Verifier/immarg-param-attribute-invalid.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

declare void @llvm.test.immarg.intrinsic.i32(i32 immarg)
declare void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> immarg)
declare void @llvm.test.immarg.intrinsic.f32(float immarg)
declare void @llvm.test.immarg.intrinsic.v2f32(<2 x float> immarg)
declare void @llvm.test.immarg.intrinsic.2ai32([2 x i32] immarg)

@gv = global i32 undef, align 4

define void @call_llvm.test.immarg.intrinsic.i32(i32 %arg) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 undef
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.i32(i32 undef)
call void @llvm.test.immarg.intrinsic.i32(i32 undef)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.i32(i32 %arg)
call void @llvm.test.immarg.intrinsic.i32(i32 %arg)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 ptrtoint (i32* @gv to i32)
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.i32(i32 ptrtoint (i32* @gv to i32))
call void @llvm.test.immarg.intrinsic.i32(i32 ptrtoint (i32* @gv to i32))
ret void
}

define void @call_llvm.test.immarg.intrinsic.f32() {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: float undef
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.f32(float undef)
call void @llvm.test.immarg.intrinsic.f32(float undef)
ret void
}

define void @call_llvm.test.immarg.intrinsic.v2i32() {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: <2 x i32> zeroinitializer
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> zeroinitializer)
call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> zeroinitializer)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: <2 x i32> <i32 1, i32 2>
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> <i32 1, i32 2>)
call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> <i32 1, i32 2>)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: <2 x i32> undef
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> undef)
call void @llvm.test.immarg.intrinsic.v2i32(<2 x i32> undef)
ret void
}

define void @call_llvm.test.immarg.intrinsic.v2f32() {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: <2 x float> zeroinitializer
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.v2f32(<2 x float> zeroinitializer)
call void @llvm.test.immarg.intrinsic.v2f32(<2 x float> zeroinitializer)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: <2 x float> <float 1.000000e+00, float 2.000000e+00>
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.v2f32(<2 x float> <float 1.000000e+00, float 2.000000e+00>)
call void @llvm.test.immarg.intrinsic.v2f32(<2 x float> <float 1.0, float 2.0>)
ret void
}

define void @call_llvm.test.immarg.intrinsic.2ai32() {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: [2 x i32] zeroinitializer
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.2ai32([2 x i32] zeroinitializer)
call void @llvm.test.immarg.intrinsic.2ai32([2 x i32] zeroinitializer)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: [2 x i32] [i32 1, i32 2]
; CHECK-NEXT: call void @llvm.test.immarg.intrinsic.2ai32([2 x i32] [i32 1, i32 2])
call void @llvm.test.immarg.intrinsic.2ai32([2 x i32] [i32 1, i32 2])
ret void
}

; CHECK: immarg attribute only applies to intrinsics
; CHECK-NEXT: void (i32)* @not_an_intrinsic
declare void @not_an_intrinsic(i32 immarg)

declare void @llvm.test.intrinsic(i32)
declare void @func(i32)

define void @only_on_callsite() {
; CHECK: immarg attribute only applies to intrinsics
; CHECK-NEXT: call void @func(i32 immarg 0)
; CHECK-NEXT: immarg may not apply only to call sites
; CHECK-NEXT: i32 0
; CHECK-NEXT: call void @func(i32 immarg 0)
call void @func(i32 immarg 0)

; CHECK: immarg may not apply only to call sites
; CHECK-NEXT: i32 0
; CHECK-NEXT: call void @llvm.test.intrinsic(i32 immarg 0)
call void @llvm.test.intrinsic(i32 immarg 0)
ret void
}

; CHECK: immarg attribute only applies to intrinsics
; CHECK: void (i32)* @on_function_definition
define void @on_function_definition(i32 immarg %arg) {
ret void
}
223 changes: 223 additions & 0 deletions llvm/test/Verifier/intrinsic-immarg.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s

declare i8* @llvm.returnaddress(i32)
define void @return_address(i32 %var) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %var
; CHECK-NEXT: %result = call i8* @llvm.returnaddress(i32 %var)
%result = call i8* @llvm.returnaddress(i32 %var)
ret void
}

declare i8* @llvm.frameaddress(i32)
define void @frame_address(i32 %var) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %var
; CHECK-NEXT: %result = call i8* @llvm.frameaddress(i32 %var)
%result = call i8* @llvm.frameaddress(i32 %var)
ret void
}

declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1)
define void @memcpy(i8* %dest, i8* %src, i1 %is.volatile) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %is.volatile
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 8, i1 %is.volatile)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 8, i1 %is.volatile)
ret void
}

declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1)
define void @memmove(i8* %dest, i8* %src, i1 %is.volatile) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %is.volatile
; CHECK-NEXT: call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 8, i1 %is.volatile)
call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 8, i1 %is.volatile)
ret void
}

declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i1)
define void @memset(i8* %dest, i8 %val, i1 %is.volatile) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %is.volatile
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 8, i1 %is.volatile)
call void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 8, i1 %is.volatile)
ret void
}


declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1)
define void @objectsize(i8* %ptr, i1 %a, i1 %b, i1 %c) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %a
; CHECK-NEXT: %val0 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 %a, i1 false, i1 false)
%val0 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 %a, i1 false, i1 false)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %b
; CHECK-NEXT: %val1 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 false, i1 %b, i1 false)
%val1 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 false, i1 %b, i1 false)

; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i1 %c
; CHECK-NEXT: %val2 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 false, i1 false, i1 %c)
%val2 = call i64 @llvm.objectsize.i64.p0i8(i8* %ptr, i1 false, i1 false, i1 %c)
ret void
}

declare i8 @llvm.expect.i8(i8, i8)
define i8 @expect(i8 %arg0, i8 %arg1) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i8 %arg1
; CHECK-NEXT: %ret = call i8 @llvm.expect.i8(i8 %arg0, i8 %arg1)
%ret = call i8 @llvm.expect.i8(i8 %arg0, i8 %arg1)
ret i8 %ret
}

declare i64 @llvm.smul.fix.i64(i64, i64, i32)
define i64 @smul_fix(i64 %arg0, i64 %arg1, i32 %arg2) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg2
; CHECK-NEXT: %ret = call i64 @llvm.smul.fix.i64(i64 %arg0, i64 %arg1, i32 %arg2)
%ret = call i64 @llvm.smul.fix.i64(i64 %arg0, i64 %arg1, i32 %arg2)
ret i64 %ret
}

declare i64 @llvm.umul.fix.i64(i64, i64, i32)
define i64 @umul_fix(i64 %arg0, i64 %arg1, i32 %arg2) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg2
; CHECK-NEXT: %ret = call i64 @llvm.umul.fix.i64(i64 %arg0, i64 %arg1, i32 %arg2)
%ret = call i64 @llvm.umul.fix.i64(i64 %arg0, i64 %arg1, i32 %arg2)
ret i64 %ret
}

declare <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>*, i32, <2 x i1>, <2 x double>)
define <2 x double> @masked_load(<2 x i1> %mask, <2 x double>* %addr, <2 x double> %dst, i32 %align) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %align
; CHECK-NEXT: %res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %addr, i32 %align, <2 x i1> %mask, <2 x double> %dst)
%res = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %addr, i32 %align, <2 x i1> %mask, <2 x double> %dst)
ret <2 x double> %res
}

declare void @llvm.masked.store.v4i32.p0v4i32(<4 x i32>, <4 x i32>*, i32, <4 x i1>)
define void @masked_store(<4 x i1> %mask, <4 x i32>* %addr, <4 x i32> %val, i32 %align) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %align
; CHECK-NEXT: call void @llvm.masked.store.v4i32.p0v4i32(<4 x i32> %val, <4 x i32>* %addr, i32 %align, <4 x i1> %mask)
call void @llvm.masked.store.v4i32.p0v4i32(<4 x i32> %val, <4 x i32>* %addr, i32 %align, <4 x i1> %mask)
ret void
}

declare <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*>, i32, <2 x i1>, <2 x double>)
define <2 x double> @test_gather(<2 x double*> %ptrs, <2 x i1> %mask, <2 x double> %src0, i32 %align) {
; CHECK: immarg operand has non-immediate parameter
; CHECK: i32 %align
; CHECK: %res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 %align, <2 x i1> %mask, <2 x double> %src0)
%res = call <2 x double> @llvm.masked.gather.v2f64.v2p0f64(<2 x double*> %ptrs, i32 %align, <2 x i1> %mask, <2 x double> %src0)
ret <2 x double> %res
}

declare void @llvm.masked.scatter.v8i32.v8p0i32(<8 x i32>, <8 x i32*>, i32, <8 x i1>)
define void @test_scatter_8i32(<8 x i32> %a1, <8 x i32*> %ptr, <8 x i1> %mask, i32 %align) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %align
; CHECK-NEXT: call void @llvm.masked.scatter.v8i32.v8p0i32(<8 x i32> %a1, <8 x i32*> %ptr, i32 %align, <8 x i1> %mask)
call void @llvm.masked.scatter.v8i32.v8p0i32(<8 x i32> %a1, <8 x i32*> %ptr, i32 %align, <8 x i1> %mask)
ret void
}

declare void @llvm.lifetime.start.p0i8(i64, i8*)
define void @test_lifetime_start(i64 %arg0, i8* %ptr) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i64 %arg0
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 %arg0, i8* %ptr)
call void @llvm.lifetime.start.p0i8(i64 %arg0, i8* %ptr)
ret void
}

declare void @llvm.lifetime.end.p0i8(i64, i8*)
define void @test_lifetime_end(i64 %arg0, i8* %ptr) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i64 %arg0
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 %arg0, i8* %ptr)
call void @llvm.lifetime.end.p0i8(i64 %arg0, i8* %ptr)
ret void
}

declare void @llvm.invariant.start.p0i8(i64, i8*)
define void @test_invariant_start(i64 %arg0, i8* %ptr) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i64 %arg0
; CHECK-NEXT: call void @llvm.invariant.start.p0i8(i64 %arg0, i8* %ptr)
call void @llvm.invariant.start.p0i8(i64 %arg0, i8* %ptr)
ret void
}

declare void @llvm.invariant.end.p0i8({}*, i64, i8*)
define void @test_invariant_end({}* %scope, i64 %arg1, i8* %ptr) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i64 %arg1
; CHECK-NEXT: call void @llvm.invariant.end.p0i8({}* %scope, i64 %arg1, i8* %ptr)
call void @llvm.invariant.end.p0i8({}* %scope, i64 %arg1, i8* %ptr)
ret void
}

declare void @llvm.prefetch(i8*, i32, i32, i32)
define void @test_prefetch(i8* %ptr, i32 %arg0, i32 %arg1) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg0
; CHECK-NEXT: call void @llvm.prefetch(i8* %ptr, i32 %arg0, i32 0, i32 0)
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg1
call void @llvm.prefetch(i8* %ptr, i32 %arg0, i32 0, i32 0)
call void @llvm.prefetch(i8* %ptr, i32 0, i32 %arg1, i32 0)
ret void
}

declare void @llvm.localrecover(i8*, i8*, i32)
define void @test_localrecover(i8* %func, i8* %fp, i32 %idx) {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %idx
; CHECK-NEXT: call void @llvm.localrecover(i8* %func, i8* %fp, i32 %idx)
call void @llvm.localrecover(i8* %func, i8* %fp, i32 %idx)
ret void
}

declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)

define private void @f() {
ret void
}

define void @calls_statepoint(i8 addrspace(1)* %arg0, i64 %arg1, i32 %arg2, i32 %arg4, i32 %arg5) gc "statepoint-example" {
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i64 %arg1
; CHECK-NEXT: %safepoint0 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 %arg1, i32 0, void ()* @f, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg2
; CHECK-NEXT: %safepoint1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 %arg2, void ()* @f, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg4
; CHECK-NEXT: %safepoint2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 %arg4, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
; CHECK: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg5
; CHECK-NEXT: %safepoint3 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 0, i32 %arg5, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
%cast = bitcast i8 addrspace(1)* %arg0 to i64 addrspace(1)*
%safepoint0 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 %arg1, i32 0, void ()* @f, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
%safepoint1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 %arg2, void ()* @f, i32 0, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
%safepoint2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 %arg4, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
%safepoint3 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 0, i32 %arg5, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg0, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg0, i8 addrspace(1)* %arg0)
ret void
}

declare void @llvm.hwasan.check.memaccess(i8*, i8*, i32)

define void @hwasan_check_memaccess(i8* %arg0,i8* %arg1, i32 %arg2) {
; CHECK: immarg operand has non-immediate parameter
; CHECK: i32 %arg2
; CHECK: call void @llvm.hwasan.check.memaccess(i8* %arg0, i8* %arg1, i32 %arg2)
call void @llvm.hwasan.check.memaccess(i8* %arg0,i8* %arg1, i32 %arg2)
ret void
}
10 changes: 9 additions & 1 deletion llvm/utils/TableGen/CodeGenIntrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,15 @@ struct CodeGenIntrinsic {
// True if the intrinsic is marked as speculatable.
bool isSpeculatable;

enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone };
enum ArgAttribute {
NoCapture,
Returned,
ReadOnly,
WriteOnly,
ReadNone,
ImmArg
};

std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes;

bool hasProperty(enum SDNP Prop) const {
Expand Down
3 changes: 3 additions & 0 deletions llvm/utils/TableGen/CodeGenTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,9 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
} else if (Property->isSubClassOf("ReadNone")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone));
} else if (Property->isSubClassOf("ImmArg")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, ImmArg));
} else
llvm_unreachable("Unknown property!");
}
Expand Down
7 changes: 6 additions & 1 deletion llvm/utils/TableGen/IntrinsicEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,6 @@ struct AttributeComparator {
CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
if (LK != RK) return (LK > RK);

// Order by argument attributes.
// This is reliable because each side is already sorted internally.
return (L->ArgumentAttributes < R->ArgumentAttributes);
Expand Down Expand Up @@ -612,6 +611,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << "Attribute::ReadNone";
addComma = true;
break;
case CodeGenIntrinsic::ImmArg:
if (addComma)
OS << ',';
OS << "Attribute::ImmArg";
addComma = true;
break;
}

++ai;
Expand Down
2 changes: 1 addition & 1 deletion llvm/utils/emacs/llvm-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"noduplicate" "noimplicitfloat" "noinline" "nonlazybind" "noredzone" "noreturn"
"norecurse" "nounwind" "optnone" "optsize" "readnone" "readonly" "returns_twice"
"speculatable" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress"
"sanitize_thread" "sanitize_memory" "strictfp" "uwtable" "writeonly") 'symbols) . font-lock-constant-face)
"sanitize_thread" "sanitize_memory" "strictfp" "uwtable" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
;; Variables
'("%[-a-zA-Z$._][-a-zA-Z$._0-9]*" . font-lock-variable-name-face)
;; Labels
Expand Down