From eeb00624413d4a4856e66809b84c558d2cdce17f Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Fri, 7 Jun 2013 23:20:55 +0000 Subject: [PATCH] Fix va_arg on x86-64 for a struct containing a single int128_t. PR16248 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183590 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 21 +++++++++++++++++---- test/CodeGen/x86_64-arguments.c | 10 ++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 604e6cb1da..09aec44d9c 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2484,7 +2484,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // FIXME: Cleanup. assert(AI.isDirect() && "Unexpected ABI info for mixed regs"); llvm::StructType *ST = cast(AI.getCoerceToType()); - llvm::Value *Tmp = CGF.CreateTempAlloca(ST); + llvm::Value *Tmp = CGF.CreateMemTemp(Ty); + Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo()); assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); llvm::Type *TyLo = ST->getElementType(0); llvm::Type *TyHi = ST->getElementType(1); @@ -2508,6 +2509,18 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); RegAddr = CGF.Builder.CreateBitCast(RegAddr, llvm::PointerType::getUnqual(LTy)); + + // Copy to a temporary if necessary to ensure the appropriate alignment. + std::pair SizeAlign = + CGF.getContext().getTypeInfoInChars(Ty); + uint64_t TySize = SizeAlign.first.getQuantity(); + unsigned TyAlign = SizeAlign.second.getQuantity(); + if (TyAlign > 8) { + RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); + llvm::Value *Tmp = CGF.CreateMemTemp(Ty); + CGF.Builder.CreateMemCpy(Tmp, RegAddr, TySize, 8, false); + RegAddr = Tmp; + } } else if (neededSSE == 1) { RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); RegAddr = CGF.Builder.CreateBitCast(RegAddr, @@ -2521,9 +2534,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, llvm::Type *DoubleTy = CGF.DoubleTy; llvm::Type *DblPtrTy = llvm::PointerType::getUnqual(DoubleTy); - llvm::StructType *ST = llvm::StructType::get(DoubleTy, - DoubleTy, NULL); - llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); + llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, NULL); + llvm::Value *V, *Tmp = CGF.CreateMemTemp(Ty); + Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo()); V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, DblPtrTy)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 518ee84330..e94ddb9e92 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -392,3 +392,13 @@ void test50(double d, double e) { // CHECK: [[T0:%.*]] = load double* // CHECK-NEXT: [[T1:%.*]] = load double* // CHECK-NEXT: call void (double, double, ...)* bitcast (void (...)* @test50_helper to void (double, double, ...)*)(double [[T0]], double [[T1]]) + +struct test51_s { __uint128_t intval; }; +void test51(struct test51_s *s, __builtin_va_list argList) { + *s = __builtin_va_arg(argList, struct test51_s); +} + +// CHECK: define void @test51 +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 16, i32 8, i1 false) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 16, i32 16, i1 false) +// CHECK-NEXT: ret void -- 2.40.0