diff --git a/include/llvm/Function.h b/include/llvm/Function.h index e2b41fe25da..40b9c46de23 100644 --- a/include/llvm/Function.h +++ b/include/llvm/Function.h @@ -166,6 +166,9 @@ public: /// @brief Determine whether the function has the given attribute. bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// @brief Extract the alignment for a call or parameter (0=unknown). + uint16_t getParamAlignment(uint16_t i) const; + /// @brief Determine if the function cannot return. bool doesNotReturn() const; diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index b6d5de0f525..8321d6ff556 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -941,6 +941,9 @@ public: /// @brief Determine whether the call or the callee has the given attribute. bool paramHasAttr(uint16_t i, unsigned attr) const; + /// @brief Extract the alignment for a call or parameter (0=unknown). + uint16_t getParamAlignment(uint16_t i) const; + /// @brief Determine if the call does not access memory. bool doesNotAccessMemory() const; @@ -1738,6 +1741,9 @@ public: /// @brief Determine whether the call or the callee has the given attribute. bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// @brief Extract the alignment for a call or parameter (0=unknown). + uint16_t getParamAlignment(uint16_t i) const; + /// @brief Determine if the call does not access memory. bool doesNotAccessMemory() const; diff --git a/include/llvm/ParameterAttributes.h b/include/llvm/ParameterAttributes.h index c3a52fbac32..33cc95c95d5 100644 --- a/include/llvm/ParameterAttributes.h +++ b/include/llvm/ParameterAttributes.h @@ -69,6 +69,12 @@ const Attributes MutuallyIncompatible[3] = { /// @brief Which attributes cannot be applied to a type. Attributes typeIncompatible (const Type *Ty); +/// This turns an int alignment (a power of 2, normally) into the +/// form used internally in ParameterAttributes. +ParamAttr::Attributes inline constructAlignmentFromInt(uint32_t i) { + return (i << 16); +} + } // end namespace ParamAttr /// @brief A more friendly way to reference the attributes. @@ -176,6 +182,13 @@ class ParamAttrsList : public FoldingSetNode { bool paramHasAttr(uint16_t i, ParameterAttributes attr) const { return getParamAttrs(i) & attr; } + + /// This extracts the alignment for the \p ith function parameter. + /// @returns 0 if unknown, else the alignment in bytes + /// @brief Extract the Alignment + uint16_t getParamAlignment(uint16_t i) const { + return (getParamAttrs(i) & ParamAttr::Alignment) >> 16; + } /// This returns whether the given attribute is set for at least one /// parameter or for the return value. diff --git a/include/llvm/Support/CallSite.h b/include/llvm/Support/CallSite.h index 401e5588db1..3bd4ef256c5 100644 --- a/include/llvm/Support/CallSite.h +++ b/include/llvm/Support/CallSite.h @@ -68,6 +68,9 @@ public: /// paramHasAttr - whether the call or the callee has the given attribute. bool paramHasAttr(uint16_t i, ParameterAttributes attr) const; + /// @brief Extract the alignment for a call or parameter (0=unknown). + uint16_t getParamAlignment(uint16_t i) const; + /// @brief Determine if the call does not access memory. bool doesNotAccessMemory() const; diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 4515b90b2ba..783c0f82d5c 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -918,9 +918,10 @@ public: bool isSRet; bool isNest; bool isByVal; + uint16_t Alignment; ArgListEntry() : isSExt(false), isZExt(false), isInReg(false), - isSRet(false), isNest(false), isByVal(false) { } + isSRet(false), isNest(false), isByVal(false), Alignment(0) { } }; typedef std::vector ArgListTy; virtual std::pair diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y index b0cdbc7c9bc..137bd58ea71 100644 --- a/lib/AsmParser/llvmAsmParser.y +++ b/lib/AsmParser/llvmAsmParser.y @@ -1234,7 +1234,8 @@ ParamAttr : ZEROEXT { $$ = ParamAttr::ZExt; } | NOALIAS { $$ = ParamAttr::NoAlias; } | BYVAL { $$ = ParamAttr::ByVal; } | NEST { $$ = ParamAttr::Nest; } - | ALIGN EUINT64VAL { $$ = $2 << 16; } + | ALIGN EUINT64VAL { $$ = + ParamAttr::constructAlignmentFromInt($2); } ; OptParamAttrs : /* empty */ { $$ = ParamAttr::None; } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 96dde98be9c..62610dbe228 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -3118,6 +3118,7 @@ void SelectionDAGLowering::LowerCallTo(CallSite CS, SDOperand Callee, Entry.isSRet = CS.paramHasAttr(attrInd, ParamAttr::StructRet); Entry.isNest = CS.paramHasAttr(attrInd, ParamAttr::Nest); Entry.isByVal = CS.paramHasAttr(attrInd, ParamAttr::ByVal); + Entry.Alignment = CS.getParamAlignment(attrInd); Args.push_back(Entry); } @@ -4146,6 +4147,10 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { const Type *ElementTy = Ty->getElementType(); unsigned FrameAlign = Log2_32(getByValTypeAlignment(ElementTy)); unsigned FrameSize = getTargetData()->getABITypeSize(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. + if (F.getParamAlignment(j)) + FrameAlign = Log2_32(F.getParamAlignment(j)); Flags |= (FrameAlign << ISD::ParamFlags::ByValAlignOffs); Flags |= (FrameSize << ISD::ParamFlags::ByValSizeOffs); } @@ -4255,6 +4260,10 @@ TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy, const Type *ElementTy = Ty->getElementType(); unsigned FrameAlign = Log2_32(getByValTypeAlignment(ElementTy)); unsigned FrameSize = getTargetData()->getABITypeSize(ElementTy); + // For ByVal, alignment should come from FE. BE will guess if this + // info is not there but there are cases it cannot get right. + if (Args[i].Alignment) + FrameAlign = Log2_32(Args[i].Alignment); Flags |= (FrameAlign << ISD::ParamFlags::ByValAlignOffs); Flags |= (FrameSize << ISD::ParamFlags::ByValSizeOffs); } diff --git a/lib/VMCore/Function.cpp b/lib/VMCore/Function.cpp index 49d770d5bd3..0cf808c507c 100644 --- a/lib/VMCore/Function.cpp +++ b/lib/VMCore/Function.cpp @@ -143,6 +143,11 @@ bool Function::paramHasAttr(uint16_t i, ParameterAttributes attr) const { return ParamAttrs && ParamAttrs->paramHasAttr(i, attr); } +/// @brief Extract the alignment for a call or parameter (0=unknown). +uint16_t Function::getParamAlignment(uint16_t i) const { + return ParamAttrs ? ParamAttrs->getParamAlignment(i) : 0; +} + /// @brief Determine if the function cannot return. bool Function::doesNotReturn() const { return paramHasAttr(0, ParamAttr::NoReturn); diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 4197f80c922..b3a78b729f5 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -61,6 +61,13 @@ bool CallSite::paramHasAttr(uint16_t i, ParameterAttributes attr) const { else return cast(I)->paramHasAttr(i, attr); } +uint16_t CallSite::getParamAlignment(uint16_t i) const { + if (CallInst *CI = dyn_cast(I)) + return CI->getParamAlignment(i); + else + return cast(I)->getParamAlignment(i); +} + bool CallSite::doesNotAccessMemory() const { if (CallInst *CI = dyn_cast(I)) return CI->doesNotAccessMemory(); @@ -384,6 +391,14 @@ bool CallInst::paramHasAttr(uint16_t i, ParameterAttributes attr) const { return false; } +uint16_t CallInst::getParamAlignment(uint16_t i) const { + if (ParamAttrs && ParamAttrs->getParamAlignment(i)) + return ParamAttrs->getParamAlignment(i); + if (const Function *F = getCalledFunction()) + return F->getParamAlignment(i); + return 0; +} + /// @brief Determine if the call does not access memory. bool CallInst::doesNotAccessMemory() const { return paramHasAttr(0, ParamAttr::ReadNone); @@ -508,6 +523,13 @@ bool InvokeInst::paramHasAttr(uint16_t i, ParameterAttributes attr) const { return false; } +uint16_t InvokeInst::getParamAlignment(uint16_t i) const { + if (ParamAttrs && ParamAttrs->getParamAlignment(i)) + return ParamAttrs->getParamAlignment(i); + if (const Function *F = getCalledFunction()) + return F->getParamAlignment(i); + return 0; +} /// @brief Determine if the call does not access memory. bool InvokeInst::doesNotAccessMemory() const {