Skip to content

Commit c3c0b27

Browse files
authored
[Intrinsics] Add support for range attributes (#135642)
Add support for specifying range attributes in Intrinsics.td. Use this to specify the ucmp/scmp range [-1,2). This case is trickier than existing intrinsic attributes, because we need to create the attribute with the correct bitwidth. As such, the attribute construction now needs to be aware of the function type. We also need to be careful to no longer assign attributes on intrinsics with invalid signatures, as we'd make invalid assumptions about the number of arguments etc otherwise. Fixes #130179.
1 parent bd49bba commit c3c0b27

File tree

14 files changed

+90
-40
lines changed

14 files changed

+90
-40
lines changed

llvm/include/llvm/IR/Intrinsics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ namespace Intrinsic {
8686
ID lookupIntrinsicID(StringRef Name);
8787

8888
/// Return the attributes for an intrinsic.
89-
AttributeList getAttributes(LLVMContext &C, ID id);
89+
AttributeList getAttributes(LLVMContext &C, ID id, FunctionType *FT);
9090

9191
/// Return the function attributes for an intrinsic.
9292
AttributeSet getFnAttributes(LLVMContext &C, ID id);

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ class ReadNone<ArgIndex idx> : IntrinsicProperty {
134134
int ArgNo = idx.Value;
135135
}
136136

137+
// The return value or argument is in the range [lower, upper),
138+
// where lower and upper are interpreted as signed integers.
139+
class Range<AttrIndex idx, int lower, int upper> : IntrinsicProperty {
140+
int ArgNo = idx.Value;
141+
int Lower = lower;
142+
int Upper = upper;
143+
}
144+
137145
def IntrNoReturn : IntrinsicProperty;
138146

139147
// Applied by default.
@@ -1620,10 +1628,10 @@ def int_umin : DefaultAttrsIntrinsic<
16201628
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
16211629
def int_scmp : DefaultAttrsIntrinsic<
16221630
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
1623-
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
1631+
[IntrNoMem, IntrSpeculatable, IntrWillReturn, Range<RetIndex, -1, 2>]>;
16241632
def int_ucmp : DefaultAttrsIntrinsic<
16251633
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
1626-
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
1634+
[IntrNoMem, IntrSpeculatable, IntrWillReturn, Range<RetIndex, -1, 2>]>;
16271635

16281636
//===------------------------- Memory Use Markers -------------------------===//
16291637
//

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,8 +1519,13 @@ bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn,
15191519
// Upgrade intrinsic attributes. This does not change the function.
15201520
if (NewFn)
15211521
F = NewFn;
1522-
if (Intrinsic::ID id = F->getIntrinsicID())
1523-
F->setAttributes(Intrinsic::getAttributes(F->getContext(), id));
1522+
if (Intrinsic::ID id = F->getIntrinsicID()) {
1523+
// Only do this if the intrinsic signature is valid.
1524+
SmallVector<Type *> OverloadTys;
1525+
if (Intrinsic::getIntrinsicSignature(id, F->getFunctionType(), OverloadTys))
1526+
F->setAttributes(
1527+
Intrinsic::getAttributes(F->getContext(), id, F->getFunctionType()));
1528+
}
15241529
return Upgraded;
15251530
}
15261531

llvm/lib/IR/Function.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,15 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
514514
// Ensure intrinsics have the right parameter attributes.
515515
// Note, the IntID field will have been set in Value::setName if this function
516516
// name is a valid intrinsic ID.
517-
if (IntID)
518-
setAttributes(Intrinsic::getAttributes(getContext(), IntID));
517+
if (IntID) {
518+
// Don't set the attributes if the intrinsic signature is invalid. This
519+
// case will either be auto-upgraded or fail verification.
520+
SmallVector<Type *> OverloadTys;
521+
if (!Intrinsic::getIntrinsicSignature(IntID, Ty, OverloadTys))
522+
return;
523+
524+
setAttributes(Intrinsic::getAttributes(getContext(), IntID, Ty));
525+
}
519526
}
520527

521528
Function::~Function() {

llvm/lib/IR/Intrinsics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/IR/Intrinsics.h"
1414
#include "llvm/ADT/StringExtras.h"
1515
#include "llvm/ADT/StringTable.h"
16+
#include "llvm/IR/ConstantRange.h"
1617
#include "llvm/IR/Function.h"
1718
#include "llvm/IR/IntrinsicsAArch64.h"
1819
#include "llvm/IR/IntrinsicsAMDGPU.h"

llvm/lib/Target/AMDGPU/SIISelLowering.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16506,7 +16506,8 @@ Align SITargetLowering::computeKnownAlignForTargetInstr(
1650616506
// site specifies a lower alignment?
1650716507
Intrinsic::ID IID = GI->getIntrinsicID();
1650816508
LLVMContext &Ctx = VT.getMachineFunction().getFunction().getContext();
16509-
AttributeList Attrs = Intrinsic::getAttributes(Ctx, IID);
16509+
AttributeList Attrs =
16510+
Intrinsic::getAttributes(Ctx, IID, Intrinsic::getType(Ctx, IID));
1651016511
if (MaybeAlign RetAlign = Attrs.getRetAlignment())
1651116512
return *RetAlign;
1651216513
}

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2903,7 +2903,7 @@ static void stripNonValidAttributesFromPrototype(Function &F) {
29032903
// assumes that the attributes defined in Intrinsic.td are conservatively
29042904
// correct for both physical and abstract model.
29052905
if (Intrinsic::ID id = F.getIntrinsicID()) {
2906-
F.setAttributes(Intrinsic::getAttributes(Ctx, id));
2906+
F.setAttributes(Intrinsic::getAttributes(Ctx, id, F.getFunctionType()));
29072907
return;
29082908
}
29092909

llvm/test/Assembler/aarch64-intrinsics-attributes.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ declare i64 @llvm.aarch64.ldxr.p0(ptr)
1010
; CHECK: declare i32 @llvm.aarch64.stxp(i64, i64, ptr) [[NOFREE_NOUNWIND_WILLRETURN]]
1111
declare i32 @llvm.aarch64.stxp(i64, i64, ptr)
1212

13-
; CHECK: declare i32 @llvm.aarch64.dsb(i32) [[NOFREE_NOUNWIND_WILLRETURN]]
14-
declare i32 @llvm.aarch64.dsb(i32)
13+
; CHECK: declare void @llvm.aarch64.dsb(i32) [[NOFREE_NOUNWIND_WILLRETURN]]
14+
declare void @llvm.aarch64.dsb(i32)
1515

1616
; CHECK: declare i64 @llvm.aarch64.neon.sqdmulls.scalar(i32, i32) [[NO_CALLBACK_NOFREE_NOSYNC_NOUNWIND_READNONE_WILLRETURN:#[0-9]+]]
1717
declare i64 @llvm.aarch64.neon.sqdmulls.scalar(i32, i32)
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
1+
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
22

33
; Check that remangling code doesn't fail on an intrinsic with wrong signature
4+
; TODO: This should probably produce an error.
45

5-
; CHECK: Attribute after last parameter!
6-
; CHECK-NEXT: ptr @llvm.memset.i64
6+
; CHECK: declare void @llvm.memset.i64
77
declare void @llvm.memset.i64(ptr nocapture, i8, i64) nounwind
88

9-
; CHECK: Attribute after last parameter!
10-
; CHECK-NEXT: ptr @llvm.memcpy.i64
9+
; CHECK: declare void @llvm.memcpy.i64
1110
declare void @llvm.memcpy.i64(ptr nocapture, i8, i64) nounwind
1211

13-
; CHECK: Attribute after last parameter!
14-
; CHECK-NEXT: ptr @llvm.memmove.i64
12+
; CHECK: declare void @llvm.memmove.i64
1513
declare void @llvm.memmove.i64(ptr nocapture, i8, i64) nounwind

llvm/test/TableGen/intrinsic-attrs.td

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ def int_random_gen : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffec
66

77
def int_deref_ptr_ret : Intrinsic<[llvm_ptr_ty], [], [Dereferenceable<RetIndex, 16>]>;
88

9-
// CHECK: static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID) {
10-
// CHECK-NEXT: switch (ID) {
9+
// CHECK: static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID,
10+
// CHECK-NEXT: Type *ArgType) {
11+
// CHECK-NEXT: unsigned BitWidth = ArgType->getScalarSizeInBits();
12+
// CHECK-NEXT: switch (ID) {
1113
// CHECK-NEXT: default: llvm_unreachable("Invalid attribute set number");
1214
// CHECK-NEXT: case 0:
1315
// CHECK-NEXT: return AttributeSet::get(C, {
@@ -26,13 +28,14 @@ def int_deref_ptr_ret : Intrinsic<[llvm_ptr_ty], [], [Dereferenceable<RetIndex,
2628
// CHECK: 0 << 8 | 0, // llvm.deref.ptr.ret
2729
// CHECK: 1 << 8 | 1, // llvm.random.gen
2830

29-
// CHECK: getAttributes(LLVMContext &C, ID id)
31+
// CHECK: getAttributes(LLVMContext &C, ID id,
32+
// CHECK-NEXT: FunctionType *FT) {
3033
// CHECK: case 1:
3134
// CHECK-NEXT: return AttributeList::get(C, {
3235
// CHECK-NEXT: {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, FnAttrID)}
3336
// CHECK-NEXT: });
3437
// CHECK-NEXT: case 0:
3538
// CHECK-NEXT: return AttributeList::get(C, {
36-
// CHECK-NEXT: {0, getIntrinsicArgAttributeSet(C, 0)},
39+
// CHECK-NEXT: {0, getIntrinsicArgAttributeSet(C, 0, FT->getContainedType(0))},
3740
// CHECK-NEXT: {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, FnAttrID)}
3841
// CHECK-NEXT: });

llvm/test/Transforms/CorrelatedValuePropagation/uscmp.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,9 @@ define i8 @ucmp_switch(i32 %x, i32 %y) {
261261
; CHECK-LABEL: @ucmp_switch(
262262
; CHECK-NEXT: [[CMP:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
263263
; CHECK-NEXT: switch i8 [[CMP]], label [[DEFAULT_UNREACHABLE:%.*]] [
264-
; CHECK-NEXT: i8 -2, label [[BB_NEG2:%.*]]
264+
; CHECK-NEXT: i8 1, label [[BB_1:%.*]]
265265
; CHECK-NEXT: i8 -1, label [[BB_NEG1:%.*]]
266266
; CHECK-NEXT: i8 0, label [[BB_0:%.*]]
267-
; CHECK-NEXT: i8 1, label [[BB_1:%.*]]
268-
; CHECK-NEXT: i8 2, label [[BB_2:%.*]]
269267
; CHECK-NEXT: ]
270268
; CHECK: bb.neg2:
271269
; CHECK-NEXT: ret i8 -2
@@ -277,6 +275,8 @@ define i8 @ucmp_switch(i32 %x, i32 %y) {
277275
; CHECK-NEXT: ret i8 1
278276
; CHECK: bb.2:
279277
; CHECK-NEXT: ret i8 2
278+
; CHECK: default.unreachable:
279+
; CHECK-NEXT: unreachable
280280
; CHECK: default:
281281
; CHECK-NEXT: ret i8 123
282282
;
@@ -312,11 +312,9 @@ define i8 @scmp_switch(i32 %x, i32 %y) {
312312
; CHECK-LABEL: @scmp_switch(
313313
; CHECK-NEXT: [[CMP:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
314314
; CHECK-NEXT: switch i8 [[CMP]], label [[DEFAULT_UNREACHABLE:%.*]] [
315-
; CHECK-NEXT: i8 -2, label [[BB_NEG2:%.*]]
315+
; CHECK-NEXT: i8 1, label [[BB_1:%.*]]
316316
; CHECK-NEXT: i8 -1, label [[BB_NEG1:%.*]]
317317
; CHECK-NEXT: i8 0, label [[BB_0:%.*]]
318-
; CHECK-NEXT: i8 1, label [[BB_1:%.*]]
319-
; CHECK-NEXT: i8 2, label [[BB_2:%.*]]
320318
; CHECK-NEXT: ]
321319
; CHECK: bb.neg2:
322320
; CHECK-NEXT: ret i8 -2
@@ -328,6 +326,8 @@ define i8 @scmp_switch(i32 %x, i32 %y) {
328326
; CHECK-NEXT: ret i8 1
329327
; CHECK: bb.2:
330328
; CHECK-NEXT: ret i8 2
329+
; CHECK: default.unreachable:
330+
; CHECK-NEXT: unreachable
331331
; CHECK: default:
332332
; CHECK-NEXT: ret i8 123
333333
;

llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,11 @@ void CodeGenIntrinsic::setProperty(const Record *R) {
439439
unsigned ArgNo = R->getValueAsInt("ArgNo");
440440
uint64_t Bytes = R->getValueAsInt("Bytes");
441441
addArgAttribute(ArgNo, Dereferenceable, Bytes);
442+
} else if (R->isSubClassOf("Range")) {
443+
unsigned ArgNo = R->getValueAsInt("ArgNo");
444+
int64_t Lower = R->getValueAsInt("Lower");
445+
int64_t Upper = R->getValueAsInt("Upper");
446+
addArgAttribute(ArgNo, Range, Lower, Upper);
442447
} else
443448
llvm_unreachable("Unknown property!");
444449
}
@@ -455,14 +460,14 @@ bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
455460
++ParamIdx;
456461
if (ParamIdx >= ArgumentAttributes.size())
457462
return false;
458-
ArgAttribute Val{ImmArg, 0};
463+
ArgAttribute Val{ImmArg, 0, 0};
459464
return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
460465
ArgumentAttributes[ParamIdx].end(), Val);
461466
}
462467

463-
void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
464-
uint64_t V) {
468+
void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V,
469+
uint64_t V2) {
465470
if (Idx >= ArgumentAttributes.size())
466471
ArgumentAttributes.resize(Idx + 1);
467-
ArgumentAttributes[Idx].emplace_back(AK, V);
472+
ArgumentAttributes[Idx].emplace_back(AK, V, V2);
468473
}

llvm/utils/TableGen/Basic/CodeGenIntrinsics.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,29 @@ struct CodeGenIntrinsic {
128128
ReadNone,
129129
ImmArg,
130130
Alignment,
131-
Dereferenceable
131+
Dereferenceable,
132+
Range,
132133
};
133134

134135
struct ArgAttribute {
135136
ArgAttrKind Kind;
136137
uint64_t Value;
138+
uint64_t Value2;
137139

138-
ArgAttribute(ArgAttrKind K, uint64_t V) : Kind(K), Value(V) {}
140+
ArgAttribute(ArgAttrKind K, uint64_t V, uint64_t V2)
141+
: Kind(K), Value(V), Value2(V2) {}
139142

140143
bool operator<(const ArgAttribute &Other) const {
141-
return std::tie(Kind, Value) < std::tie(Other.Kind, Other.Value);
144+
return std::tie(Kind, Value, Value2) <
145+
std::tie(Other.Kind, Other.Value, Other.Value2);
142146
}
143147
};
144148

145149
/// Vector of attributes for each argument.
146150
SmallVector<SmallVector<ArgAttribute, 0>> ArgumentAttributes;
147151

148-
void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0);
152+
void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0,
153+
uint64_t V2 = 0);
149154

150155
bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
151156

llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ static StringRef getArgAttrEnumName(CodeGenIntrinsic::ArgAttrKind Kind) {
493493
return "Alignment";
494494
case CodeGenIntrinsic::Dereferenceable:
495495
return "Dereferenceable";
496+
case CodeGenIntrinsic::Range:
497+
return "Range";
496498
}
497499
llvm_unreachable("Unknown CodeGenIntrinsic::ArgAttrKind enum");
498500
}
@@ -502,7 +504,9 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
502504
raw_ostream &OS) {
503505
OS << R"(// Add parameter attributes that are not common to all intrinsics.
504506
#ifdef GET_INTRINSIC_ATTRIBUTES
505-
static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID) {
507+
static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID,
508+
Type *ArgType) {
509+
unsigned BitWidth = ArgType->getScalarSizeInBits();
506510
switch (ID) {
507511
default: llvm_unreachable("Invalid attribute set number");)";
508512
// Compute unique argument attribute sets.
@@ -535,6 +539,17 @@ static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID) {
535539
Attr.Kind == CodeGenIntrinsic::Dereferenceable)
536540
OS << formatv(" Attribute::get(C, Attribute::{}, {}),\n",
537541
AttrName, Attr.Value);
542+
else if (Attr.Kind == CodeGenIntrinsic::Range)
543+
// This allows implicitTrunc because the range may only fit the
544+
// type based on rules implemented in the IR verifier. E.g. the
545+
// [-1, 1] range for ucmp/scmp intrinsics requires a minimum i2 type.
546+
// Give the verifier a chance to diagnose this instead of asserting
547+
// here.
548+
OS << formatv(" Attribute::get(C, Attribute::{}, "
549+
"ConstantRange(APInt(BitWidth, {}, /*isSigned=*/true, "
550+
"/*implicitTrunc=*/true), APInt(BitWidth, {}, "
551+
"/*isSigned=*/true, /*implicitTrunc=*/true))),\n",
552+
AttrName, (int64_t)Attr.Value, (int64_t)Attr.Value2);
538553
else
539554
OS << formatv(" Attribute::get(C, Attribute::{}),\n", AttrName);
540555
}
@@ -635,7 +650,8 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
635650
OS << R"(
636651
};
637652
638-
AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {)";
653+
AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
654+
FunctionType *FT) {)";
639655

640656
OS << formatv(R"(
641657
if (id == 0)
@@ -669,8 +685,9 @@ AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {)";
669685

670686
unsigned ArgAttrID = UniqArgAttributes.find(Attrs)->second;
671687
OS << LS
672-
<< formatv(" {{{}, getIntrinsicArgAttributeSet(C, {})}", AttrIdx,
673-
ArgAttrID);
688+
<< formatv(" {{{}, getIntrinsicArgAttributeSet(C, {}, "
689+
"FT->getContainedType({}))}",
690+
AttrIdx, ArgAttrID, AttrIdx);
674691
}
675692

676693
if (hasFnAttributes(Int)) {

0 commit comments

Comments
 (0)