Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -4723,7 +4723,7 @@ Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); AttrBuilder B; - B.addByValAttr(NDRangeL.getAddress(*this).getElementType()); + B.addByValAttr(NDRangeL.getAddress(*this).getElementType(), {}); llvm::AttributeList ByValAttrSet = llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B); Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2369,8 +2369,6 @@ if (AI.getInReg()) Attrs.addAttribute(llvm::Attribute::InReg); - if (AI.getIndirectByVal()) - Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); auto *Decl = ParamType->getAsRecordDecl(); if (CodeGenOpts.PassByValueIsNoAlias && Decl && @@ -2398,9 +2396,11 @@ // For now, only add this when we have a byval argument. // TODO: be less lazy about updating test cases. - if (AI.getIndirectByVal()) + if (AI.getIndirectByVal()) { + Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType), {}); // FIXME(chill): fold the following `align` Attrs.addAlignmentAttr(Align.getQuantity()); - + } + // byval disables readnone and readonly. FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly) .removeAttribute(llvm::Attribute::ReadNone); Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -2106,8 +2106,8 @@ auto PtrTy = cast(FD->getParamDecl(0)->getType()); llvm::Type *ByValTy = CGM.getTypes().ConvertType(PtrTy->getPointeeType()); - llvm::Attribute NewAttr = llvm::Attribute::getWithByValType( - Fn->getContext(), ByValTy); + llvm::Attribute NewAttr = llvm::Attribute::getWithByValArgs( + Fn->getContext(), ByValTy, {}); Fn->addParamAttr(0, NewAttr); } Index: llvm/include/llvm/CodeGen/TargetLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLowering.h +++ llvm/include/llvm/CodeGen/TargetLowering.h @@ -287,6 +287,7 @@ bool IsCFGuardTarget : 1; MaybeAlign Alignment = None; Type *ByValType = nullptr; + MaybeAlign ByValAlignment; Type *PreallocatedType = nullptr; ArgListEntry() Index: llvm/include/llvm/IR/Argument.h =================================================================== --- llvm/include/llvm/IR/Argument.h +++ llvm/include/llvm/IR/Argument.h @@ -103,8 +103,8 @@ MaybeAlign getParamAlign() const; /// If this is a byval argument, return its type. - Type *getParamByValType() const; - + std::pair getParamByValArgs() const; + /// If this is an sret argument, return its type. Type *getParamStructRetType() const; Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -95,7 +95,8 @@ static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val = 0); static Attribute get(LLVMContext &Context, StringRef Kind, StringRef Val = StringRef()); - static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty); + static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty, + MaybeAlign A = {}); /// Return a uniquified Attribute object that has the specific /// alignment set. @@ -110,7 +111,8 @@ const Optional &NumElemsArg); static Attribute getWithVScaleRangeArgs(LLVMContext &Context, unsigned MinValue, unsigned MaxValue); - static Attribute getWithByValType(LLVMContext &Context, Type *Ty); + static Attribute getWithByValArgs(LLVMContext &Context, Type *Ty, + MaybeAlign Align); static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty); static Attribute getWithByRefType(LLVMContext &Context, Type *Ty); static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty); @@ -120,7 +122,8 @@ /// changed to \p ReplacementTy. Attribute getWithNewType(LLVMContext &Context, Type *ReplacementTy) { assert(isTypeAttribute() && "this requires a typed attribute"); - return get(Context, getKindAsEnum(), ReplacementTy); + auto TyArgs = getTypedAttrArgs(); + return get(Context, getKindAsEnum(), ReplacementTy, TyArgs.second); } static Attribute::AttrKind getAttrKindFromName(StringRef AttrName); @@ -176,10 +179,12 @@ /// attribute to be a string attribute. StringRef getValueAsString() const; + std::pair getTypedAttrArgs() const; + /// Return the attribute's value as a Type. This requires the attribute to be /// a type attribute. - Type *getValueAsType() const; - + // Type *getValueAsType() const; + /// Returns the alignment field of an attribute as a byte alignment /// value. MaybeAlign getAlignment() const; @@ -322,7 +327,7 @@ MaybeAlign getStackAlignment() const; uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; - Type *getByValType() const; + std::pair getByValArgs() const; Type *getStructRetType() const; Type *getByRefType() const; Type *getPreallocatedType() const; @@ -573,6 +578,7 @@ return addDereferenceableOrNullAttr(C, ArgNo + FirstArgIndex, Bytes); } + // FIXME(chill): How about ByVal attribute /// Add the allocsize attribute to the attribute set at the given index. /// Returns a new list because attribute lists are immutable. LLVM_NODISCARD AttributeList @@ -675,7 +681,7 @@ MaybeAlign getParamAlignment(unsigned ArgNo) const; /// Return the byval type for the specified function parameter. - Type *getParamByValType(unsigned ArgNo) const; + std::pair getParamByValArgs(unsigned ArgNo) const; /// Return the sret type for the specified function parameter. Type *getParamStructRetType(unsigned ArgNo) const; @@ -788,6 +794,7 @@ std::map, SmallString<32>, std::less<>> TargetDepAttrs; MaybeAlign Alignment; MaybeAlign StackAlignment; + MaybeAlign ByValAlignment; uint64_t DerefBytes = 0; uint64_t DerefOrNullBytes = 0; uint64_t AllocSizeArgs = 0; @@ -880,8 +887,10 @@ uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; } /// Retrieve the byval type. - Type *getByValType() const { return ByValType; } - + std::pair getByValArgs() const { + return {ByValType, ByValAlignment}; + } + /// Retrieve the sret type. Type *getStructRetType() const { return StructRetType; } @@ -942,7 +951,7 @@ AttrBuilder &addVScaleRangeAttr(unsigned MinValue, unsigned MaxValue); /// This turns a byval type into the form used internally in Attribute. - AttrBuilder &addByValAttr(Type *Ty); + AttrBuilder &addByValAttr(Type *Ty, MaybeAlign Alignment); /// This turns a sret type into the form used internally in Attribute. AttrBuilder &addStructRetAttr(Type *Ty); Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -484,8 +484,8 @@ } /// Extract the byval type for a parameter. - Type *getParamByValType(unsigned ArgNo) const { - return AttributeSets.getParamByValType(ArgNo); + std::pair getParamByValArgs(unsigned ArgNo) const { + return AttributeSets.getParamByValArgs(ArgNo); } /// Extract the sret type for a parameter. Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -1732,9 +1732,12 @@ } /// Extract the byval type for a call or parameter. - Type *getParamByValType(unsigned ArgNo) const { - Type *Ty = Attrs.getParamByValType(ArgNo); - return Ty ? Ty : getArgOperand(ArgNo)->getType()->getPointerElementType(); + std::pair getParamByValArgs(unsigned ArgNo) const { + auto ByValArgs = Attrs.getParamByValArgs(ArgNo); + if (ByValArgs.first == nullptr) + ByValArgs.first = + getArgOperand(ArgNo)->getType()->getPointerElementType(); + return ByValArgs; } /// Extract the preallocated type for a call or parameter. Index: llvm/lib/Analysis/StackSafetyAnalysis.cpp =================================================================== --- llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -404,7 +404,7 @@ unsigned ArgNo = CB.getArgOperandNo(&UI); if (CB.isByValArgument(ArgNo)) { US.updateRange(getAccessRange( - UI, Ptr, DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); + UI, Ptr, DL.getTypeStoreSize(CB.getParamByValArgs(ArgNo).first))); break; } Index: llvm/lib/AsmParser/LLParser.h =================================================================== --- llvm/lib/AsmParser/LLParser.h +++ llvm/lib/AsmParser/LLParser.h @@ -329,7 +329,8 @@ bool parseFnAttributeValuePairs(AttrBuilder &B, std::vector &FwdRefAttrGrps, bool inAttrGrp, LocTy &BuiltinLoc); - bool parseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName); + bool parseRequiredTypeAttr(Type *&Result, MaybeAlign &Alignment, + lltok::Kind AttrName); bool parsePreallocated(Type *&Result); bool parseInalloca(Type *&Result); bool parseByRef(Type *&Result); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1717,14 +1717,16 @@ } case lltok::kw_byval: { Type *Ty; - if (parseRequiredTypeAttr(Ty, lltok::kw_byval)) + MaybeAlign A; + if (parseRequiredTypeAttr(Ty, A, lltok::kw_byval)) return true; - B.addByValAttr(Ty); + B.addByValAttr(Ty, A); continue; } case lltok::kw_sret: { Type *Ty; - if (parseRequiredTypeAttr(Ty, lltok::kw_sret)) + MaybeAlign A; // FIXME(chill): Ignored + if (parseRequiredTypeAttr(Ty, A, lltok::kw_sret)) return true; B.addStructRetAttr(Ty); continue; @@ -2680,8 +2682,9 @@ } /// parseRequiredTypeAttr -/// ::= attrname() -bool LLParser::parseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName) { +/// ::= attrname( [, align]) +bool LLParser::parseRequiredTypeAttr(Type *&Result, MaybeAlign &Alignment, + lltok::Kind AttrName) { Result = nullptr; if (!EatIfPresent(AttrName)) return true; @@ -2689,6 +2692,17 @@ return error(Lex.getLoc(), "expected '('"); if (parseType(Result)) return true; + if (EatIfPresent(lltok::comma)) { + auto AlignAt = Lex.getLoc(); + unsigned A; + if (parseUInt32(A)) + return true; + if (A <= 1) + return error(AlignAt, "alignment must be > 1"); + Alignment = Align(A); + } else + Alignment = None; + if (!EatIfPresent(lltok::rparen)) return error(Lex.getLoc(), "expected ')'"); return false; @@ -2697,19 +2711,22 @@ /// parsePreallocated /// ::= preallocated() bool LLParser::parsePreallocated(Type *&Result) { - return parseRequiredTypeAttr(Result, lltok::kw_preallocated); + MaybeAlign A; + return parseRequiredTypeAttr(Result, A, lltok::kw_preallocated); } /// parseInalloca /// ::= inalloca() bool LLParser::parseInalloca(Type *&Result) { - return parseRequiredTypeAttr(Result, lltok::kw_inalloca); + MaybeAlign A; + return parseRequiredTypeAttr(Result, A, lltok::kw_inalloca); } /// parseByRef /// ::= byref() bool LLParser::parseByRef(Type *&Result) { - return parseRequiredTypeAttr(Result, lltok::kw_byref); + MaybeAlign A; + return parseRequiredTypeAttr(Result, A, lltok::kw_byref); } /// parseOptionalOperandBundles Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1621,7 +1621,7 @@ // nullptr. We will have to insert the real type when we associate // this AttributeList with a function. if (Kind == Attribute::ByVal) - B.addByValAttr(nullptr); + B.addByValAttr(nullptr, {}); else if (Kind == Attribute::StructRet) B.addStructRetAttr(nullptr); else if (Kind == Attribute::InAlloca) @@ -1666,11 +1666,17 @@ assert((Record[i] == 5 || Record[i] == 6) && "Invalid attribute group entry"); bool HasType = Record[i] == 6; + bool HasAlign = Record[i] == 7; + assert(HasType || !HasAlign); Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::ByVal) { - B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr); + Type *Ty = HasType ? getTypeByID(Record[++i]) : nullptr; + MaybeAlign A; + if (HasAlign) + A =Align(Record[++i]); + B.addByValAttr(Ty, A); } else if (Kind == Attribute::StructRet) { B.addStructRetAttr(HasType ? getTypeByID(Record[++i]) : nullptr); } else if (Kind == Attribute::ByRef) { @@ -3344,7 +3350,7 @@ Attribute NewAttr; switch (Kind) { case Attribute::ByVal: - NewAttr = Attribute::getWithByValType(Context, PtrEltTy); + NewAttr = Attribute::getWithByValArgs(Context, PtrEltTy, {}); // FIXME(chill): get alignment from `align` ? break; case Attribute::StructRet: NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy); @@ -3832,7 +3838,7 @@ Attribute NewAttr; switch (Kind) { case Attribute::ByVal: - NewAttr = Attribute::getWithByValType(Context, PtrEltTy); + NewAttr = Attribute::getWithByValArgs(Context, PtrEltTy, {}); break; case Attribute::StructRet: NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -805,11 +805,17 @@ } } else { assert(Attr.isTypeAttribute()); - Type *Ty = Attr.getValueAsType(); - Record.push_back(Ty ? 6 : 5); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = Attr.getTypedAttrArgs(); + assert(Ty != nullptr || !A.hasValue()); + Record.push_back(5 + (Ty != nullptr) + A.hasValue()); Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum())); - if (Ty) - Record.push_back(VE.getTypeID(Attr.getValueAsType())); + if (Ty) { + Record.push_back(VE.getTypeID(Ty)); + if (A.hasValue()) + Record.push_back(A->value()); + } } } Index: llvm/lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- llvm/lib/Bitcode/Writer/ValueEnumerator.cpp +++ llvm/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -1002,7 +1002,7 @@ for (const auto &I : F.args()) { EnumerateValue(&I); if (I.hasAttribute(Attribute::ByVal)) - EnumerateType(I.getParamByValType()); + EnumerateType(I.getParamByValArgs().first); else if (I.hasAttribute(Attribute::StructRet)) EnumerateType(I.getParamStructRetType()); else if (I.hasAttribute(Attribute::ByRef)) Index: llvm/lib/CodeGen/GlobalISel/CallLowering.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -157,13 +157,18 @@ if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated()) { Type *ElementTy = cast(Arg.Ty)->getElementType(); - auto Ty = Attrs.getAttribute(OpIdx, Attribute::ByVal).getValueAsType(); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = + Attrs.getAttribute(OpIdx, Attribute::ByVal).getTypedAttrArgs(); Flags.setByValSize(DL.getTypeAllocSize(Ty ? Ty : ElementTy)); // For ByVal, alignment should be passed from FE. BE will guess if // this info is not there but there are cases it cannot get right. Align FrameAlign; - if (auto ParamAlign = FuncInfo.getParamAlign(OpIdx - 1)) + if (A.hasValue()) + FrameAlign = *A; + else if (auto ParamAlign = FuncInfo.getParamAlign(OpIdx - 1)) FrameAlign = *ParamAlign; else FrameAlign = Align(getTLI()->getByValTypeAlignment(ElementTy, DL)); Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9951,7 +9951,7 @@ unsigned PartBase = 0; Type *FinalType = Arg.getType(); if (Arg.hasAttribute(Attribute::ByVal)) - FinalType = Arg.getParamByValType(); + std::tie(FinalType, std::ignore) = Arg.getParamByValArgs(); // FIXME(chill): alignment bool NeedsRegBlock = TLI->functionArgumentNeedsConsecutiveRegisters( FinalType, F.getCallingConv(), F.isVarArg()); for (unsigned Value = 0, NumValues = ValueVTs.size(); Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -118,7 +118,7 @@ Alignment = Call->getParamAlign(ArgIdx); ByValType = nullptr; if (IsByVal) - ByValType = Call->getParamByValType(ArgIdx); + std::tie(ByValType, ByValAlignment) = Call->getParamByValArgs(ArgIdx); PreallocatedType = nullptr; if (IsPreallocated) PreallocatedType = Call->getParamPreallocatedType(ArgIdx); Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -4433,9 +4433,15 @@ llvm_unreachable("unexpected type attr"); } - if (Type *Ty = Attr.getValueAsType()) { + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = Attr.getTypedAttrArgs(); + assert(!A.hasValue() || Attr.hasAttribute(Attribute::ByVal)); + if (Ty != nullptr) { Out << '('; TypePrinter.print(Ty, Out); + if (A.hasValue()) + Out << ", " << A->value(); Out << ')'; } } Index: llvm/lib/IR/AttributeImpl.h =================================================================== --- llvm/lib/IR/AttributeImpl.h +++ llvm/lib/IR/AttributeImpl.h @@ -68,7 +68,7 @@ StringRef getKindAsString() const; StringRef getValueAsString() const; - Type *getValueAsType() const; + std::pair getTypedAttrArgs() const; /// Used when sorting the attributes. bool operator<(const AttributeImpl &AI) const; @@ -80,8 +80,12 @@ Profile(ID, getKindAsEnum(), getValueAsInt()); else if (isStringAttribute()) Profile(ID, getKindAsString(), getValueAsString()); - else - Profile(ID, getKindAsEnum(), getValueAsType()); + else { + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = getTypedAttrArgs(); + Profile(ID, getKindAsEnum(), Ty, A); + } } static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, @@ -96,9 +100,10 @@ } static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, - Type *Ty) { + Type *Ty, MaybeAlign A) { ID.AddInteger(Kind); ID.AddPointer(Ty); + ID.AddInteger(A.valueOrOne().value()); } }; @@ -180,12 +185,14 @@ class TypeAttributeImpl : public EnumAttributeImpl { Type *Ty; + MaybeAlign Alignment; public: - TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) - : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} + TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty, MaybeAlign A) + : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty), Alignment(A) {} Type *getTypeValue() const { return Ty; } + MaybeAlign getTypeAlignment() const { return Alignment; } }; class AttributeBitSet { @@ -254,7 +261,7 @@ std::pair> getAllocSizeArgs() const; std::pair getVScaleRangeArgs() const; std::string getAsString(bool InAttrGrp) const; - Type *getByValType() const; + std::pair getByValArgs() const; Type *getStructRetType() const; Type *getByRefType() const; Type *getPreallocatedType() const; Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -137,11 +137,13 @@ } Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, - Type *Ty) { + Type *Ty, MaybeAlign A) { LLVMContextImpl *pImpl = Context.pImpl; FoldingSetNodeID ID; ID.AddInteger(Kind); ID.AddPointer(Ty); + ID.AddInteger(A.getValueOr(Align{}).value()); + void *InsertPoint; AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); @@ -149,7 +151,7 @@ if (!PA) { // If we didn't find any existing attributes of the same shape then create a // new one and insert it. - PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty); + PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty, A); pImpl->AttrsSet.InsertNode(PA, InsertPoint); } @@ -179,8 +181,9 @@ return get(Context, DereferenceableOrNull, Bytes); } -Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { - return get(Context, ByVal, Ty); +Attribute Attribute::getWithByValArgs(LLVMContext &Context, Type *Ty, + MaybeAlign A) { + return get(Context, ByVal, Ty, A); } Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) { @@ -301,11 +304,11 @@ return pImpl->getValueAsString(); } -Type *Attribute::getValueAsType() const { +std::pair Attribute::getTypedAttrArgs() const { if (!pImpl) return {}; assert(isTypeAttribute() && "Invalid attribute type to get the value as a type!"); - return pImpl->getValueAsType(); + return pImpl->getTypedAttrArgs(); } @@ -511,8 +514,15 @@ } Result += '('; - getValueAsType()->print(OS, false, true); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = getTypedAttrArgs(); + Ty->print(OS, false, true); OS.flush(); + if (A.hasValue()) { + Result += ", "; + Result += utostr(A->value()); + } Result += ')'; return Result; } @@ -652,9 +662,10 @@ return static_cast(this)->getStringValue(); } -Type *AttributeImpl::getValueAsType() const { +std::pair AttributeImpl::getTypedAttrArgs() const { assert(isTypeAttribute()); - return static_cast(this)->getTypeValue(); + auto TyAttr = static_cast(this); + return {TyAttr->getTypeValue(), TyAttr->getTypeAlignment()}; } bool AttributeImpl::operator<(const AttributeImpl &AI) const { @@ -805,8 +816,9 @@ return SetNode ? SetNode->getByRefType() : nullptr; } -Type *AttributeSet::getByValType() const { - return SetNode ? SetNode->getByValType() : nullptr; +std::pair AttributeSet::getByValArgs() const { + return SetNode ? SetNode->getByValArgs() + : std::pair(nullptr, {}); } Type *AttributeSet::getStructRetType() const { @@ -915,9 +927,11 @@ Attribute Attr; switch (Kind) { - case Attribute::ByVal: - Attr = Attribute::getWithByValType(C, B.getByValType()); + case Attribute::ByVal: { + auto ByValArgs = B.getByValArgs(); + Attr = Attribute::getWithByValArgs(C, ByValArgs.first, ByValArgs.second); break; + } case Attribute::StructRet: Attr = Attribute::getWithStructRetType(C, B.getStructRetType()); break; @@ -1012,33 +1026,45 @@ return None; } -Type *AttributeSetNode::getByValType() const { +std::pair AttributeSetNode::getByValArgs() const { if (auto A = findEnumAttribute(Attribute::ByVal)) - return A->getValueAsType(); - return nullptr; + return A->getTypedAttrArgs(); + return {}; } Type *AttributeSetNode::getStructRetType() const { - if (auto A = findEnumAttribute(Attribute::StructRet)) - return A->getValueAsType(); + if (auto A = findEnumAttribute(Attribute::StructRet)) { + Type *Ty; + std::tie(Ty, std::ignore) = A->getTypedAttrArgs(); + return Ty; + } return nullptr; } Type *AttributeSetNode::getByRefType() const { - if (auto A = findEnumAttribute(Attribute::ByRef)) - return A->getValueAsType(); + if (auto A = findEnumAttribute(Attribute::ByRef)) { + Type *Ty; + std::tie(Ty, std::ignore) = A->getTypedAttrArgs(); + return Ty; + } return nullptr; } Type *AttributeSetNode::getPreallocatedType() const { - if (auto A = findEnumAttribute(Attribute::Preallocated)) - return A->getValueAsType(); + if (auto A = findEnumAttribute(Attribute::Preallocated)) { + Type *Ty; + std::tie(Ty, std::ignore) = A->getTypedAttrArgs(); + return Ty; + } return nullptr; } Type *AttributeSetNode::getInAllocaType() const { - if (auto A = findEnumAttribute(Attribute::InAlloca)) - return A->getValueAsType(); + if (auto A = findEnumAttribute(Attribute::InAlloca)) { + Type *Ty; + std::tie(Ty, std::ignore) = A->getTypedAttrArgs(); + return Ty; + } return nullptr; } @@ -1583,8 +1609,8 @@ return getAttributes(ArgNo + FirstArgIndex).getAlignment(); } -Type *AttributeList::getParamByValType(unsigned Index) const { - return getAttributes(Index+FirstArgIndex).getByValType(); +std::pair AttributeList::getParamByValArgs(unsigned Index) const { + return getAttributes(Index+FirstArgIndex).getByValArgs(); } Type *AttributeList::getParamStructRetType(unsigned Index) const { @@ -1708,14 +1734,15 @@ Alignment = Attr.getAlignment(); else if (Kind == Attribute::StackAlignment) StackAlignment = Attr.getStackAlignment(); - else if (Kind == Attribute::ByVal) - ByValType = Attr.getValueAsType(); + else if (Kind == Attribute::ByVal) { + std::tie(ByValType, ByValAlignment) = Attr.getTypedAttrArgs(); + } else if (Kind == Attribute::StructRet) - StructRetType = Attr.getValueAsType(); + std::tie(StructRetType, std::ignore) = Attr.getTypedAttrArgs(); else if (Kind == Attribute::ByRef) - ByRefType = Attr.getValueAsType(); + std::tie(ByRefType, std::ignore) = Attr.getTypedAttrArgs(); else if (Kind == Attribute::Preallocated) - PreallocatedType = Attr.getValueAsType(); + std::tie(PreallocatedType, std::ignore) = Attr.getTypedAttrArgs(); else if (Kind == Attribute::Dereferenceable) DerefBytes = Attr.getDereferenceableBytes(); else if (Kind == Attribute::DereferenceableOrNull) @@ -1725,7 +1752,7 @@ else if (Kind == Attribute::VScaleRange) VScaleRangeArgs = Attr.getValueAsInt(); else if (Kind == Attribute::InAlloca) - InAllocaType = Attr.getValueAsType(); + std::tie(InAllocaType, std::ignore) = Attr.getTypedAttrArgs(); return *this; } @@ -1858,9 +1885,10 @@ return *this; } -AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { +AttrBuilder &AttrBuilder::addByValAttr(Type *Ty, MaybeAlign A) { Attrs[Attribute::ByVal] = true; ByValType = Ty; + ByValAlignment = A; return *this; } @@ -2058,7 +2086,7 @@ .addAttribute(Attribute::InAlloca) .addPreallocatedAttr(Ty) .addInAllocaAttr(Ty) - .addByValAttr(Ty) + .addByValAttr(Ty, {}) .addStructRetAttr(Ty) .addByRefAttr(Ty); Index: llvm/lib/IR/AutoUpgrade.cpp =================================================================== --- llvm/lib/IR/AutoUpgrade.cpp +++ llvm/lib/IR/AutoUpgrade.cpp @@ -4362,7 +4362,7 @@ if (F.getCallingConv() == CallingConv::X86_INTR && !F.arg_empty() && !F.hasParamAttribute(0, Attribute::ByVal)) { Type *ByValTy = cast(F.getArg(0)->getType())->getElementType(); - Attribute NewAttr = Attribute::getWithByValType(F.getContext(), ByValTy); + Attribute NewAttr = Attribute::getWithByValArgs(F.getContext(), ByValTy, {}); F.addParamAttr(0, NewAttr); } } Index: llvm/lib/IR/Core.cpp =================================================================== --- llvm/lib/IR/Core.cpp +++ llvm/lib/IR/Core.cpp @@ -142,7 +142,7 @@ if (AttrKind == Attribute::AttrKind::ByVal) { // After r362128, byval attributes need to have a type attribute. Provide a // NULL one until a proper API is added for this. - return wrap(Attribute::getWithByValType(Ctx, NULL)); + return wrap(Attribute::getWithByValArgs(Ctx, NULL, {})); } if (AttrKind == Attribute::AttrKind::StructRet) { @@ -173,7 +173,9 @@ LLVMTypeRef LLVMGetTypeAttributeValue(LLVMAttributeRef A) { auto Attr = unwrap(A); - return wrap(Attr.getValueAsType()); + Type *Ty; + std::tie(Ty, std::ignore) = Attr.getTypedAttrArgs(); + return wrap(Ty); } LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C, Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -156,7 +156,7 @@ static Type *getMemoryParamAllocType(AttributeSet ParamAttrs, Type *ArgTy) { // FIXME: All the type carrying attributes are mutually exclusive, so there // should be a single query to get the stored type that handles any of them. - if (Type *ByValTy = ParamAttrs.getByValType()) + if (Type *ByValTy = ParamAttrs.getByValArgs().first) return ByValTy; if (Type *ByRefTy = ParamAttrs.getByRefType()) return ByRefTy; @@ -200,9 +200,9 @@ return getParent()->getParamAlign(getArgNo()); } -Type *Argument::getParamByValType() const { +std::pair Argument::getParamByValArgs() const { assert(getType()->isPointerTy() && "Only pointers have byval types"); - return getParent()->getParamByValType(getArgNo()); + return getParent()->getParamByValArgs(getArgNo()); } Type *Argument::getParamStructRetType() const { Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -1822,8 +1822,8 @@ "Attribute 'byref' type does not match parameter!", V); } - if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) { - Assert(Attrs.getByValType() == PTy->getElementType(), + if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValArgs().first) { + Assert(Attrs.getByValArgs().first == PTy->getElementType(), "Attribute 'byval' type does not match parameter!", V); } Index: llvm/lib/Linker/IRMover.cpp =================================================================== --- llvm/lib/Linker/IRMover.cpp +++ llvm/lib/Linker/IRMover.cpp @@ -650,7 +650,9 @@ {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef, Attribute::InAlloca}) { if (Attrs.hasAttribute(i, TypedAttr)) { - if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) { + Type *Ty; + std::tie(Ty, std::ignore) = Attrs.getAttribute(i, TypedAttr).getTypedAttrArgs(); + if (Ty != nullptr) { Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMap.get(Ty)); break; } Index: llvm/lib/Transforms/IPO/ArgumentPromotion.cpp =================================================================== --- llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -994,8 +994,9 @@ } // Otherwise, see if we can promote the pointer to its value. - Type *ByValTy = - PtrArg->hasByValAttr() ? PtrArg->getParamByValType() : nullptr; + Type *ByValTy = nullptr; + if (PtrArg->hasByValAttr()) + std::tie(ByValTy, std::ignore) = PtrArg->getParamByValArgs(); if (isSafeToPromoteArgument(PtrArg, ByValTy, AAR, MaxElements)) ArgsToPromote.insert(PtrArg); } Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -2361,7 +2361,7 @@ auto *ArgType = UseCall ->getAttribute(AttributeList::FunctionIndex, Attribute::Preallocated) - .getValueAsType(); + .getTypedAttrArgs().first; auto *InsertBefore = PreallocatedSetup->getNextNonDebugInstruction(); Builder.SetInsertPoint(InsertBefore); auto *Alloca = Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1945,7 +1945,7 @@ Type* SrcTy = cast(CI->getOperand(0)->getType())->getElementType(); Type *DstTy = Call.isByValArgument(ix) - ? Call.getParamByValType(ix) + ? Call.getParamByValArgs(ix).first : cast(CI->getType())->getElementType(); if (!SrcTy->isSized() || !DstTy->isSized()) return false; @@ -2220,9 +2220,10 @@ if (Call.isByValArgument(ix)) { Call.removeParamAttr(ix, Attribute::ByVal); Call.addParamAttr( - ix, Attribute::getWithByValType( - Call.getContext(), - CI->getOperand(0)->getType()->getPointerElementType())); + ix, + Attribute::getWithByValArgs( + Call.getContext(), + CI->getOperand(0)->getType()->getPointerElementType(), {})); } Changed = true; } @@ -2469,7 +2470,7 @@ if (!ParamPTy || !ParamPTy->getElementType()->isSized()) return false; - Type *CurElTy = Call.getParamByValType(i); + Type *CurElTy = Call.getParamByValArgs(i).first; if (DL.getTypeAllocSize(CurElTy) != DL.getTypeAllocSize(ParamPTy->getElementType())) return false; @@ -2536,7 +2537,7 @@ // Add any parameter attributes. if (CallerPAL.hasParamAttribute(i, Attribute::ByVal)) { AttrBuilder AB(CallerPAL.getParamAttributes(i)); - AB.addByValAttr(NewArg->getType()->getPointerElementType()); + AB.addByValAttr(NewArg->getType()->getPointerElementType(), {}); ArgAttrs.push_back(AttributeSet::get(Ctx, AB)); } else ArgAttrs.push_back(CallerPAL.getParamAttributes(i)); Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1442,8 +1442,10 @@ if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) || ignoreAccess(CI->getArgOperand(ArgNo))) continue; - Type *Ty = CI->getParamByValType(ArgNo); - Interesting.emplace_back(I, ArgNo, false, Ty, Align(1)); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = CI->getParamByValArgs(ArgNo); + Interesting.emplace_back(I, ArgNo, false, Ty, A.valueOrOne()); } } } @@ -2993,9 +2995,11 @@ const DataLayout &DL = F.getParent()->getDataLayout(); for (Argument &Arg : F.args()) { if (Arg.hasByValAttr()) { - Type *Ty = Arg.getParamByValType(); - const Align Alignment = - DL.getValueOrABITypeAlignment(Arg.getParamAlign(), Ty); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = Arg.getParamByValArgs(); + const Align Alignment = DL.getValueOrABITypeAlignment( + A.hasValue() ? *A : Arg.getParamAlign(), Ty); AllocaInst *AI = IRB.CreateAlloca( Ty, nullptr, Index: llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -682,8 +682,10 @@ if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) || ignoreAccess(CI->getArgOperand(ArgNo))) continue; - Type *Ty = CI->getParamByValType(ArgNo); - Interesting.emplace_back(I, ArgNo, false, Ty, Align(1)); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = CI->getParamByValArgs(ArgNo); + Interesting.emplace_back(I, ArgNo, false, Ty, A.valueOrOne()); } } } Index: llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -1683,7 +1683,7 @@ bool FArgEagerCheck = ClEagerChecks && !FArgByVal && FArgNoUndef; unsigned Size = FArg.hasByValAttr() - ? DL.getTypeAllocSize(FArg.getParamByValType()) + ? DL.getTypeAllocSize(FArg.getParamByValArgs().first) : DL.getTypeAllocSize(FArg.getType()); if (A == &FArg) { @@ -1697,8 +1697,12 @@ // ByVal pointer itself has clean shadow. We copy the actual // argument shadow to the underlying memory. // Figure out maximal valid memcpy alignment. - const Align ArgAlign = DL.getValueOrABITypeAlignment( - MaybeAlign(FArg.getParamAlignment()), FArg.getParamByValType()); + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = FArg.getParamByValArgs(); + if (!A.hasValue()) + A = FArg.getParamAlign(); + const Align ArgAlign = DL.getValueOrABITypeAlignment(A, Ty); Value *CpShadowPtr = getShadowOriginPtr(V, EntryIRB, EntryIRB.getInt8Ty(), ArgAlign, /*isStore*/ true) @@ -3677,9 +3681,13 @@ // load assert(A->getType()->isPointerTy() && "ByVal argument is not a pointer!"); - Size = DL.getTypeAllocSize(CB.getParamByValType(i)); + Type *ByValTy; + MaybeAlign ByValAlign; + std::tie(ByValTy, ByValAlign) = CB.getParamByValArgs(i); + Size = DL.getTypeAllocSize(ByValTy); if (ArgOffset + Size > kParamTLSSize) break; - const MaybeAlign ParamAlignment(CB.getParamAlign(i)); + const MaybeAlign ParamAlignment( + ByValAlign.hasValue() ? ByValAlign : CB.getParamAlign(i)); MaybeAlign Alignment = llvm::None; if (ParamAlignment) Alignment = std::min(*ParamAlignment, kShadowTLSAlignment); @@ -4198,7 +4206,7 @@ if (IsFixed) continue; assert(A->getType()->isPointerTy()); - Type *RealTy = CB.getParamByValType(ArgNo); + Type *RealTy = CB.getParamByValArgs(ArgNo).first; uint64_t ArgSize = DL.getTypeAllocSize(RealTy); Value *ShadowBase = getShadowPtrForVAArgument( RealTy, IRB, OverflowOffset, alignTo(ArgSize, 8)); @@ -4814,9 +4822,12 @@ bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal); if (IsByVal) { assert(A->getType()->isPointerTy()); - Type *RealTy = CB.getParamByValType(ArgNo); + Type *RealTy; + MaybeAlign RealAlign; + std::tie(RealTy, RealAlign) = CB.getParamByValArgs(ArgNo); uint64_t ArgSize = DL.getTypeAllocSize(RealTy); - MaybeAlign ArgAlign = CB.getParamAlign(ArgNo); + MaybeAlign ArgAlign = + RealAlign.hasValue() ? *RealAlign : CB.getParamAlign(ArgNo); if (!ArgAlign || *ArgAlign < Align(8)) ArgAlign = Align(8); VAArgOffset = alignTo(VAArgOffset, ArgAlign); Index: llvm/lib/Transforms/Utils/CallPromotionUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/CallPromotionUtils.cpp +++ llvm/lib/Transforms/Utils/CallPromotionUtils.cpp @@ -18,6 +18,8 @@ #include "llvm/IR/Instructions.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include + using namespace llvm; #define DEBUG_TYPE "call-promotion-utils" @@ -490,10 +492,14 @@ // If byval is used, this must be a pointer type, and the byval type must // match the element type. Update it if present. - if (ArgAttrs.getByValType()) { - Type *NewTy = Callee->getParamByValType(ArgNo); + Type *OldTy; + std::tie(OldTy, std::ignore) = ArgAttrs.getByValArgs(); + if (OldTy) { + Type *NewTy; + MaybeAlign ByValAlign; + std::tie(NewTy, ByValAlign) = Callee->getParamByValArgs(ArgNo); ArgAttrs.addByValAttr( - NewTy ? NewTy : cast(FormalTy)->getElementType()); + NewTy ? NewTy : cast(FormalTy)->getElementType(), ByValAlign); } NewArgAttrs.push_back(AttributeSet::get(Ctx, ArgAttrs)); Index: llvm/lib/Transforms/Utils/FunctionComparator.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -122,11 +122,16 @@ if (LA.getKindAsEnum() != RA.getKindAsEnum()) return cmpNumbers(LA.getKindAsEnum(), RA.getKindAsEnum()); - Type *TyL = LA.getValueAsType(); - Type *TyR = RA.getValueAsType(); + Type *TyL, *TyR; + MaybeAlign AlignL, AlignR; + std::tie(TyL, AlignL) = LA.getTypedAttrArgs(); + std::tie(TyR, AlignR) = RA.getTypedAttrArgs(); if (TyL && TyR) { if (int Res = cmpTypes(TyL, TyR)) return Res; + if (int Res = cmpNumbers(AlignL.valueOrOne().value(), + AlignR.valueOrOne().value())) + return Res; continue; } @@ -134,6 +139,9 @@ // independent of the value of a real pointer. if (int Res = cmpNumbers((uint64_t)TyL, (uint64_t)TyR)) return Res; + if (int Res = cmpNumbers(AlignL.valueOrOne().value(), + AlignR.valueOrOne().value())) + return Res; continue; } if (LA < RA) Index: llvm/lib/Transforms/Utils/ValueMapper.cpp =================================================================== --- llvm/lib/Transforms/Utils/ValueMapper.cpp +++ llvm/lib/Transforms/Utils/ValueMapper.cpp @@ -947,7 +947,10 @@ for (Attribute::AttrKind TypedAttr : {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef, Attribute::InAlloca}) { - if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) { + Type *Ty; + MaybeAlign A; + std::tie(Ty, A) = Attrs.getAttribute(i, TypedAttr).getTypedAttrArgs(); + if (Ty != nullptr) { Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMapper->remapType(Ty)); break; Index: llvm/unittests/IR/AttributesTest.cpp =================================================================== --- llvm/unittests/IR/AttributesTest.cpp +++ llvm/unittests/IR/AttributesTest.cpp @@ -177,11 +177,19 @@ StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct"); // Insufficiently careful printing can result in byval(%mystruct = { i32 }) - Attribute A = Attribute::getWithByValType(C, Ty); + Attribute A = Attribute::getWithByValArgs(C, Ty, {}); EXPECT_EQ(A.getAsString(), "byval(%mystruct)"); - A = Attribute::getWithByValType(C, Type::getInt32Ty(C)); + A = Attribute::getWithByValArgs(C, Type::getInt32Ty(C), {}); EXPECT_EQ(A.getAsString(), "byval(i32)"); } +TEST(Attributes, ByValAlignment) { + LLVMContext C; + StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct"); + + Attribute A = Attribute::getWithByValArgs(C, Ty, Align(4)); + EXPECT_EQ(A.getAsString(), "byval(%mystruct, 4)"); +} + } // end anonymous namespace