1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[IR] Add elementtype attribute

This implements the elementtype attribute specified in D105407. It
just adds the attribute and the specified verifier rules, but
doesn't yet make use of it anywhere.

Differential Revision: https://reviews.llvm.org/D106008
This commit is contained in:
Nikita Popov 2021-07-07 22:29:43 +02:00
parent 159ef87203
commit d58a8fbeab
13 changed files with 66 additions and 1 deletions

View File

@ -190,6 +190,7 @@ enum Kind {
kw_convergent, kw_convergent,
kw_dereferenceable, kw_dereferenceable,
kw_dereferenceable_or_null, kw_dereferenceable_or_null,
kw_elementtype,
kw_inaccessiblememonly, kw_inaccessiblememonly,
kw_inaccessiblemem_or_argmemonly, kw_inaccessiblemem_or_argmemonly,
kw_inlinehint, kw_inlinehint,

View File

@ -670,6 +670,7 @@ enum AttributeKindCodes {
ATTR_KIND_VSCALE_RANGE = 74, ATTR_KIND_VSCALE_RANGE = 74,
ATTR_KIND_SWIFT_ASYNC = 75, ATTR_KIND_SWIFT_ASYNC = 75,
ATTR_KIND_NO_SANITIZE_COVERAGE = 76, ATTR_KIND_NO_SANITIZE_COVERAGE = 76,
ATTR_KIND_ELEMENTTYPE = 77,
}; };
enum ComdatSelectionKindCodes { enum ComdatSelectionKindCodes {

View File

@ -346,6 +346,7 @@ public:
Type *getByRefType() const; Type *getByRefType() const;
Type *getPreallocatedType() const; Type *getPreallocatedType() const;
Type *getInAllocaType() const; Type *getInAllocaType() const;
Type *getElementType() const;
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
std::pair<unsigned, unsigned> getVScaleRangeArgs() const; std::pair<unsigned, unsigned> getVScaleRangeArgs() const;
std::string getAsString(bool InAttrGrp = false) const; std::string getAsString(bool InAttrGrp = false) const;

View File

@ -86,6 +86,9 @@ def Dereferenceable : IntAttr<"dereferenceable", [ParamAttr, RetAttr]>;
def DereferenceableOrNull : IntAttr<"dereferenceable_or_null", def DereferenceableOrNull : IntAttr<"dereferenceable_or_null",
[ParamAttr, RetAttr]>; [ParamAttr, RetAttr]>;
/// Provide pointer element type to intrinsic.
def ElementType : TypeAttr<"elementtype", [ParamAttr]>;
/// Function may only access memory that is inaccessible from IR. /// Function may only access memory that is inaccessible from IR.
def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly", [FnAttr]>; def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly", [FnAttr]>;

View File

@ -643,6 +643,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(convergent); KEYWORD(convergent);
KEYWORD(dereferenceable); KEYWORD(dereferenceable);
KEYWORD(dereferenceable_or_null); KEYWORD(dereferenceable_or_null);
KEYWORD(elementtype);
KEYWORD(inaccessiblememonly); KEYWORD(inaccessiblememonly);
KEYWORD(inaccessiblemem_or_argmemonly); KEYWORD(inaccessiblemem_or_argmemonly);
KEYWORD(inlinehint); KEYWORD(inlinehint);

View File

@ -1385,6 +1385,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::Cold; return Attribute::Cold;
case bitc::ATTR_KIND_CONVERGENT: case bitc::ATTR_KIND_CONVERGENT:
return Attribute::Convergent; return Attribute::Convergent;
case bitc::ATTR_KIND_ELEMENTTYPE:
return Attribute::ElementType;
case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY:
return Attribute::InaccessibleMemOnly; return Attribute::InaccessibleMemOnly;
case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY:

View File

@ -630,6 +630,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_COLD; return bitc::ATTR_KIND_COLD;
case Attribute::Hot: case Attribute::Hot:
return bitc::ATTR_KIND_HOT; return bitc::ATTR_KIND_HOT;
case Attribute::ElementType:
return bitc::ATTR_KIND_ELEMENTTYPE;
case Attribute::InaccessibleMemOnly: case Attribute::InaccessibleMemOnly:
return bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY; return bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY;
case Attribute::InaccessibleMemOrArgMemOnly: case Attribute::InaccessibleMemOrArgMemOnly:

View File

@ -708,6 +708,10 @@ Type *AttributeSet::getInAllocaType() const {
return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr; return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr;
} }
Type *AttributeSet::getElementType() const {
return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr;
}
std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs() const { std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs() const {
return SetNode ? SetNode->getAllocSizeArgs() return SetNode ? SetNode->getAllocSizeArgs()
: std::pair<unsigned, Optional<unsigned>>(0, 0); : std::pair<unsigned, Optional<unsigned>>(0, 0);
@ -1909,7 +1913,8 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
.addInAllocaAttr(Ty) .addInAllocaAttr(Ty)
.addByValAttr(Ty) .addByValAttr(Ty)
.addStructRetAttr(Ty) .addStructRetAttr(Ty)
.addByRefAttr(Ty); .addByRefAttr(Ty)
.addTypeAttr(Attribute::ElementType, Ty);
// Some attributes can apply to all "values" but there are no `void` values. // Some attributes can apply to all "values" but there are no `void` values.
if (Ty->isVoidTy()) if (Ty->isVoidTy())

View File

@ -1813,6 +1813,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
Assert(Attrs.getInAllocaType() == PTy->getElementType(), Assert(Attrs.getInAllocaType() == PTy->getElementType(),
"Attribute 'inalloca' type does not match parameter!", V); "Attribute 'inalloca' type does not match parameter!", V);
} }
if (Attrs.hasAttribute(Attribute::ElementType)) {
Assert(Attrs.getElementType() == PTy->getElementType(),
"Attribute 'elementtype' type does not match parameter!", V);
}
} }
} }
} }
@ -1874,6 +1879,8 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
if (!IsIntrinsic) { if (!IsIntrinsic) {
Assert(!ArgAttrs.hasAttribute(Attribute::ImmArg), Assert(!ArgAttrs.hasAttribute(Attribute::ImmArg),
"immarg attribute only applies to intrinsics",V); "immarg attribute only applies to intrinsics",V);
Assert(!ArgAttrs.hasAttribute(Attribute::ElementType),
"Attribute 'elementtype' can only be applied to intrinsics.", V);
} }
verifyParameterAttrs(ArgAttrs, Ty, V); verifyParameterAttrs(ArgAttrs, Ty, V);
@ -2331,6 +2338,9 @@ void Verifier::visitFunction(const Function &F) {
Assert(!Attrs.hasFnAttribute(Attribute::Builtin), Assert(!Attrs.hasFnAttribute(Attribute::Builtin),
"Attribute 'builtin' can only be applied to a callsite.", &F); "Attribute 'builtin' can only be applied to a callsite.", &F);
Assert(!Attrs.hasAttrSomewhere(Attribute::ElementType),
"Attribute 'elementtype' can only be applied to a callsite.", &F);
// Check that this function meets the restrictions on this calling convention. // Check that this function meets the restrictions on this calling convention.
// Sometimes varargs is used for perfectly forwarding thunks, so some of these // Sometimes varargs is used for perfectly forwarding thunks, so some of these
// restrictions can be lifted. // restrictions can be lifted.

View File

@ -902,6 +902,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::Convergent: case Attribute::Convergent:
case Attribute::Dereferenceable: case Attribute::Dereferenceable:
case Attribute::DereferenceableOrNull: case Attribute::DereferenceableOrNull:
case Attribute::ElementType:
case Attribute::InAlloca: case Attribute::InAlloca:
case Attribute::InReg: case Attribute::InReg:
case Attribute::InaccessibleMemOnly: case Attribute::InaccessibleMemOnly:

View File

@ -465,6 +465,13 @@ define void @f78() noprofile
ret void; ret void;
} }
declare void @llvm.some.intrinsic(i32*)
define void @f79() {
; CHECK: call void @llvm.some.intrinsic(i32* elementtype(i32) null)
call void @llvm.some.intrinsic(i32* elementtype(i32) null)
ret void
}
; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone } ; CHECK: attributes #2 = { readnone }

