Author: dsanders Date: Tue Jan 13 04:47:00 2015 New Revision: 225782 URL: http://llvm.org/viewvc/llvm-project?rev=225782&view=rev Log: [mips] Fix va_arg() for pointer types on big-endian N32.
Summary: The Mips ABI's treat pointers in the same way as integers. They are sign-extended to 32-bit for O32, and 64-bit for N32/N64. This doesn't matter for O32 and N64 where pointers are already the correct width but it does matter for big-endian N32, where pointers are 32-bit and need promoting. The caller side is already passing pointers correctly. This patch corrects the callee. Reviewers: vmedic, atanasyan Reviewed By: atanasyan Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D6812 Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/CodeGen/TargetInfo.cpp cfe/trunk/test/CodeGen/mips-varargs.c Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=225782&r1=225781&r2=225782&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Jan 13 04:47:00 2015 @@ -3315,8 +3315,12 @@ Value *ScalarExprEmitter::VisitVAArgExpr llvm::Value *Val = Builder.CreateLoad(ArgPtr); // If EmitVAArg promoted the type, we must truncate it. - if (ArgTy != Val->getType()) - Val = Builder.CreateTrunc(Val, ArgTy); + if (ArgTy != Val->getType()) { + if (ArgTy->isPointerTy() && !Val->getType()->isPointerTy()) + Val = Builder.CreateIntToPtr(Val, ArgTy); + else + Val = Builder.CreateTrunc(Val, ArgTy); + } return Val; } Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=225782&r1=225781&r2=225782&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Jan 13 04:47:00 2015 @@ -5832,10 +5832,13 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm llvm::Type *BP = CGF.Int8PtrTy; llvm::Type *BPP = CGF.Int8PtrPtrTy; - // Integer arguments are promoted 32-bit on O32 and 64-bit on N32/N64. + // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64. + // Pointers are also promoted in the same way but this only matters for N32. unsigned SlotSizeInBits = IsO32 ? 32 : 64; - if (Ty->isIntegerType() && - CGF.getContext().getIntWidth(Ty) < SlotSizeInBits) { + unsigned PtrWidth = getTarget().getPointerWidth(0); + if ((Ty->isIntegerType() && + CGF.getContext().getIntWidth(Ty) < SlotSizeInBits) || + (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) { Ty = CGF.getContext().getIntTypeForBitwidth(SlotSizeInBits, Ty->isSignedIntegerType()); } @@ -5847,7 +5850,6 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm std::min(getContext().getTypeAlign(Ty) / 8, StackAlignInBytes); llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); llvm::Value *AddrTyped; - unsigned PtrWidth = getTarget().getPointerWidth(0); llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty; if (TypeAlign > MinABIStackAlignInBytes) { Modified: cfe/trunk/test/CodeGen/mips-varargs.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mips-varargs.c?rev=225782&r1=225781&r2=225782&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/mips-varargs.c (original) +++ cfe/trunk/test/CodeGen/mips-varargs.c Tue Jan 13 04:47:00 2015 @@ -136,6 +136,55 @@ long long test_i64(char *fmt, ...) { // ALL: ret i64 [[ARG1]] // ALL: } +char *test_ptr(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + char *v = va_arg(va, char *); + va_end(va); + + return v; +} + +// ALL-LABEL: define i8* @test_ptr(i8*{{.*}} %fmt, ...) +// +// O32: %va = alloca i8*, align [[PTRALIGN:4]] +// N32: %va = alloca i8*, align [[PTRALIGN:4]] +// N64: %va = alloca i8*, align [[PTRALIGN:8]] +// +// ALL: [[VA1:%.+]] = bitcast i8** %va to i8* +// ALL: call void @llvm.va_start(i8* [[VA1]]) +// +// O32: [[TMP0:%.+]] = bitcast i8** %va to i8*** +// O32: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]] +// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. +// N32: [[TMP0:%.+]] = bitcast i8** %va to i64** +// N32: [[AP_CUR:%.+]] = load i64** [[TMP0]], align [[PTRALIGN]] +// N64: [[TMP0:%.+]] = bitcast i8** %va to i8*** +// N64: [[AP_CUR:%.+]] = load i8*** [[TMP0]], align [[PTRALIGN]] +// +// O32: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], i32 1 +// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. +// N32: [[AP_NEXT:%.+]] = getelementptr i64* [[AP_CUR]], {{i32|i64}} 1 +// N64: [[AP_NEXT:%.+]] = getelementptr i8** [[AP_CUR]], {{i32|i64}} 1 +// +// O32: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]] +// N32 differs because the vararg is not a N32 pointer. It's been promoted to 64-bit. +// N32: store i64* [[AP_NEXT]], i64** [[TMP0]], align [[PTRALIGN]] +// N64: store i8** [[AP_NEXT]], i8*** [[TMP0]], align [[PTRALIGN]] +// +// O32: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 4 +// N32 differs because the vararg is not a N32 pointer. It's been promoted to +// 64-bit so we must truncate the excess and bitcast to a N32 pointer. +// N32: [[TMP2:%.+]] = load i64* [[AP_CUR]], align 8 +// N32: [[TMP3:%.+]] = trunc i64 [[TMP2]] to i32 +// N32: [[ARG1:%.+]] = inttoptr i32 [[TMP3]] to i8* +// N64: [[ARG1:%.+]] = load i8** [[AP_CUR]], align 8 +// +// ALL: call void @llvm.va_end(i8* [[VA1]]) +// ALL: ret i8* [[ARG1]] +// ALL: } + int test_v4i32(char *fmt, ...) { va_list va; _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
