Skip to content

Commit c85611e

Browse files
authored
[SimplifyLibCall][Attribute] Fix bug where we may keep range attr with incompatible type (#112649)
In a variety of places we change the bitwidth of a parameter but don't update the attributes. The issue in this case is from the `range` attribute when inlining `__memset_chk`. `optimizeMemSetChk` will replace an `i32` with an `i8`, and if the `i32` had a `range` attr assosiated it will cause an error. Fixes #112633
1 parent ab208de commit c85611e

18 files changed

+88
-34
lines changed

llvm/include/llvm/IR/Argument.h

+2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ class Argument final : public Value {
182182

183183
Attribute getAttribute(Attribute::AttrKind Kind) const;
184184

185+
AttributeSet getAttributes() const;
186+
185187
/// Method for support type inquiry through isa, cast, and dyn_cast.
186188
static bool classof(const Value *V) {
187189
return V->getValueID() == ArgumentVal;

llvm/include/llvm/IR/Attributes.h

+11-5
Original file line numberDiff line numberDiff line change
@@ -1288,11 +1288,17 @@ enum AttributeSafetyKind : uint8_t {
12881288
/// follows the same type rules as FPMathOperator.
12891289
bool isNoFPClassCompatibleType(Type *Ty);
12901290

1291-
/// Which attributes cannot be applied to a type. The argument \p ASK indicates,
1292-
/// if only attributes that are known to be safely droppable are contained in
1293-
/// the mask; only attributes that might be unsafe to drop (e.g., ABI-related
1294-
/// attributes) are in the mask; or both.
1295-
AttributeMask typeIncompatible(Type *Ty, AttributeSafetyKind ASK = ASK_ALL);
1291+
/// Which attributes cannot be applied to a type. The argument \p AS
1292+
/// is used as a hint for the attributes whose compatibility is being
1293+
/// checked against \p Ty. This does not mean the return will be a
1294+
/// subset of \p AS, just that attributes that have specific dynamic
1295+
/// type compatibilities (i.e `range`) will be checked against what is
1296+
/// contained in \p AS. The argument \p ASK indicates, if only
1297+
/// attributes that are known to be safely droppable are contained in
1298+
/// the mask; only attributes that might be unsafe to drop (e.g.,
1299+
/// ABI-related attributes) are in the mask; or both.
1300+
AttributeMask typeIncompatible(Type *Ty, AttributeSet AS,
1301+
AttributeSafetyKind ASK = ASK_ALL);
12961302

12971303
/// Get param/return attributes which imply immediate undefined behavior if an
12981304
/// invalid value is passed. For example, this includes noundef (where undef

llvm/include/llvm/IR/InstrTypes.h

+12-4
Original file line numberDiff line numberDiff line change
@@ -1453,14 +1453,22 @@ class CallBase : public Instruction {
14531453
/// looking through to the attributes on the called function when necessary).
14541454
///@{
14551455

1456-
/// Return the parameter attributes for this call.
1457-
///
1456+
/// Return the attributes for this call.
14581457
AttributeList getAttributes() const { return Attrs; }
14591458

1460-
/// Set the parameter attributes for this call.
1461-
///
1459+
/// Set the attributes for this call.
14621460
void setAttributes(AttributeList A) { Attrs = A; }
14631461

1462+
/// Return the return attributes for this call.
1463+
AttributeSet getRetAttributes() const {
1464+
return getAttributes().getRetAttrs();
1465+
}
1466+
1467+
/// Return the param attributes for this call.
1468+
AttributeSet getParamAttributes(unsigned ArgNo) const {
1469+
return getAttributes().getParamAttrs(ArgNo);
1470+
}
1471+
14641472
/// Try to intersect the attributes from 'this' CallBase and the
14651473
/// 'Other' CallBase. Sets the intersected attributes to 'this' and
14661474
/// return true if successful. Doesn't modify 'this' and returns

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -7040,11 +7040,12 @@ Error BitcodeReader::materialize(GlobalValue *GV) {
70407040
// Remove incompatible attributes on function calls.
70417041
if (auto *CI = dyn_cast<CallBase>(&I)) {
70427042
CI->removeRetAttrs(AttributeFuncs::typeIncompatible(
7043-
CI->getFunctionType()->getReturnType()));
7043+
CI->getFunctionType()->getReturnType(), CI->getRetAttributes()));
70447044

70457045
for (unsigned ArgNo = 0; ArgNo < CI->arg_size(); ++ArgNo)
70467046
CI->removeParamAttrs(ArgNo, AttributeFuncs::typeIncompatible(
7047-
CI->getArgOperand(ArgNo)->getType()));
7047+
CI->getArgOperand(ArgNo)->getType(),
7048+
CI->getParamAttributes(ArgNo)));
70487049
}
70497050
}
70507051

llvm/lib/IR/Attributes.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -2300,7 +2300,7 @@ bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {
23002300
}
23012301

23022302
/// Which attributes cannot be applied to a type.
2303-
AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
2303+
AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
23042304
AttributeSafetyKind ASK) {
23052305
AttributeMask Incompatible;
23062306

@@ -2316,6 +2316,11 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
23162316
// Attributes that only apply to integers or vector of integers.
23172317
if (ASK & ASK_SAFE_TO_DROP)
23182318
Incompatible.addAttribute(Attribute::Range);
2319+
} else {
2320+
Attribute RangeAttr = AS.getAttribute(Attribute::Range);
2321+
if (RangeAttr.isValid() &&
2322+
RangeAttr.getRange().getBitWidth() != Ty->getScalarSizeInBits())
2323+
Incompatible.addAttribute(Attribute::Range);
23192324
}
23202325

