llvm.org GIT mirror llvm / 274105b
Add the allocsize attribute to LLVM. `allocsize` is a function attribute that allows users to request that LLVM treat arbitrary functions as allocation functions. This patch makes LLVM accept the `allocsize` attribute, and makes `@llvm.objectsize` recognize said attribute. The review for this was split into two patches for ease of reviewing: D18974 and D14933. As promised on the revisions, I'm landing both patches as a single commit. Differential Revision: http://reviews.llvm.org/D14933 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@266032 91177308-0d34-0410-b5e6-96231b3b80d8 George Burgess IV 3 years ago
20 changed file(s) with 581 addition(s) and 75 deletion(s). Raw diff Collapse all Expand all
12681268 epilogue, the backend should forcibly align the stack pointer.
12691269 Specify the desired alignment, which must be a power of two, in
12701270 parentheses.
1271 ``allocsize([, ])``
1272 This attribute indicates that the annotated function will always return at
1273 least a given number of bytes (or null). Its arguments are zero-indexed
1274 parameter numbers; if one argument is provided, then it's assumed that at
1275 least ``CallSite.Args[EltSizeParam]`` bytes will be available at the
1276 returned pointer. If two are provided, then it's assumed that
1277 ``CallSite.Args[EltSizeParam] * CallSite.Args[NumEltsParam]`` bytes are
1278 available. The referenced parameters must be integer types. No assumptions
1279 are made about the contents of the returned block of memory.
12711280 ``alwaysinline``
12721281 This attribute indicates that the inliner should attempt to inline
12731282 this function into callers whenever possible, ignoring any active
512512 ATTR_KIND_SWIFT_ERROR = 47,
513513 ATTR_KIND_NO_RECURSE = 48,
514514 ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
515 ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50
515 ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
516 ATTR_KIND_ALLOC_SIZE = 51
516517 };
517518
518519 enum ComdatSelectionKindCodes {
1717
1818 #include "llvm/ADT/ArrayRef.h"
1919 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/Optional.h"
2021 #include "llvm/Support/Compiler.h"
2122 #include "llvm/Support/PointerLikeTypeTraits.h"
2223 #include
9394 uint64_t Bytes);
9495 static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context,
9596 uint64_t Bytes);
97 static Attribute getWithAllocSizeArgs(LLVMContext &Context,
98 unsigned ElemSizeArg,
99 const Optional &NumElemsArg);
96100
97101 //===--------------------------------------------------------------------===//
98102 // Attribute Accessors
145149 /// \brief Returns the number of dereferenceable_or_null bytes from the
146150 /// dereferenceable_or_null attribute.
147151 uint64_t getDereferenceableOrNullBytes() const;
152
153 /// Returns the argument numbers for the allocsize attribute (or pair(0, 0)
154 /// if not known).
155 std::pair> getAllocSizeArgs() const;
148156
149157 /// \brief The Attribute is converted to a string of equivalent mnemonic. This
150158 /// is, presumably, for writing out the mnemonics for the assembly writer.
266274 AttributeSet addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index,
267275 uint64_t Bytes) const;
268276
277 /// Add the allocsize attribute to the attribute set at the given index.
278 /// Because attribute sets are immutable, this returns a new set.
279 AttributeSet addAllocSizeAttr(LLVMContext &C, unsigned Index,
280 unsigned ElemSizeArg,
281 const Optional &NumElemsArg);
282
269283 //===--------------------------------------------------------------------===//
270284 // AttributeSet Accessors
271285 //===--------------------------------------------------------------------===//
317331 /// \brief Get the number of dereferenceable_or_null bytes (or zero if
318332 /// unknown).
319333 uint64_t getDereferenceableOrNullBytes(unsigned Index) const;
334
335 /// Get the allocsize argument numbers (or pair(0, 0) if unknown).
336 std::pair>
337 getAllocSizeArgs(unsigned Index) const;
320338
321339 /// \brief Return the attributes at the index as a string.
322340 std::string getAsString(unsigned Index, bool InAttrGrp = false) const;
399417 uint64_t StackAlignment;
400418 uint64_t DerefBytes;
401419 uint64_t DerefOrNullBytes;
420 uint64_t AllocSizeArgs;
402421
403422 public:
404423 AttrBuilder()
405424 : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
406 DerefOrNullBytes(0) {}
425 DerefOrNullBytes(0), AllocSizeArgs(0) {}
407426 explicit AttrBuilder(uint64_t Val)
408427 : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
409 DerefOrNullBytes(0) {
428 DerefOrNullBytes(0), AllocSizeArgs(0) {
410429 addRawValue(Val);
411430 }
412431 AttrBuilder(const Attribute &A)
413432 : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
414 DerefOrNullBytes(0) {
433 DerefOrNullBytes(0), AllocSizeArgs(0) {
415434 addAttribute(A);
416435 }
417436 AttrBuilder(AttributeSet AS, unsigned Idx);
480499 /// dereferenceable_or_null attribute exists (zero is returned otherwise).
481500 uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; }
482501
502 /// Retrieve the allocsize args, if the allocsize attribute exists. If it
503 /// doesn't exist, pair(0, 0) is returned.
504 std::pair> getAllocSizeArgs() const;
505
483506 /// \brief This turns an int alignment (which must be a power of 2) into the
484507 /// form used internally in Attribute.
485508 AttrBuilder &addAlignmentAttr(unsigned Align);
495518 /// \brief This turns the number of dereferenceable_or_null bytes into the
496519 /// form used internally in Attribute.
497520 AttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes);
521
522 /// This turns one (or two) ints into the form used internally in Attribute.
523 AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg,
524 const Optional &NumElemsArg);
525
526 /// Add an allocsize attribute, using the representation returned by
527 /// Attribute.getIntValue().
528 AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr);
498529
499530 /// \brief Return true if the builder contains no target-independent
500531 /// attributes.
1414 /// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias.
1515 /// 0 means unaligned (different from align(1)).
1616 def Alignment : EnumAttr<"align">;
17
18 /// The result of the function is guaranteed to point to a number of bytes that
19 /// we can determine if we know the value of the function's arguments.
20 def AllocSize : EnumAttr<"allocsize">;
1721
1822 /// inline=always.
1923 def AlwaysInline : EnumAttr<"alwaysinline">;
4141 };
4242
4343 struct AllocFnsTy {
44 LibFunc::Func Func;
4544 AllocType AllocTy;
46 unsigned char NumParams;
45 unsigned NumParams;
4746 // First and Second size parameters (or -1 if unused)
48 signed char FstParam, SndParam;
47 int FstParam, SndParam;
4948 };
5049
5150 // FIXME: certain users need more information. E.g., SimplifyLibCalls needs to
5251 // know which functions are nounwind, noalias, nocapture parameters, etc.
53 static const AllocFnsTy AllocationFnData[] = {
54 {LibFunc::malloc, MallocLike, 1, 0, -1},
55 {LibFunc::valloc, MallocLike, 1, 0, -1},
56 {LibFunc::Znwj, OpNewLike, 1, 0, -1}, // new(unsigned int)
57 {LibFunc::ZnwjRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new(unsigned int, nothrow)
58 {LibFunc::Znwm, OpNewLike, 1, 0, -1}, // new(unsigned long)
59 {LibFunc::ZnwmRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new(unsigned long, nothrow)
60 {LibFunc::Znaj, OpNewLike, 1, 0, -1}, // new[](unsigned int)
61 {LibFunc::ZnajRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new[](unsigned int, nothrow)
62 {LibFunc::Znam, OpNewLike, 1, 0, -1}, // new[](unsigned long)
63 {LibFunc::ZnamRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new[](unsigned long, nothrow)
64 {LibFunc::msvc_new_int, OpNewLike, 1, 0, -1}, // new(unsigned int)
65 {LibFunc::msvc_new_int_nothrow, MallocLike, 2, 0, -1}, // new(unsigned int, nothrow)
66 {LibFunc::msvc_new_longlong, OpNewLike, 1, 0, -1}, // new(unsigned long long)
67 {LibFunc::msvc_new_longlong_nothrow, MallocLike, 2, 0, -1}, // new(unsigned long long, nothrow)
68 {LibFunc::msvc_new_array_int, OpNewLike, 1, 0, -1}, // new[](unsigned int)
69 {LibFunc::msvc_new_array_int_nothrow, MallocLike, 2, 0, -1}, // new[](unsigned int, nothrow)
70 {LibFunc::msvc_new_array_longlong, OpNewLike, 1, 0, -1}, // new[](unsigned long long)
71 {LibFunc::msvc_new_array_longlong_nothrow, MallocLike, 2, 0, -1}, // new[](unsigned long long, nothrow)
72 {LibFunc::calloc, CallocLike, 2, 0, 1},
73 {LibFunc::realloc, ReallocLike, 2, 1, -1},
74 {LibFunc::reallocf, ReallocLike, 2, 1, -1},
75 {LibFunc::strdup, StrDupLike, 1, -1, -1},
76 {LibFunc::strndup, StrDupLike, 2, 1, -1}
52 static const std::pair AllocationFnData[] = {
53 {LibFunc::malloc, {MallocLike, 1, 0, -1}},
54 {LibFunc::valloc, {MallocLike, 1, 0, -1}},
55 {LibFunc::Znwj, {OpNewLike, 1, 0, -1}}, // new(unsigned int)
56 {LibFunc::ZnwjRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new(unsigned int, nothrow)
57 {LibFunc::Znwm, {OpNewLike, 1, 0, -1}}, // new(unsigned long)
58 {LibFunc::ZnwmRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new(unsigned long, nothrow)
59 {LibFunc::Znaj, {OpNewLike, 1, 0, -1}}, // new[](unsigned int)
60 {LibFunc::ZnajRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new[](unsigned int, nothrow)
61 {LibFunc::Znam, {OpNewLike, 1, 0, -1}}, // new[](unsigned long)
62 {LibFunc::ZnamRKSt9nothrow_t, {MallocLike, 2, 0, -1}}, // new[](unsigned long, nothrow)
63 {LibFunc::msvc_new_int, {OpNewLike, 1, 0, -1}}, // new(unsigned int)
64 {LibFunc::msvc_new_int_nothrow, {MallocLike, 2, 0, -1}}, // new(unsigned int, nothrow)
65 {LibFunc::msvc_new_longlong, {OpNewLike, 1, 0, -1}}, // new(unsigned long long)
66 {LibFunc::msvc_new_longlong_nothrow, {MallocLike, 2, 0, -1}}, // new(unsigned long long, nothrow)
67 {LibFunc::msvc_new_array_int, {OpNewLike, 1, 0, -1}}, // new[](unsigned int)
68 {LibFunc::msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned int, nothrow)
69 {LibFunc::msvc_new_array_longlong, {OpNewLike, 1, 0, -1}}, // new[](unsigned long long)
70 {LibFunc::msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned long long, nothrow)
71 {LibFunc::calloc, {CallocLike, 2, 0, 1}},
72 {LibFunc::realloc, {ReallocLike, 2, 1, -1}},
73 {LibFunc::reallocf, {ReallocLike, 2, 1, -1}},
74 {LibFunc::strdup, {StrDupLike, 1, -1, -1}},
75 {LibFunc::strndup, {StrDupLike, 2, 1, -1}}
7776 // TODO: Handle "int posix_memalign(void **, size_t, size_t)"
7877 };
7978
9594 return Callee;
9695 }
9796
98 /// \brief Returns the allocation data for the given value if it is a call to a
99 /// known allocation function, and NULL otherwise.
100 static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy,
101 const TargetLibraryInfo *TLI,
102 bool LookThroughBitCast = false) {
97 /// Returns the allocation data for the given value if it's either a call to a
98 /// known allocation function, or a call to a function with the allocsize
99 /// attribute.
100 static Optional getAllocationData(const Value *V, AllocType AllocTy,
101 const TargetLibraryInfo *TLI,
102 bool LookThroughBitCast = false) {
103103 // Skip intrinsics
104104 if (isa(V))
105 return nullptr;
106
107 Function *Callee = getCalledFunction(V, LookThroughBitCast);
105 return None;
106
107 const Function *Callee = getCalledFunction(V, LookThroughBitCast);
108108 if (!Callee)
109 return nullptr;
109 return None;
110
111 // If it has allocsize, we can skip checking if it's a known function.
112 //
113 // MallocLike is chosen here because allocsize makes no guarantees about the
114 // nullness of the result of the function, nor does it deal with strings, nor
115 // does it require that the memory returned is zeroed out.
116 LLVM_CONSTEXPR auto AllocSizeAllocTy = MallocLike;
117 if ((AllocTy & AllocSizeAllocTy) == AllocSizeAllocTy &&
118 Callee->hasFnAttribute(Attribute::AllocSize)) {
119 Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
120 std::pair> Args = Attr.getAllocSizeArgs();
121
122 AllocFnsTy Result;
123 Result.AllocTy = AllocSizeAllocTy;
124 Result.NumParams = Callee->getNumOperands();
125 Result.FstParam = Args.first;
126 Result.SndParam = Args.second.getValueOr(-1);
127 return Result;
128 }
110129
111130 // Make sure that the function is available.
112131 StringRef FnName = Callee->getName();
113132 LibFunc::Func TLIFn;
114133 if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn))
115 return nullptr;
116
117 const AllocFnsTy *FnData =
134 return None;
135
136 const auto *Iter =
118137 std::find_if(std::begin(AllocationFnData), std::end(AllocationFnData),
119 [TLIFn](const AllocFnsTy &Fn) { return Fn.Func == TLIFn; });
120
121 if (FnData == std::end(AllocationFnData))
122 return nullptr;
123
138 [TLIFn](const std::pair &P) {
139 return P.first == TLIFn;
140 });
141
142 if (Iter == std::end(AllocationFnData))
143 return None;
144
145 const AllocFnsTy *FnData = &Iter->second;
124146 if ((FnData->AllocTy & AllocTy) != FnData->AllocTy)
125 return nullptr;
147 return None;
126148
127149 // Check function prototype.
128150 int FstParam = FnData->FstParam;
137159 (SndParam < 0 ||
138160 FTy->getParamType(SndParam)->isIntegerTy(32) ||
139161 FTy->getParamType(SndParam)->isIntegerTy(64)))
140 return FnData;
141 return nullptr;
162 return *FnData;
163 return None;
142164 }
143165
144166 static bool hasNoAliasAttr(const Value *V, bool LookThroughBitCast) {
152174 /// like).
153175 bool llvm::isAllocationFn(const Value *V, const TargetLibraryInfo *TLI,
154176 bool LookThroughBitCast) {
155 return getAllocationData(V, AnyAlloc, TLI, LookThroughBitCast);
177 return getAllocationData(V, AnyAlloc, TLI, LookThroughBitCast).hasValue();
156178 }
157179
158180 /// \brief Tests if a value is a call or invoke to a function that returns a
169191 /// allocates uninitialized memory (such as malloc).
170192 bool llvm::isMallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
171193 bool LookThroughBitCast) {
172 return getAllocationData(V, MallocLike, TLI, LookThroughBitCast);
194 return getAllocationData(V, MallocLike, TLI, LookThroughBitCast).hasValue();
173195 }
174196
175197 /// \brief Tests if a value is a call or invoke to a library function that
176198 /// allocates zero-filled memory (such as calloc).
177199 bool llvm::isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
178200 bool LookThroughBitCast) {
179 return getAllocationData(V, CallocLike, TLI, LookThroughBitCast);
201 return getAllocationData(V, CallocLike, TLI, LookThroughBitCast).hasValue();
180202 }
181203
182204 /// \brief Tests if a value is a call or invoke to a library function that
183205 /// allocates memory (either malloc, calloc, or strdup like).
184206 bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
185207 bool LookThroughBitCast) {
186 return getAllocationData(V, AllocLike, TLI, LookThroughBitCast);
208 return getAllocationData(V, AllocLike, TLI, LookThroughBitCast).hasValue();
187209 }
188210
189211 /// extractMallocCall - Returns the corresponding CallInst if the instruction
453475 }
454476
455477 SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) {
456 const AllocFnsTy *FnData = getAllocationData(CS.getInstruction(), AnyAlloc,
457 TLI);
478 Optional FnData =
479 getAllocationData(CS.getInstruction(), AnyAlloc, TLI);
458480 if (!FnData)
459481 return unknown();
460482
466488
467489 // strndup limits strlen
468490 if (FnData->FstParam > 0) {
469 ConstantInt *Arg= dyn_cast(CS.getArgument(FnData->FstParam));
491 ConstantInt *Arg =
492 dyn_cast(CS.getArgument(FnData->FstParam));
470493 if (!Arg)
471494 return unknown();
472495
481504 if (!Arg)
482505 return unknown();
483506
484 APInt Size = Arg->getValue().zextOrSelf(IntTyBits);
507 // When we're compiling N-bit code, and the user uses parameters that are
508 // greater than N bits (e.g. uint64_t on a 32-bit build), we can run into
509 // trouble with APInt size issues. This function handles resizing + overflow
510 // checks for us.
511 auto CheckedZextOrTrunc = [&](APInt &I) {
512 // More bits than we can handle. Checking the bit width isn't necessary, but
513 // it's faster than checking active bits, and should give `false` in the
514 // vast majority of cases.
515 if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)
516 return false;
517 if (I.getBitWidth() != IntTyBits)
518 I = I.zextOrTrunc(IntTyBits);
519 return true;
520 };
521
522 APInt Size = Arg->getValue();
523 if (!CheckedZextOrTrunc(Size))
524 return unknown();
525
485526 // size determined by just 1 parameter
486527 if (FnData->SndParam < 0)
487528 return std::make_pair(Size, Zero);
490531 if (!Arg)
491532 return unknown();
492533
493 Size *= Arg->getValue().zextOrSelf(IntTyBits);
494 return std::make_pair(Size, Zero);
534 APInt NumElems = Arg->getValue();
535 if (!CheckedZextOrTrunc(NumElems))
536 return unknown();
537
538 bool Overflow;
539 Size = Size.umul_ov(NumElems, Overflow);
540 return Overflow ? unknown() : std::make_pair(Size, Zero);
495541
496542 // TODO: handle more standard functions (+ wchar cousins):
497543 // - strdup / strndup
669715 }
670716
671717 SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitCallSite(CallSite CS) {
672 const AllocFnsTy *FnData = getAllocationData(CS.getInstruction(), AnyAlloc,
673 TLI);
718 Optional FnData =
719 getAllocationData(CS.getInstruction(), AnyAlloc, TLI);
674720 if (!FnData)
675721 return unknown();
676722
610610 KEYWORD(attributes);
611611
612612 KEYWORD(alwaysinline);
613 KEYWORD(allocsize);
613614 KEYWORD(argmemonly);
614615 KEYWORD(builtin);
615616 KEYWORD(byval);
1313 #include "LLParser.h"
1414 #include "llvm/ADT/SmallPtrSet.h"
1515 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringExtras.h"
1617 #include "llvm/AsmParser/SlotMapping.h"
1718 #include "llvm/IR/AutoUpgrade.h"
1819 #include "llvm/IR/CallingConv.h"
10481049 return true;
10491050 }
10501051 B.addStackAlignmentAttr(Alignment);
1052 continue;
1053 }
1054 case lltok::kw_allocsize: {
1055 unsigned ElemSizeArg;
1056 Optional NumElemsArg;
1057 // inAttrGrp doesn't matter; we only support allocsize(a[, b])
1058 if (parseAllocSizeArguments(ElemSizeArg, NumElemsArg))
1059 return true;
1060 B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
10511061 continue;
10521062 }
10531063 case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break;
17891799 return false;
17901800 }
17911801
1802 bool LLParser::parseAllocSizeArguments(unsigned &BaseSizeArg,
1803 Optional &HowManyArg) {
1804 Lex.Lex();
1805
1806 auto StartParen = Lex.getLoc();
1807 if (!EatIfPresent(lltok::lparen))
1808 return Error(StartParen, "expected '('");
1809
1810 if (ParseUInt32(BaseSizeArg))
1811 return true;
1812
1813 if (EatIfPresent(lltok::comma)) {
1814 auto HowManyAt = Lex.getLoc();
1815 unsigned HowMany;
1816 if (ParseUInt32(HowMany))
1817 return true;
1818 if (HowMany == BaseSizeArg)
1819 return Error(HowManyAt,
1820 "'allocsize' indices can't refer to the same parameter");
1821 HowManyArg = HowMany;
1822 } else
1823 HowManyArg = None;
1824
1825 auto EndParen = Lex.getLoc();
1826 if (!EatIfPresent(lltok::rparen))
1827 return Error(EndParen, "expected ')'");
1828 return false;
1829 }
1830
17921831 /// ParseScopeAndOrdering
17931832 /// if isAtomic: ::= 'singlethread'? AtomicOrdering
17941833 /// else: ::=
1515
1616 #include "LLLexer.h"
1717 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/Optional.h"
1819 #include "llvm/ADT/StringMap.h"
1920 #include "llvm/IR/Attributes.h"
2021 #include "llvm/IR/Instructions.h"
246247 bool ParseOptionalStackAlignment(unsigned &Alignment);
247248 bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma);
248249 bool ParseOptionalCommaInAlloca(bool &IsInAlloca);
249 bool ParseIndexList(SmallVectorImpl &Indices,bool &AteExtraComma);
250 bool parseAllocSizeArguments(unsigned &ElemSizeArg,
251 Optional &HowManyArg);
252 bool ParseIndexList(SmallVectorImpl &Indices,
253 bool &AteExtraComma);
250254 bool ParseIndexList(SmallVectorImpl &Indices) {
251255 bool AteExtraComma;
252256 if (ParseIndexList(Indices, AteExtraComma)) return true;
113113
114114 // Attributes:
115115 kw_attributes,
116 kw_allocsize,
116117 kw_alwaysinline,
117118 kw_argmemonly,
118119 kw_sanitize_address,
12871287 return Attribute::Dereferenceable;
12881288 case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL:
12891289 return Attribute::DereferenceableOrNull;
1290 case bitc::ATTR_KIND_ALLOC_SIZE:
1291 return Attribute::AllocSize;
12901292 case bitc::ATTR_KIND_NO_RED_ZONE:
12911293 return Attribute::NoRedZone;
12921294 case bitc::ATTR_KIND_NO_RETURN:
14111413 B.addDereferenceableAttr(Record[++i]);
14121414 else if (Kind == Attribute::DereferenceableOrNull)
14131415 B.addDereferenceableOrNullAttr(Record[++i]);
1416 else if (Kind == Attribute::AllocSize)
1417 B.addAllocSizeAttrFromRawRepr(Record[++i]);
14141418 } else { // String attribute
14151419 assert((Record[i] == 3 || Record[i] == 4) &&
14161420 "Invalid attribute group entry");
163163 switch (Kind) {
164164 case Attribute::Alignment:
165165 return bitc::ATTR_KIND_ALIGNMENT;
166 case Attribute::AllocSize:
167 return bitc::ATTR_KIND_ALLOC_SIZE;
166168 case Attribute::AlwaysInline:
167169 return bitc::ATTR_KIND_ALWAYS_INLINE;
168170 case Attribute::ArgMemOnly:
1616 #define LLVM_LIB_IR_ATTRIBUTEIMPL_H
1717
1818 #include "llvm/ADT/FoldingSet.h"
19 #include "llvm/ADT/Optional.h"
1920 #include "llvm/IR/Attributes.h"
2021 #include "llvm/Support/DataTypes.h"
2122 #include "llvm/Support/TrailingObjects.h"
119120 : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) {
120121 assert((Kind == Attribute::Alignment || Kind == Attribute::StackAlignment ||
121122 Kind == Attribute::Dereferenceable ||
122 Kind == Attribute::DereferenceableOrNull) &&
123 Kind == Attribute::DereferenceableOrNull ||
124 Kind == Attribute::AllocSize) &&
123125 "Wrong kind for int attribute!");
124126 }
125127
187189 unsigned getStackAlignment() const;
188190 uint64_t getDereferenceableBytes() const;
189191 uint64_t getDereferenceableOrNullBytes() const;
192 std::pair> getAllocSizeArgs() const;
190193 std::string getAsString(bool InAttrGrp) const;
191194
192195 typedef const Attribute *iterator;
3131 // Attribute Construction Methods
3232 //===----------------------------------------------------------------------===//
3333
34 // allocsize has two integer arguments, but because they're both 32 bits, we can
35 // pack them into one 64-bit value, at the cost of making said value
36 // nonsensical.
37 //
38 // In order to do this, we need to reserve one value of the second (optional)
39 // allocsize argument to signify "not present."
40 LLVM_CONSTEXPR static unsigned AllocSizeNumElemsNotPresent =
41 std::numeric_limits::max();
42
43 static uint64_t packAllocSizeArgs(unsigned ElemSizeArg,
44 const Optional &NumElemsArg) {
45 assert((!NumElemsArg.hasValue() ||
46 *NumElemsArg != AllocSizeNumElemsNotPresent) &&
47 "Attempting to pack a reserved value");
48
49 return uint64_t(ElemSizeArg) << 32 |
50 NumElemsArg.getValueOr(AllocSizeNumElemsNotPresent);
51 }
52
53 static std::pair>
54 unpackAllocSizeArgs(uint64_t Num) {
55 unsigned NumElems = Num & std::numeric_limits::max();
56 unsigned ElemSizeArg = Num >> 32;
57
58 Optional NumElemsArg;
59 if (NumElems != AllocSizeNumElemsNotPresent)
60 NumElemsArg = NumElems;
61 return std::make_pair(ElemSizeArg, NumElemsArg);
62 }
63
3464 Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
3565 uint64_t Val) {
3666 LLVMContextImpl *pImpl = Context.pImpl;
100130 return get(Context, DereferenceableOrNull, Bytes);
101131 }
102132
133 Attribute
134 Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
135 const Optional &NumElemsArg) {
136 assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) &&
137 "Invalid allocsize arguments -- given allocsize(0, 0)");
138 return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));
139 }
140
103141 //===----------------------------------------------------------------------===//
104142 // Attribute Accessor Methods
105143 //===----------------------------------------------------------------------===//
177215 "Trying to get dereferenceable bytes from "
178216 "non-dereferenceable attribute!");
179217 return pImpl->getValueAsInt();
218 }
219
220 std::pair> Attribute::getAllocSizeArgs() const {
221 assert(hasAttribute(Attribute::AllocSize) &&
222 "Trying to get allocsize args from non-allocsize attribute");
223 return unpackAllocSizeArgs(pImpl->getValueAsInt());
180224 }
181225
182226 std::string Attribute::getAsString(bool InAttrGrp) const {
311355 if (hasAttribute(Attribute::DereferenceableOrNull))
312356 return AttrWithBytesToString("dereferenceable_or_null");
313357
358 if (hasAttribute(Attribute::AllocSize)) {
359 unsigned ElemSize;
360 Optional NumElems;
361 std::tie(ElemSize, NumElems) = getAllocSizeArgs();
362
363 std::string Result = "allocsize(";
364 Result += utostr(ElemSize);
365 if (NumElems.hasValue()) {
366 Result += ',';
367 Result += utostr(*NumElems);
368 }
369 Result += ')';
370 return Result;
371 }
372
314373 // Convert target-dependent attributes to strings of the form:
315374 //
316375 // "kind"
467526 case Attribute::ArgMemOnly:
468527 llvm_unreachable("argmemonly attribute not supported in raw format");
469528 break;
529 case Attribute::AllocSize:
530 llvm_unreachable("allocsize not supported in raw format");
531 break;
470532 }
471533 llvm_unreachable("Unsupported attribute type");
472534 }
558620 return 0;
559621 }
560622
623 std::pair>
624 AttributeSetNode::getAllocSizeArgs() const {
625 for (iterator I = begin(), E = end(); I != E; ++I)
626 if (I->hasAttribute(Attribute::AllocSize))
627 return I->getAllocSizeArgs();
628 return std::make_pair(0, 0);
629 }
630
561631 std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
562632 std::string Str;
563633 for (iterator I = begin(), E = end(); I != E; ++I) {
593663 Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26;
594664 else if (Kind == Attribute::Dereferenceable)
595665 llvm_unreachable("dereferenceable not supported in bit mask");
666 else if (Kind == Attribute::AllocSize)
667 llvm_unreachable("allocsize not supported in bit mask");
596668 else
597669 Mask |= AttributeImpl::getAttrMask(Kind);
598670 }
708780 Attr = Attribute::getWithDereferenceableOrNullBytes(
709781 C, B.getDereferenceableOrNullBytes());
710782 break;
783 case Attribute::AllocSize: {
784 auto A = B.getAllocSizeArgs();
785 Attr = Attribute::getWithAllocSizeArgs(C, A.first, A.second);
786 break;
787 }
711788 default:
712789 Attr = Attribute::get(C, Kind);
713790 }
9591036 return addAttributes(C, Index, AttributeSet::get(C, Index, B));
9601037 }
9611038
1039 AttributeSet
1040 AttributeSet::addAllocSizeAttr(LLVMContext &C, unsigned Index,
1041 unsigned ElemSizeArg,
1042 const Optional &NumElemsArg) {
1043 llvm::AttrBuilder B;
1044 B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
1045 return addAttributes(C, Index, AttributeSet::get(C, Index, B));
1046 }
1047
9621048 //===----------------------------------------------------------------------===//
9631049 // AttributeSet Accessor Methods
9641050 //===----------------------------------------------------------------------===//
10561142 return ASN ? ASN->getDereferenceableOrNullBytes() : 0;
10571143 }
10581144
1059 std::string AttributeSet::getAsString(unsigned Index,
1060 bool InAttrGrp) const {
1145 std::pair>
1146 AttributeSet::getAllocSizeArgs(unsigned Index) const {
1147 AttributeSetNode *ASN = getAttributes(Index);
1148 return ASN ? ASN->getAllocSizeArgs() : std::make_pair(0, 0);
1149 }
1150
1151 std::string AttributeSet::getAsString(unsigned Index, bool InAttrGrp) const {
10611152 AttributeSetNode *ASN = getAttributes(Index);
10621153 return ASN ? ASN->getAsString(InAttrGrp) : std::string("");
10631154 }
11321223
11331224 AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
11341225 : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
1135 DerefOrNullBytes(0) {
1226 DerefOrNullBytes(0), AllocSizeArgs(0) {
11361227 AttributeSetImpl *pImpl = AS.pImpl;
11371228 if (!pImpl) return;
11381229
11511242 Attrs.reset();
11521243 TargetDepAttrs.clear();
11531244 Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0;
1245 AllocSizeArgs = 0;
11541246 }
11551247
11561248 AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
11571249 assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
11581250 assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment &&
1159 Val != Attribute::Dereferenceable &&
1251 Val != Attribute::Dereferenceable && Val != Attribute::AllocSize &&
11601252 "Adding integer attribute without adding a value!");
11611253 Attrs[Val] = true;
11621254 return *this;
11791271 DerefBytes = Attr.getDereferenceableBytes();
11801272 else if (Kind == Attribute::DereferenceableOrNull)
11811273 DerefOrNullBytes = Attr.getDereferenceableOrNullBytes();
1274 else if (Kind == Attribute::AllocSize)
1275 AllocSizeArgs = Attr.getValueAsInt();
11821276 return *this;
11831277 }
11841278
11991293 DerefBytes = 0;
12001294 else if (Val == Attribute::DereferenceableOrNull)
12011295 DerefOrNullBytes = 0;
1296 else if (Val == Attribute::AllocSize)
1297 AllocSizeArgs = 0;
12021298
12031299 return *this;
12041300 }
12331329 return *this;
12341330 }
12351331
1332 std::pair> AttrBuilder::getAllocSizeArgs() const {
1333 return unpackAllocSizeArgs(AllocSizeArgs);
1334 }
1335
12361336 AttrBuilder &AttrBuilder::addAlignmentAttr(unsigned Align) {
12371337 if (Align == 0) return *this;
12381338
12701370
12711371 Attrs[Attribute::DereferenceableOrNull] = true;
12721372 DerefOrNullBytes = Bytes;
1373 return *this;
1374 }
1375
1376 AttrBuilder &AttrBuilder::addAllocSizeAttr(unsigned ElemSize,
1377 const Optional &NumElems) {
1378 return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));
1379 }
1380
1381 AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) {
1382 // (0, 0) is our "not present" value, so we need to check for it here.
1383 assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)");
1384
1385 Attrs[Attribute::AllocSize] = true;
1386 // Reuse existing machinery to store this as a single 64-bit integer so we can
1387 // save a few bytes over using a pair>.
1388 AllocSizeArgs = RawArgs;
12731389 return *this;
12741390 }
12751391
12871403 if (!DerefOrNullBytes)
12881404 DerefOrNullBytes = B.DerefOrNullBytes;
12891405
1406 if (!AllocSizeArgs)
1407 AllocSizeArgs = B.AllocSizeArgs;
1408
12901409 Attrs |= B.Attrs;
12911410
12921411 for (auto I : B.td_attrs())
13081427
13091428 if (B.DerefOrNullBytes)
13101429 DerefOrNullBytes = 0;
1430
1431 if (B.AllocSizeArgs)
1432 AllocSizeArgs = 0;
13111433
13121434 Attrs &= ~B.Attrs;
13131435
13871509 I = Attribute::AttrKind(I + 1)) {
13881510 if (I == Attribute::Dereferenceable ||
13891511 I == Attribute::DereferenceableOrNull ||
1390 I == Attribute::ArgMemOnly)
1512 I == Attribute::ArgMemOnly ||
1513 I == Attribute::AllocSize)
13911514 continue;
13921515 if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
13931516 Attrs[I] = true;
13121312 I->getKindAsEnum() == Attribute::ArgMemOnly ||
13131313 I->getKindAsEnum() == Attribute::NoRecurse ||
13141314 I->getKindAsEnum() == Attribute::InaccessibleMemOnly ||
1315 I->getKindAsEnum() == Attribute::InaccessibleMemOrArgMemOnly) {
1315 I->getKindAsEnum() == Attribute::InaccessibleMemOrArgMemOnly ||
1316 I->getKindAsEnum() == Attribute::AllocSize) {
13161317 if (!isFunction) {
13171318 CheckFailed("Attribute '" + I->getAsString() +
13181319 "' only applies to functions!", V);
15431544 const GlobalValue *GV = cast(V);
15441545 Assert(GV->hasUnnamedAddr(),
15451546 "Attribute 'jumptable' requires 'unnamed_addr'", V);
1547 }
1548
1549 if (Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::AllocSize)) {
1550 std::pair> Args =
1551 Attrs.getAllocSizeArgs(AttributeSet::FunctionIndex);
1552
1553 auto CheckParam = [&](StringRef Name, unsigned ParamNo) {
1554 if (ParamNo >= FT->getNumParams()) {
1555 CheckFailed("'allocsize' " + Name + " argument is out of bounds", V);
1556 return false;
1557 }
1558
1559 if (!FT->getParamType(ParamNo)->isIntegerTy()) {
1560 CheckFailed("'allocsize' " + Name +
1561 " argument must refer to an integer parameter",
1562 V);
1563 return false;
1564 }
1565
1566 return true;
1567 };
1568
1569 if (!CheckParam("element size", Args.first))
1570 return;
1571
1572 if (Args.second && !CheckParam("number of elements", *Args.second))
1573 return;
15461574 }
15471575 }
15481576
995995 default: break;
996996 case Intrinsic::objectsize: {
997997 uint64_t Size;
998 if (getObjectSize(II->getArgOperand(0), Size, DL, TLI))
999 return replaceInstUsesWith(CI, ConstantInt::get(CI.getType(), Size));
998 if (getObjectSize(II->getArgOperand(0), Size, DL, TLI)) {
999 APInt APSize(II->getType()->getIntegerBitWidth(), Size);
1000 // Equality check to be sure that `Size` can fit in a value of type
1001 // `II->getType()`
1002 if (APSize == Size)
1003 return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), APSize));
1004 }
10001005 return nullptr;
10011006 }
10021007 case Intrinsic::bswap: {
203203 ; CHECK: define void @f34()
204204 {
205205 call void @nobuiltin() nobuiltin
206 ; CHECK: call void @nobuiltin() #30
206 ; CHECK: call void @nobuiltin() #32
207207 ret void;
208208 }
209209
315315 store %swift_error* null, %swift_error** %error_ptr_ref
316316 %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
317317 ret float 1.0
318 }
319
320 ; CHECK: define i8* @f54(i32) #30
321 define i8* @f54(i32) allocsize(0) {
322 ret i8* null
323 }
324
325 ; CHECK: define i8* @f55(i32, i32) #31
326 define i8* @f55(i32, i32) allocsize(0, 1) {
327 ret i8* null
318328 }
319329
320330 ; CHECK: attributes #0 = { noreturn }
347357 ; CHECK: attributes #27 = { norecurse }
348358 ; CHECK: attributes #28 = { inaccessiblememonly }
349359 ; CHECK: attributes #29 = { inaccessiblemem_or_argmemonly }
350 ; CHECK: attributes #30 = { nobuiltin }
360 ; CHECK: attributes #30 = { allocsize(0) }
361 ; CHECK: attributes #31 = { allocsize(0,1) }
362 ; CHECK: attributes #32 = { nobuiltin }
0 ; RUN: opt < %s -instcombine -S | FileCheck %s
1 ;
2 ; The idea is that we want to have sane semantics (e.g. not assertion failures)
3 ; when given an allocsize function that takes a 64-bit argument in the face of
4 ; 32-bit pointers.
5
6 target datalayout="e-p:32:32:32"
7
8 declare i8* @my_malloc(i8*, i64) allocsize(1)
9
10 define void @test_malloc(i8** %p, i32* %r) {
11 %1 = call i8* @my_malloc(i8* null, i64 100)
12 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
13
14 %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %1, i1 false)
15 ; CHECK: store i32 100
16 store i32 %2, i32* %r, align 8
17
18 ; Big number is 5 billion.
19 %3 = call i8* @my_malloc(i8* null, i64 5000000000)
20 store i8* %3, i8** %p, align 8 ; To ensure objectsize isn't killed
21
22 ; CHECK: call i32 @llvm.objectsize
23 %4 = call i32 @llvm.objectsize.i32.p0i8(i8* %3, i1 false)
24 store i32 %4, i32* %r, align 8
25 ret void
26 }
27
28 declare i32 @llvm.objectsize.i32.p0i8(i8*, i1)
0 ; RUN: opt < %s -instcombine -S | FileCheck %s
1 ;
2 ; Test that instcombine folds allocsize function calls properly.
3 ; Dummy arguments are inserted to verify that allocsize is picking the right
4 ; args, and to prove that arbitrary unfoldable values don't interfere with
5 ; allocsize if they're not used by allocsize.
6
7 declare i8* @my_malloc(i8*, i32) allocsize(1)
8 declare i8* @my_calloc(i8*, i8*, i32, i32) allocsize(2, 3)
9
10 ; CHECK-LABEL: define void @test_malloc
11 define void @test_malloc(i8** %p, i64* %r) {
12 %1 = call i8* @my_malloc(i8* null, i32 100)
13 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
14
15 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false)
16 ; CHECK: store i64 100
17 store i64 %2, i64* %r, align 8
18 ret void
19 }
20
21 ; CHECK-LABEL: define void @test_calloc
22 define void @test_calloc(i8** %p, i64* %r) {
23 %1 = call i8* @my_calloc(i8* null, i8* null, i32 100, i32 5)
24 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
25
26 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false)
27 ; CHECK: store i64 500
28 store i64 %2, i64* %r, align 8
29 ret void
30 }
31
32 ; Failure cases with non-constant values...
33 ; CHECK-LABEL: define void @test_malloc_fails
34 define void @test_malloc_fails(i8** %p, i64* %r, i32 %n) {
35 %1 = call i8* @my_malloc(i8* null, i32 %n)
36 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
37
38 ; CHECK: @llvm.objectsize.i64.p0i8
39 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false)
40 store i64 %2, i64* %r, align 8
41 ret void
42 }
43
44 ; CHECK-LABEL: define void @test_calloc_fails
45 define void @test_calloc_fails(i8** %p, i64* %r, i32 %n) {
46 %1 = call i8* @my_calloc(i8* null, i8* null, i32 %n, i32 5)
47 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
48
49 ; CHECK: @llvm.objectsize.i64.p0i8
50 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false)
51 store i64 %2, i64* %r, align 8
52
53
54 %3 = call i8* @my_calloc(i8* null, i8* null, i32 100, i32 %n)
55 store i8* %3, i8** %p, align 8 ; To ensure objectsize isn't killed
56
57 ; CHECK: @llvm.objectsize.i64.p0i8
58 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %3, i1 false)
59 store i64 %4, i64* %r, align 8
60 ret void
61 }
62
63 declare i8* @my_malloc_outofline(i8*, i32) #0
64 declare i8* @my_calloc_outofline(i8*, i8*, i32, i32) #1
65
66 ; Verifying that out of line allocsize is parsed correctly
67 ; CHECK-LABEL: define void @test_outofline
68 define void @test_outofline(i8** %p, i64* %r) {
69 %1 = call i8* @my_malloc_outofline(i8* null, i32 100)
70 store i8* %1, i8** %p, align 8 ; To ensure objectsize isn't killed
71
72 %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %1, i1 false)
73 ; CHECK: store i64 100
74 store i64 %2, i64* %r, align 8
75
76
77 %3 = call i8* @my_calloc_outofline(i8* null, i8* null, i32 100, i32 5)
78 store i8* %3, i8** %p, align 8 ; To ensure objectsize isn't killed
79
80 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %3, i1 false)
81 ; CHECK: store i64 500
82 store i64 %4, i64* %r, align 8
83 ret void
84 }
85
86 declare i8* @my_malloc_i64(i8*, i64) #0
87 declare i8* @my_tiny_calloc(i8*, i8*, i8, i8) #1
88 declare i8* @my_varied_calloc(i8*, i8*, i32, i8) #1
89
90 ; CHECK-LABEL: define void @test_overflow
91 define void @test_overflow(i8** %p, i32* %r) {
92 %r64 = bitcast i32* %r to i64*
93
94 ; (2**31 + 1) * 2 > 2**31. So overflow. Yay.
95 %big_malloc = call i8* @my_calloc(i8* null, i8* null, i32 2147483649, i32 2)
96 store i8* %big_malloc, i8** %p, align 8
97
98 ; CHECK: @llvm.objectsize
99 %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_malloc, i1 false)
100 store i32 %1, i32* %r, align 4
101
102
103 %big_little_malloc = call i8* @my_tiny_calloc(i8* null, i8* null, i8 127, i8 4)
104 store i8* %big_little_malloc, i8** %p, align 8
105
106 ; CHECK: store i32 508
107 %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_little_malloc, i1 false)
108 store i32 %2, i32* %r, align 4
109
110
111 ; malloc(2**33)
112 %big_malloc_i64 = call i8* @my_malloc_i64(i8* null, i64 8589934592)
113 store i8* %big_malloc_i64, i8** %p, align 8
114
115 ; CHECK: @llvm.objectsize
116 %3 = call i32 @llvm.objectsize.i32.p0i8(i8* %big_malloc_i64, i1 false)
117 store i32 %3, i32* %r, align 4
118
119
120 %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %big_malloc_i64, i1 false)
121 ; CHECK: store i64 8589934592
122 store i64 %4, i64* %r64, align 8
123
124
125 ; Just intended to ensure that we properly handle args of different types...
126 %varied_calloc = call i8* @my_varied_calloc(i8* null, i8* null, i32 1000, i8 5)
127 store i8* %varied_calloc, i8** %p, align 8
128
129 ; CHECK: store i32 5000
130 %5 = call i32 @llvm.objectsize.i32.p0i8(i8* %varied_calloc, i1 false)
131 store i32 %5, i32* %r, align 4
132
133 ret void
134 }
135
136 attributes #0 = { allocsize(1) }
137 attributes #1 = { allocsize(2, 3) }
138
139 declare i32 @llvm.objectsize.i32.p0i8(i8*, i1)
140 declare i64 @llvm.objectsize.i64.p0i8(i8*, i1)
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1 ;
2 ; We handle allocsize with identical args in the parser, rather than the
3 ; verifier. So, a seperate test is needed.
4
5 ; CHECK: 'allocsize' indices can't refer to the same parameter
6 declare i8* @a(i32, i32) allocsize(0, 0)
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1
2 ; CHECK: 'allocsize' element size argument is out of bounds
3 declare i8* @a(i32) allocsize(1)
4
5 ; CHECK: 'allocsize' element size argument must refer to an integer parameter
6 declare i8* @b(i32*) allocsize(0)
7
8 ; CHECK: 'allocsize' number of elements argument is out of bounds
9 declare i8* @c(i32) allocsize(0, 1)
10
11 ; CHECK: 'allocsize' number of elements argument must refer to an integer parameter
12 declare i8* @d(i32, i32*) allocsize(0, 1)
13
14 ; CHECK: 'allocsize' number of elements argument is out of bounds
15 declare i8* @e(i32, i32) allocsize(1, 2)