View File

@ -0,0 +1,28 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
declare void @some_function(i32*)
; CHECK: Attribute 'elementtype(i32)' applied to incompatible type!
define void @type_mismatch1() {
call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* null, i32 elementtype(i32) 0, i32 0)
ret void
}
; CHECK: Attribute 'elementtype' type does not match parameter!
define void @type_mismatch2() {
call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* elementtype(i64) null, i32 0, i32 0)
ret void
}
; CHECK: Attribute 'elementtype' can only be applied to intrinsics.
define void @not_intrinsic() {
call void @some_function(i32* elementtype(i32) null)
ret void
}
; CHECK: Attribute 'elementtype' can only be applied to a callsite.
define void @llvm.not_call(i32* elementtype(i32)) {
ret void
}
declare i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32*, i32, i32)

View File

@ -53,11 +53,13 @@ define void @intrinsic_calls(ptr %a) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.masked.load.v2i32.p0(ptr [[A:%.*]], i32 4, <2 x i1> zeroinitializer, <2 x i32> zeroinitializer) ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.masked.load.v2i32.p0(ptr [[A:%.*]], i32 4, <2 x i1> zeroinitializer, <2 x i32> zeroinitializer)
; CHECK-NEXT: call void @llvm.masked.store.v2i32.p0(<2 x i32> zeroinitializer, ptr [[A]], i32 4, <2 x i1> zeroinitializer) ; CHECK-NEXT: call void @llvm.masked.store.v2i32.p0(<2 x i32> zeroinitializer, ptr [[A]], i32 4, <2 x i1> zeroinitializer)
; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr> zeroinitializer, i32 4, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) ; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr> zeroinitializer, i32 4, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer)
; CHECK-NEXT: [[TMP3:%.*]] = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype(i32) null, i32 0, i32 0)
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;
call <2 x i32> @llvm.masked.load.v2i32.p0(ptr %a, i32 4, <2 x i1> zeroinitializer, <2 x i32> zeroinitializer) call <2 x i32> @llvm.masked.load.v2i32.p0(ptr %a, i32 4, <2 x i1> zeroinitializer, <2 x i32> zeroinitializer)
call void @llvm.masked.store.v2i32.p0(<2 x i32> zeroinitializer, ptr %a, i32 4, <2 x i1> zeroinitializer) call void @llvm.masked.store.v2i32.p0(<2 x i32> zeroinitializer, ptr %a, i32 4, <2 x i1> zeroinitializer)
call <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr> zeroinitializer, i32 4, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) call <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr> zeroinitializer, i32 4, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer)
call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype(i32) null, i32 0, i32 0)
ret void ret void
} }
@ -69,3 +71,4 @@ declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
declare <2 x i32> @llvm.masked.load.v2i32.p0(ptr, i32, <2 x i1>, <2 x i32>) declare <2 x i32> @llvm.masked.load.v2i32.p0(ptr, i32, <2 x i1>, <2 x i32>)
declare void @llvm.masked.store.v2i32.p0(<2 x i32>, ptr, i32, <2 x i1>) declare void @llvm.masked.store.v2i32.p0(<2 x i32>, ptr, i32, <2 x i1>)
declare <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr>, i32, <2 x i1>, <2 x i64>) declare <2 x i64> @llvm.masked.gather.v2i64.v2p0(<2 x ptr>, i32, <2 x i1>, <2 x i64>)
declare ptr @llvm.preserve.array.access.index.p0.p0(ptr, i32, i32)