Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -94,6 +94,11 @@ int Align = align; } +class Dereferenceable : IntrinsicProperty { + int ArgNo = idx.Value; + int Bytes = bytes; +} + // Returned - The specified argument is always the return value of the // intrinsic. class Returned : IntrinsicProperty { Index: llvm/test/TableGen/intrinsic-attrs.td =================================================================== --- llvm/test/TableGen/intrinsic-attrs.td +++ llvm/test/TableGen/intrinsic-attrs.td @@ -9,7 +9,16 @@ int isAny = 0; } -def llvm_i32_ty : LLVMType; +def llvm_i32_ty : LLVMType; +def llvm_ptr_ty : LLVMType; + +class AttrIndex { + int Value = idx; +} + +def FuncIndex : AttrIndex<-1>; +def RetIndex : AttrIndex<0>; +class ArgIndex : AttrIndex; class IntrinsicProperty { bit IsDefault = is_default; @@ -17,6 +26,10 @@ def IntrNoMem : IntrinsicProperty; def IntrHasSideEffects : IntrinsicProperty; +class Dereferenceable : IntrinsicProperty { + int ArgNo = idx.Value; + int Bytes = bytes; +} class Intrinsic ret_types, list param_types = [], @@ -40,12 +53,33 @@ // ... this intrinsic. def int_random_gen : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffects]>; +def int_deref_ptr_ret : Intrinsic<[llvm_ptr_ty], [], [Dereferenceable]>; + +// CHECK: static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID) { +// CHECK-NEXT: switch (ID) { +// CHECK-NEXT: default: llvm_unreachable("Invalid attribute set number"); +// CHECK-NEXT: case 0: +// CHECK-NEXT: return AttributeSet::get(C, { +// CHECK-NEXT: Attribute::get(C, Attribute::Dereferenceable, 16), +// CHECK-NEXT: }); +// CHECK-NEXT: } +// CHECK-NEXT: } + // CHECK: static AttributeSet getIntrinsicFnAttributeSet( // CHECK: case 0: // CHECK-NEXT: return AttributeSet::get(C, { // CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), // CHECK-NEXT: }); -// CHECK: 1, // llvm.random.gen + +// CHECK: 1, // llvm.deref.ptr.ret +// CHECK: 2, // llvm.random.gen + // CHECK: case 1: -// CHECK-NEXT: AS[0] = {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, 0)}; +// CHECK-NEXT: AS[0] = {0, getIntrinsicArgAttributeSet(C, 0)}; +// CHECK-NEXT: AS[1] = {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, 0)}; +// CHECK-NEXT: NumAttrs = 2; + +// CHECK: case 2: +// CHECK-NEXT: AS[0] = {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, 1)}; +// CHECK-NEXT: NumAttrs = 1; Index: llvm/utils/TableGen/CodeGenIntrinsics.h =================================================================== --- llvm/utils/TableGen/CodeGenIntrinsics.h +++ llvm/utils/TableGen/CodeGenIntrinsics.h @@ -113,7 +113,8 @@ WriteOnly, ReadNone, ImmArg, - Alignment + Alignment, + Dereferenceable }; struct ArgAttribute { Index: llvm/utils/TableGen/CodeGenIntrinsics.cpp =================================================================== --- llvm/utils/TableGen/CodeGenIntrinsics.cpp +++ llvm/utils/TableGen/CodeGenIntrinsics.cpp @@ -234,6 +234,10 @@ unsigned ArgNo = R->getValueAsInt("ArgNo"); uint64_t Align = R->getValueAsInt("Align"); addArgAttribute(ArgNo, Alignment, Align); + } else if (R->isSubClassOf("Dereferenceable")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + uint64_t Bytes = R->getValueAsInt("Bytes"); + addArgAttribute(ArgNo, Dereferenceable, Bytes); } else llvm_unreachable("Unknown property!"); } Index: llvm/utils/TableGen/IntrinsicEmitter.cpp =================================================================== --- llvm/utils/TableGen/IntrinsicEmitter.cpp +++ llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -474,6 +474,10 @@ OS << " Attribute::get(C, Attribute::Alignment, " << Attr.Value << "),\n"; break; + case CodeGenIntrinsic::Dereferenceable: + OS << " Attribute::get(C, Attribute::Dereferenceable, " + << Attr.Value << "),\n"; + break; } } OS << " });\n";