From c191035f421b5dc69873cba8885fee41e984cc5d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 7 Jul 2021 22:29:43 +0200 Subject: [PATCH] [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 --- llvm/include/llvm/AsmParser/LLToken.h | 1 + llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/IR/Attributes.h | 1 + llvm/include/llvm/IR/Attributes.td | 3 +++ llvm/lib/AsmParser/LLLexer.cpp | 1 + llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 ++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 ++ llvm/lib/IR/Attributes.cpp | 7 +++++- llvm/lib/IR/Verifier.cpp | 10 ++++++++ llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + llvm/test/Bitcode/attributes.ll | 7 ++++++ llvm/test/Verifier/elementtype.ll | 28 +++++++++++++++++++++ llvm/test/Verifier/opaque-ptr.ll | 3 +++ 13 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Verifier/elementtype.ll diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index 7aed41e241aa..50cad74d6974 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -190,6 +190,7 @@ enum Kind { kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_elementtype, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, kw_inlinehint, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index da591f4183b0..28870afb2fcb 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -670,6 +670,7 @@ enum AttributeKindCodes { ATTR_KIND_VSCALE_RANGE = 74, ATTR_KIND_SWIFT_ASYNC = 75, ATTR_KIND_NO_SANITIZE_COVERAGE = 76, + ATTR_KIND_ELEMENTTYPE = 77, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h index b375a783974f..96c8054e7fa1 100644 --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -346,6 +346,7 @@ public: Type *getByRefType() const; Type *getPreallocatedType() const; Type *getInAllocaType() const; + Type *getElementType() const; std::pair> getAllocSizeArgs() const; std::pair getVScaleRangeArgs() const; std::string getAsString(bool InAttrGrp = false) const; diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 327953d3718e..99b474161df7 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -86,6 +86,9 @@ def Dereferenceable : IntAttr<"dereferenceable", [ParamAttr, RetAttr]>; def DereferenceableOrNull : IntAttr<"dereferenceable_or_null", [ParamAttr, RetAttr]>; +/// Provide pointer element type to intrinsic. +def ElementType : TypeAttr<"elementtype", [ParamAttr]>; + /// Function may only access memory that is inaccessible from IR. def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly", [FnAttr]>; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 5f68db84367c..b062fb81fc8f 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -643,6 +643,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(elementtype); KEYWORD(inaccessiblememonly); KEYWORD(inaccessiblemem_or_argmemonly); KEYWORD(inlinehint); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index c9c1cef3c879..07db3c05eb4a 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1385,6 +1385,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; + case bitc::ATTR_KIND_ELEMENTTYPE: + return Attribute::ElementType; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index bdb973e8e421..da3158bcdfa4 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -630,6 +630,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_COLD; case Attribute::Hot: return bitc::ATTR_KIND_HOT; + case Attribute::ElementType: + return bitc::ATTR_KIND_ELEMENTTYPE; case Attribute::InaccessibleMemOnly: return bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY; case Attribute::InaccessibleMemOrArgMemOnly: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 368fc87dc801..4ef61c78de61 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -708,6 +708,10 @@ Type *AttributeSet::getInAllocaType() const { return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr; } +Type *AttributeSet::getElementType() const { + return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr; +} + std::pair> AttributeSet::getAllocSizeArgs() const { return SetNode ? SetNode->getAllocSizeArgs() : std::pair>(0, 0); @@ -1909,7 +1913,8 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) { .addInAllocaAttr(Ty) .addByValAttr(Ty) .addStructRetAttr(Ty) - .addByRefAttr(Ty); + .addByRefAttr(Ty) + .addTypeAttr(Attribute::ElementType, Ty); // Some attributes can apply to all "values" but there are no `void` values. if (Ty->isVoidTy()) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 442857ecb680..71e778c8ec7c 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1813,6 +1813,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, Assert(Attrs.getInAllocaType() == PTy->getElementType(), "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) { Assert(!ArgAttrs.hasAttribute(Attribute::ImmArg), "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); @@ -2331,6 +2338,9 @@ void Verifier::visitFunction(const Function &F) { Assert(!Attrs.hasFnAttribute(Attribute::Builtin), "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. // Sometimes varargs is used for perfectly forwarding thunks, so some of these // restrictions can be lifted. diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 3d631651fa7d..9edc52b53550 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -902,6 +902,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::Convergent: case Attribute::Dereferenceable: case Attribute::DereferenceableOrNull: + case Attribute::ElementType: case Attribute::InAlloca: case Attribute::InReg: case Attribute::InaccessibleMemOnly: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index 57bea084ac87..6ba8ce2854d6 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -465,6 +465,13 @@ define void @f78() noprofile 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 #1 = { nounwind } ; CHECK: attributes #2 = { readnone } diff --git a/llvm/test/Verifier/elementtype.ll b/llvm/test/Verifier/elementtype.ll new file mode 100644 index 000000000000..ff957469d700 --- /dev/null +++ b/llvm/test/Verifier/elementtype.ll @@ -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) diff --git a/llvm/test/Verifier/opaque-ptr.ll b/llvm/test/Verifier/opaque-ptr.ll index 4d824ef49f7d..1f29000db569 100644 --- a/llvm/test/Verifier/opaque-ptr.ll +++ b/llvm/test/Verifier/opaque-ptr.ll @@ -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: 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: [[TMP3:%.*]] = call ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype(i32) null, i32 0, i32 0) ; 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 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 ptr @llvm.preserve.array.access.index.p0.p0(ptr elementtype(i32) null, i32 0, i32 0) 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 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 ptr @llvm.preserve.array.access.index.p0.p0(ptr, i32, i32)