23212326
if (!Ty->isPointerTy()) {

llvm/lib/IR/AutoUpgrade.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -5378,9 +5378,11 @@ void llvm::UpgradeFunctionAttributes(Function &F) {
53785378
}
53795379

53805380
// Remove all incompatibile attributes from function.
5381-
F.removeRetAttrs(AttributeFuncs::typeIncompatible(F.getReturnType()));
5381+
F.removeRetAttrs(AttributeFuncs::typeIncompatible(
5382+
F.getReturnType(), F.getAttributes().getRetAttrs()));
53825383
for (auto &Arg : F.args())
5383-
Arg.removeAttrs(AttributeFuncs::typeIncompatible(Arg.getType()));
5384+
Arg.removeAttrs(
5385+
AttributeFuncs::typeIncompatible(Arg.getType(), Arg.getAttributes()));
53845386

53855387
// Older versions of LLVM treated an "implicit-section-name" attribute
53865388
// similarly to directly setting the section on a Function.

llvm/lib/IR/Function.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,10 @@ Attribute Argument::getAttribute(Attribute::AttrKind Kind) const {
359359
return getParent()->getParamAttribute(getArgNo(), Kind);
360360
}
361361

362+
AttributeSet Argument::getAttributes() const {
363+
return getParent()->getAttributes().getParamAttrs(getArgNo());
364+
}
365+
362366
//===----------------------------------------------------------------------===//
363367
// Helper Methods in Function
364368
//===----------------------------------------------------------------------===//

llvm/lib/IR/Verifier.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,7 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
20122012
Attrs.hasAttribute(Attribute::ReadOnly)),
20132013
"Attributes writable and readonly are incompatible!", V);
20142014

2015-
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
2015+
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty, Attrs);
20162016
for (Attribute Attr : Attrs) {
20172017
if (!Attr.isStringAttribute() &&
20182018
IncompatibleAttrs.contains(Attr.getKindAsEnum())) {

llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,8 @@ bool AMDGPULibCalls::fold(CallInst *CI) {
788788
B.CreateFPToSI(FPOp->getOperand(1), PownType->getParamType(1));
789789
// Have to drop any nofpclass attributes on the original call site.
790790
Call->removeParamAttrs(
791-
1, AttributeFuncs::typeIncompatible(CastedArg->getType()));
791+
1, AttributeFuncs::typeIncompatible(CastedArg->getType(),
792+
Call->getParamAttributes(1)));
792793
Call->setCalledFunction(PownFunc);
793794
Call->setArgOperand(1, CastedArg);
794795
return fold_pow(FPOp, B, PownInfo) || true;

llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -857,9 +857,10 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
857857
// here. Currently, this should not be possible, but special handling might be
858858
// required when new return value attributes are added.
859859
if (NRetTy->isVoidTy())
860-
RAttrs.remove(AttributeFuncs::typeIncompatible(NRetTy));
860+
RAttrs.remove(AttributeFuncs::typeIncompatible(NRetTy, PAL.getRetAttrs()));
861861
else
862-
assert(!RAttrs.overlaps(AttributeFuncs::typeIncompatible(NRetTy)) &&
862+
assert(!RAttrs.overlaps(
863+
AttributeFuncs::typeIncompatible(NRetTy, PAL.getRetAttrs())) &&
863864
"Return attributes no longer compatible?");
864865

865866
AttributeSet RetAttrs = AttributeSet::get(F->getContext(), RAttrs);
@@ -903,7 +904,8 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
903904
// Adjust the call return attributes in case the function was changed to
904905
// return void.
905906
AttrBuilder RAttrs(F->getContext(), CallPAL.getRetAttrs());
906-
RAttrs.remove(AttributeFuncs::typeIncompatible(NRetTy));
907+
RAttrs.remove(
908+
AttributeFuncs::typeIncompatible(NRetTy, CallPAL.getRetAttrs()));
907909
AttributeSet RetAttrs = AttributeSet::get(F->getContext(), RAttrs);
908910

909911
// Declare these outside of the loops, so we can reuse them for the second

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -4151,7 +4151,8 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
41514151

41524152
if (!CallerPAL.isEmpty() && !Caller->use_empty()) {
41534153
AttrBuilder RAttrs(FT->getContext(), CallerPAL.getRetAttrs());
4154-
if (RAttrs.overlaps(AttributeFuncs::typeIncompatible(NewRetTy)))
4154+
if (RAttrs.overlaps(AttributeFuncs::typeIncompatible(
4155+
NewRetTy, CallerPAL.getRetAttrs())))
41554156
return false; // Attribute not compatible with transformed value.
41564157
}
41574158

@@ -4197,7 +4198,8 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
41974198
// Check if there are any incompatible attributes we cannot drop safely.
41984199
if (AttrBuilder(FT->getContext(), CallerPAL.getParamAttrs(i))
41994200
.overlaps(AttributeFuncs::typeIncompatible(
4200-
ParamTy, AttributeFuncs::ASK_UNSAFE_TO_DROP)))
4201+
ParamTy, CallerPAL.getParamAttrs(i),
4202+
AttributeFuncs::ASK_UNSAFE_TO_DROP)))
42014203
return false; // Attribute not compatible with transformed value.
42024204

