From 7e9f52f1faacf5505476418411127c5b16e07533 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 5 Jun 2013 03:00:13 +0000 Subject: [PATCH] Fix CoerceIntOrPtrToIntOrPtr on big-endian targets. Type coercion for argument passing is equivalent to storing the source type and loading the destination type from the same pointer. On big-endian targets, this means that the high bits of integers are preserved. This patch fixes the CoerceIntOrPtrToIntOrPtr() function on big-endian targets by inserting the required shift instructions to preserve the high bits instead of the low bits. This is used by SparcABIInfo when passing small structs in the high bits of registers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183291 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCall.cpp | 25 +++++++++++++++++++++++-- test/CodeGen/sparcv9-abi.c | 26 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 3c079cd58b..a53283eb14 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -642,6 +642,10 @@ EnterStructPointerForCoercedAccess(llvm::Value *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. +/// +/// This behaves as if the value were coerced through memory, so on big-endian +/// targets the high bits are preserved in a truncation, while little-endian +/// targets preserve the low bits. static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, llvm::Type *Ty, CodeGenFunction &CGF) { @@ -661,8 +665,25 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, if (isa(DestIntTy)) DestIntTy = CGF.IntPtrTy; - if (Val->getType() != DestIntTy) - Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii"); + if (Val->getType() != DestIntTy) { + const llvm::DataLayout &DL = CGF.CGM.getDataLayout(); + if (DL.isBigEndian()) { + // Preserve the high bits on big-endian targets. + // That is what memory coercion does. + uint64_t SrcSize = DL.getTypeAllocSizeInBits(Val->getType()); + uint64_t DstSize = DL.getTypeAllocSizeInBits(DestIntTy); + if (SrcSize > DstSize) { + Val = CGF.Builder.CreateLShr(Val, SrcSize - DstSize, "coerce.highbits"); + Val = CGF.Builder.CreateTrunc(Val, DestIntTy, "coerce.val.ii"); + } else { + Val = CGF.Builder.CreateZExt(Val, DestIntTy, "coerce.val.ii"); + Val = CGF.Builder.CreateShl(Val, DstSize - SrcSize, "coerce.highbits"); + } + } else { + // Little-endian targets preserve the low bits. No shifts required. + Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii"); + } + } if (isa(Ty)) Val = CGF.Builder.CreateIntToPtr(Val, Ty, "coerce.val.ip"); diff --git a/test/CodeGen/sparcv9-abi.c b/test/CodeGen/sparcv9-abi.c index b4c7d68549..b58c84689a 100644 --- a/test/CodeGen/sparcv9-abi.c +++ b/test/CodeGen/sparcv9-abi.c @@ -85,7 +85,33 @@ struct mixed2 { double b; }; +// CHECK: define { i64, double } @f_mixed2(i64 %x.coerce0, double %x.coerce1) +// CHECK: store i64 %x.coerce0 +// CHECK: store double %x.coerce1 struct mixed2 f_mixed2(struct mixed2 x) { x.a += 1; return x; } + +// Struct with single element and padding in passed in the high bits of a +// register. +struct tiny { + char a; +}; + +// CHECK: define i64 @f_tiny(i64 %x.coerce) +// CHECK: %[[HB:[^ ]+]] = lshr i64 %x.coerce, 56 +// CHECK: = trunc i64 %[[HB]] to i8 +struct tiny f_tiny(struct tiny x) { + x.a += 1; + return x; +} + +// CHECK: define void @call_tiny() +// CHECK: %[[XV:[^ ]+]] = zext i8 %{{[^ ]+}} to i64 +// CHECK: %[[HB:[^ ]+]] = shl i64 %[[XV]], 56 +// CHECK: = call i64 @f_tiny(i64 %[[HB]]) +void call_tiny() { + struct tiny x = { 1 }; + f_tiny(x); +} -- 2.40.0