diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -177,6 +177,7 @@ // Attributes: kw_attributes, + kw_allocalign, kw_allocsize, kw_alwaysinline, kw_argmemonly, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -677,6 +677,7 @@ ATTR_KIND_NO_SANITIZE_COVERAGE = 76, ATTR_KIND_ELEMENTTYPE = 77, ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION = 78, + ATTR_KIND_ALLOC_ALIGN = 79, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -1183,6 +1183,9 @@ /// This turns an inalloca type into the form used internally in Attribute. AttrBuilder &addInAllocaAttr(Type *Ty); + /// Add an allocalign attribute. + AttrBuilder &addAllocAlignAttr(uint64_t Bytes); + /// Add an allocsize attribute, using the representation returned by /// Attribute.getIntValue(). AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr); diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -47,6 +47,10 @@ /// 0 means unaligned (different from align(1)). def Alignment : IntAttr<"align", [ParamAttr, RetAttr]>; +/// Parameter of a function that tells us the alignment of an allocation, as in +/// aligned_alloc and aligned ::operator::new. +def AllocAlign: IntAttr<"allocalign", [FnAttr]>; + /// The result of the function is guaranteed to point to a number of bytes that /// we can determine if we know the value of the function's arguments. def AllocSize : IntAttr<"allocsize", [FnAttr]>; diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -224,6 +224,7 @@ getAllocationData(const Value *V, AllocType AllocTy, function_ref GetTLI) { bool IsNoBuiltinCall; + // TODO(augie): I think this is where I sniff for the attribute on the call if (const Function *Callee = getCalledFunction(V, IsNoBuiltinCall)) if (!IsNoBuiltinCall) return getAllocationDataForFunction( @@ -332,13 +333,22 @@ Value *llvm::getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI) { + int AlignParam; assert(isAllocationFn(V, TLI)); + + const CallBase *CB = cast(V); + if (CB->hasFnAttr(Attribute::AllocAlign)) { + Attribute A = CB->getFnAttr(Attribute::AllocAlign); + AlignParam = A.getValueAsInt() - 1; + } else { const Optional FnData = getAllocationData(V, AnyAlloc, TLI); if (!FnData.hasValue() || FnData->AlignParam < 0) { return nullptr; } - return V->getOperand(FnData->AlignParam); + AlignParam = FnData->AlignParam; + } + return V->getOperand(AlignParam); } /// When we're compiling N-bit code, and the user uses parameters that are diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1437,6 +1437,8 @@ return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; + case bitc::ATTR_KIND_ALLOC_ALIGN: + return Attribute::AllocAlign; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: @@ -1625,6 +1627,8 @@ B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); + else if (Kind == Attribute::AllocAlign) + B.addAllocAlignAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); else if (Kind == Attribute::VScaleRange) diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -610,6 +610,8 @@ switch (Kind) { case Attribute::Alignment: return bitc::ATTR_KIND_ALIGNMENT; + case Attribute::AllocAlign: + return bitc::ATTR_KIND_ALLOC_ALIGN; case Attribute::AllocSize: return bitc::ATTR_KIND_ALLOC_SIZE; case Attribute::AlwaysInline: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -420,6 +420,13 @@ if (hasAttribute(Attribute::DereferenceableOrNull)) return AttrWithBytesToString("dereferenceable_or_null"); + + if (hasAttribute(Attribute::AllocAlign)) { + std::string Pretty = "allocalign("; + Pretty += utostr(getValueAsInt()); + Pretty += ")"; + return Pretty; + } if (hasAttribute(Attribute::AllocSize)) { unsigned ElemSize; @@ -1647,6 +1654,11 @@ return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes); } +AttrBuilder &AttrBuilder::addAllocAlignAttr(uint64_t Bytes) { + assert(Bytes != 0 && "allocalign(0) is invalid"); + return addRawIntAttr(Attribute::AllocAlign, Bytes); +} + AttrBuilder &AttrBuilder::addAllocSizeAttr(unsigned ElemSize, const Optional &NumElems) { return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems)); diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -887,6 +887,7 @@ switch (Attr.getKindAsEnum()) { // Those attributes cannot be propagated safely. Explicitly list them // here so we get a warning if new attributes are added. + case Attribute::AllocAlign: case Attribute::AllocSize: case Attribute::ArgMemOnly: case Attribute::Builtin: