diff options
author | Chris Lattner <sabre@nondot.org> | 2010-06-27 06:26:04 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-06-27 06:26:04 +0000 |
commit | 6d11cdbde41aa847369db85369b2ce5f82515b06 (patch) | |
tree | dd91de006d63ba02d315f6a53bd45ddcb456a74c /lib/CodeGen/CGCall.cpp | |
parent | e7bb777caf478ac8b096bd6a0c14d78ea8b2f5be (diff) |
If coercing something from int or pointer type to int or pointer type
(potentially after unwrapping it from a struct) do it without going through
memory. We now compile:
struct DeclGroup {
unsigned NumDecls;
};
int foo(DeclGroup D) {
return D.NumDecls;
}
into:
%struct.DeclGroup = type { i32 }
define i32 @_Z3foo9DeclGroup(i64) nounwind ssp noredzone {
entry:
%D = alloca %struct.DeclGroup, align 4 ; <%struct.DeclGroup*> [#uses=2]
%coerce.dive = getelementptr %struct.DeclGroup* %D, i32 0, i32 0 ; <i32*> [#uses=1]
%coerce.val.ii = trunc i64 %0 to i32 ; <i32> [#uses=1]
store i32 %coerce.val.ii, i32* %coerce.dive
%tmp = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i32*> [#uses=1]
%tmp1 = load i32* %tmp ; <i32> [#uses=1]
ret i32 %tmp1
}
instead of:
%struct.DeclGroup = type { i32 }
define i32 @_Z3foo9DeclGroup(i64) nounwind ssp noredzone {
entry:
%D = alloca %struct.DeclGroup, align 4 ; <%struct.DeclGroup*> [#uses=2]
%tmp = alloca i64 ; <i64*> [#uses=2]
%coerce.dive = getelementptr %struct.DeclGroup* %D, i32 0, i32 0 ; <i32*> [#uses=1]
store i64 %0, i64* %tmp
%1 = bitcast i64* %tmp to i32* ; <i32*> [#uses=1]
%2 = load i32* %1, align 1 ; <i32> [#uses=1]
store i32 %2, i32* %coerce.dive
%tmp1 = getelementptr inbounds %struct.DeclGroup* %D, i32 0, i32 0 ; <i32*> [#uses=1]
%tmp2 = load i32* %tmp1 ; <i32> [#uses=1]
ret i32 %tmp2
}
... which is quite a bit less terrifying.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106975 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGCall.cpp')
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 7835505dcf..6151fa2ed4 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -378,6 +378,38 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr, return SrcPtr; } +/// CoerceIntOrPtrToIntOrPtr - Convert a value Val to the specific Ty where both +/// are either integers or pointers. This does a truncation of the value if it +/// is too large or a zero extension if it is too small. +static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, + const llvm::Type *Ty, + CodeGenFunction &CGF) { + if (Val->getType() == Ty) + return Val; + + if (isa<llvm::PointerType>(Val->getType())) { + // If this is Pointer->Pointer avoid conversion to and from int. + if (isa<llvm::PointerType>(Ty)) + return CGF.Builder.CreateBitCast(Val, Ty, "coerce.val"); + + // Convert the pointer to an integer so we can play with its width. + const llvm::Type *IntPtrTy = llvm::IntegerType::get(Ty->getContext(), + CGF.LLVMPointerWidth); + Val = CGF.Builder.CreatePtrToInt(Val, IntPtrTy, "coerce.val.pi"); + } + + const llvm::Type *DestIntTy = Ty; + if (isa<llvm::PointerType>(DestIntTy)) + DestIntTy = llvm::IntegerType::get(Ty->getContext(), CGF.LLVMPointerWidth); + + if (Val->getType() != DestIntTy) + Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii"); + + if (isa<llvm::PointerType>(Ty)) + Val = CGF.Builder.CreateIntToPtr(Val, Ty, "coerce.val.ip"); + return Val; +} + /// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as @@ -400,6 +432,14 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); + // If the source and destination are integer or pointer types, just do an + // extension or truncation to the desired type. + if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) && + (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) { + llvm::LoadInst *Load = CGF.Builder.CreateLoad(SrcPtr); + return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF); + } + // If load is legal, just bitcast the src pointer. if (SrcSize >= DstSize) { // Generally SrcSize is never greater than DstSize, since this means we are @@ -448,6 +488,15 @@ static void CreateCoercedStore(llvm::Value *Src, DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType(); } + // If the source and destination are integer or pointer types, just do an + // extension or truncation to the desired type. + if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) && + (isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) { + Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF); + CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); + return; + } + uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy); // If store is legal, just bitcast the src pointer. |