Index: llvm/include/llvm/IR/Argument.h =================================================================== --- llvm/include/llvm/IR/Argument.h +++ llvm/include/llvm/IR/Argument.h @@ -83,8 +83,8 @@ /// in-memory ABI size copied to the stack for the call. Otherwise, return 0. uint64_t getPassPointeeByValueCopySize(const DataLayout &DL) const; - /// Return true if this argument has the byval, inalloca, preallocated, or - /// byref attribute. These attributes represent arguments being passed by + /// Return true if this argument has the byval, sret, inalloca, preallocated, + /// or byref attribute. These attributes represent arguments being passed by /// value (which may or may not involve a stack copy) bool hasPointeeInMemoryValueAttr() const; @@ -103,6 +103,9 @@ /// If this is a byval argument, return its type. Type *getParamByValType() const; + /// If this is an sret argument, return its type. + Type *getParamStructRetType() const; + /// If this is a byref argument, return its type. Type *getParamByRefType() const; Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -472,6 +472,12 @@ return Ty ? Ty : (arg_begin() + ArgNo)->getType()->getPointerElementType(); } + /// Extract the sret type for a parameter. + Type *getParamStructRetType(unsigned ArgNo) const { + // FIXME: Add type to attribute like byval + return (arg_begin() + ArgNo)->getType()->getPointerElementType(); + } + /// Extract the byref type for a parameter. Type *getParamByRefType(unsigned ArgNo) const { return AttributeSets.getParamByRefType(ArgNo); Index: llvm/lib/Analysis/Lint.cpp =================================================================== --- llvm/lib/Analysis/Lint.cpp +++ llvm/lib/Analysis/Lint.cpp @@ -250,7 +250,7 @@ // Check that an sret argument points to valid memory. if (Formal->hasStructRetAttr() && Actual->getType()->isPointerTy()) { - Type *Ty = cast(Formal->getType())->getElementType(); + Type *Ty = Formal->getParamStructRetType(); visitMemoryReference(I, Actual, DL->getTypeStoreSize(Ty), DL->getABITypeAlign(Ty), Ty, MemRef::Read | MemRef::Write); Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -140,12 +140,13 @@ return false; AttributeList Attrs = getParent()->getAttributes(); return Attrs.hasParamAttribute(getArgNo(), Attribute::ByVal) || + Attrs.hasParamAttribute(getArgNo(), Attribute::StructRet) || Attrs.hasParamAttribute(getArgNo(), Attribute::InAlloca) || Attrs.hasParamAttribute(getArgNo(), Attribute::Preallocated) || Attrs.hasParamAttribute(getArgNo(), Attribute::ByRef); } -/// For a byval, inalloca, or preallocated parameter, get the in-memory +/// For a byval, sret, inalloca, or preallocated parameter, get the in-memory /// parameter type. static Type *getMemoryParamAllocType(AttributeSet ParamAttrs, Type *ArgTy) { // FIXME: All the type carrying attributes are mutually exclusive, so there @@ -157,10 +158,11 @@ if (Type *PreAllocTy = ParamAttrs.getPreallocatedType()) return PreAllocTy; - // FIXME: inalloca always depends on pointee element type. It's also possible - // for byval to miss it. + // FIXME: sret and inalloca always depends on pointee element type. It's also + // possible for byval to miss it. if (ParamAttrs.hasAttribute(Attribute::InAlloca) || ParamAttrs.hasAttribute(Attribute::ByVal) || + ParamAttrs.hasAttribute(Attribute::StructRet) || ParamAttrs.hasAttribute(Attribute::Preallocated)) return cast(ArgTy)->getElementType(); @@ -196,6 +198,11 @@ return getParent()->getParamByValType(getArgNo()); } +Type *Argument::getParamStructRetType() const { + assert(getType()->isPointerTy() && "Only pointers have sret types"); + return getParent()->getParamStructRetType(getArgNo()); +} + Type *Argument::getParamByRefType() const { assert(getType()->isPointerTy() && "Only pointers have byval types"); return getParent()->getParamByRefType(getArgNo()); Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -804,7 +804,7 @@ const MaybeAlign Alignment = A->getParamAlign(); if (!Alignment && A->hasStructRetAttr()) { // An sret parameter has at least the ABI alignment of the return type. - Type *EltTy = cast(A->getType())->getElementType(); + Type *EltTy = A->getParamStructRetType(); if (EltTy->isSized()) return DL.getABITypeAlign(EltTy); } Index: llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp =================================================================== --- llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -813,7 +813,7 @@ if (!A->hasStructRetAttr()) return false; - Type *StructTy = cast(A->getType())->getElementType(); + Type *StructTy = A->getParamStructRetType(); if (!StructTy->isSized()) { // The call may never return and hence the copy-instruction may never // be executed, and therefore it's not safe to say "the destination Index: llvm/test/CodeGen/X86/vectorcall.ll =================================================================== --- llvm/test/CodeGen/X86/vectorcall.ll +++ llvm/test/CodeGen/X86/vectorcall.ll @@ -172,7 +172,8 @@ declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1) define x86_vectorcallcc void @test_mixed_7(%struct.HVA5* noalias sret %agg.result) { -; CHECK-LABEL: test_mixed_7 +; X86-LABEL: test_mixed_7@@4 +; X64-LABEL: test_mixed_7@@8 ; X64: mov{{[ql]}} %rcx, %rax ; CHECK: movaps %xmm{{[0-9]}}, 64(%{{rcx|eax}}) ; CHECK: movaps %xmm{{[0-9]}}, 48(%{{rcx|eax}})