42034205
if (Call.isInAllocaArgument(i) ||
@@ -4235,7 +4237,8 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
42354237

42364238
// If the return value is not being used, the type may not be compatible
42374239
// with the existing attributes. Wipe out any problematic attributes.
4238-
RAttrs.remove(AttributeFuncs::typeIncompatible(NewRetTy));
4240+
RAttrs.remove(
4241+
AttributeFuncs::typeIncompatible(NewRetTy, CallerPAL.getRetAttrs()));
42394242

42404243
LLVMContext &Ctx = Call.getContext();
42414244
AI = Call.arg_begin();
@@ -4250,7 +4253,7 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
42504253
// Add any parameter attributes except the ones incompatible with the new
42514254
// type. Note that we made sure all incompatible ones are safe to drop.
42524255
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(
4253-
ParamTy, AttributeFuncs::ASK_SAFE_TO_DROP);
4256+
ParamTy, CallerPAL.getParamAttrs(i), AttributeFuncs::ASK_SAFE_TO_DROP);
42544257
ArgAttrs.push_back(
42554258
CallerPAL.getParamAttrs(i).removeAttributes(Ctx, IncompatibleAttrs));
42564259
}

llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1305,8 +1305,8 @@ DataFlowSanitizer::buildWrapperFunction(Function *F, StringRef NewFName,
13051305
Function *NewF = Function::Create(NewFT, NewFLink, F->getAddressSpace(),
13061306
NewFName, F->getParent());
13071307
NewF->copyAttributesFrom(F);
1308-
NewF->removeRetAttrs(
1309-
AttributeFuncs::typeIncompatible(NewFT->getReturnType()));
1308+
NewF->removeRetAttrs(AttributeFuncs::typeIncompatible(
1309+
NewFT->getReturnType(), NewF->getAttributes().getRetAttrs()));
13101310

13111311
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", NewF);
13121312
if (F->isVarArg()) {

llvm/lib/Transforms/Utils/CallPromotionUtils.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,8 @@ CallBase &llvm::promoteCall(CallBase &CB, Function *Callee,
529529

530530
// Remove any incompatible attributes for the argument.
531531
AttrBuilder ArgAttrs(Ctx, CallerPAL.getParamAttrs(ArgNo));
532-
ArgAttrs.remove(AttributeFuncs::typeIncompatible(FormalTy));
532+
ArgAttrs.remove(AttributeFuncs::typeIncompatible(
533+
FormalTy, CallerPAL.getParamAttrs(ArgNo)));
533534

534535
// We may have a different byval/inalloca type.
535536
if (ArgAttrs.getByValType())
@@ -549,7 +550,8 @@ CallBase &llvm::promoteCall(CallBase &CB, Function *Callee,
549550
AttrBuilder RAttrs(Ctx, CallerPAL.getRetAttrs());
550551
if (!CallSiteRetTy->isVoidTy() && CallSiteRetTy != CalleeRetTy) {
551552
createRetBitCast(CB, CallSiteRetTy, RetBitCast);
552-
RAttrs.remove(AttributeFuncs::typeIncompatible(CalleeRetTy));
553+
RAttrs.remove(
554+
AttributeFuncs::typeIncompatible(CalleeRetTy, CallerPAL.getRetAttrs()));
553555
AttributeChanged = true;
554556
}
555557

llvm/lib/Transforms/Utils/CloneFunction.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,9 @@ void llvm::CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
819819
// Drop all incompatible return attributes that cannot be applied to NewFunc
820820
// during cloning, so as to allow instruction simplification to reason on the
821821
// old state of the function. The original attributes are restored later.
822-
AttributeMask IncompatibleAttrs =
823-
AttributeFuncs::typeIncompatible(OldFunc->getReturnType());
824822
AttributeList Attrs = NewFunc->getAttributes();
823+
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(
824+
OldFunc->getReturnType(), Attrs.getRetAttrs());
825825
NewFunc->removeRetAttrs(IncompatibleAttrs);
826826

827827
// As phi-nodes have been now remapped, allow incremental simplification of

llvm/lib/Transforms/Utils/InlineFunction.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3057,8 +3057,8 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
30573057
else
30583058
Builder.CreateRet(NewDeoptCall);
30593059
// Since the ret type is changed, remove the incompatible attributes.
3060-
NewDeoptCall->removeRetAttrs(
3061-
AttributeFuncs::typeIncompatible(NewDeoptCall->getType()));
3060+
NewDeoptCall->removeRetAttrs(AttributeFuncs::typeIncompatible(
3061+
NewDeoptCall->getType(), NewDeoptCall->getRetAttributes()));
30623062
}
30633063

30643064
// Leave behind the normal returns so we can merge control flow.

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,13 @@ static Value *copyFlags(const CallInst &Old, Value *New) {
342342
static Value *mergeAttributesAndFlags(CallInst *NewCI, const CallInst &Old) {
343343
NewCI->setAttributes(AttributeList::get(
344344
NewCI->getContext(), {NewCI->getAttributes(), Old.getAttributes()}));
345-
NewCI->removeRetAttrs(AttributeFuncs::typeIncompatible(NewCI->getType()));
345+
NewCI->removeRetAttrs(AttributeFuncs::typeIncompatible(
346+
NewCI->getType(), NewCI->getRetAttributes()));
347+
for (unsigned I = 0; I < NewCI->arg_size(); ++I)
348+
NewCI->removeParamAttrs(
349+
I, AttributeFuncs::typeIncompatible(NewCI->getArgOperand(I)->getType(),
350+
NewCI->getParamAttributes(I)));
351+
346352
return copyFlags(Old, NewCI);
347353
}
348354

llvm/test/Transforms/InstCombine/simplify-libcalls.ll

+12
Original file line numberDiff line numberDiff line change
@@ -342,5 +342,17 @@ define signext i32 @emit_stpncpy() {
342342
ret i32 0
343343
}
344344

345+
define void @simplify_memset_chk_pr112633(ptr %p, i32 %conv) {
346+
; CHECK-LABEL: @simplify_memset_chk_pr112633(
347+
; CHECK-NEXT: [[CALL_I:%.*]] = tail call ptr @__memset_chk(ptr [[P:%.*]], i32 range(i32 0, 123) [[CONV:%.*]], i64 1, i64 1)
348+
; CHECK-NEXT: ret void
349+
;
350+
%call.i = tail call ptr @__memset_chk(ptr %p, i32 range(i32 0, 123) %conv, i64 1, i64 1)
351+
ret void
352+
}
353+
354+
declare ptr @__memset_chk(ptr, i32, i64, i64)
355+
356+
345357
attributes #0 = { nobuiltin }
346358
attributes #1 = { builtin }

llvm/test/Verifier/range-attr.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
22

3-
; CHECK: Range bit width must match type bit width!
3+
; CHECK: Attribute 'range(i8 1, 0)' applied to incompatible type!
44
; CHECK-NEXT: ptr @bit_widths_do_not_match
55
define void @bit_widths_do_not_match(i32 range(i8 1, 0) %a) {
66
ret void
77
}
88

9-
; CHECK: Range bit width must match type bit width!
9+
; CHECK: Attribute 'range(i8 1, 0)' applied to incompatible type!
1010
; CHECK-NEXT: ptr @bit_widths_do_not_match_vector
1111
define void @bit_widths_do_not_match_vector(<4 x i32> range(i8 1, 0) %a) {
1212
ret void

0 commit comments

Comments
 (0)