From a4b56d30389753cbde96ad410e86db4b4b86ac16 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 5 Jun 2013 03:00:18 +0000 Subject: [PATCH] Implement SparcV9ABIInfo::EmitVAArg. This could actually be implemented with the LLVM IR va_arg instruction, but it doesn't seem to offer any advantages over accessing the va_list pointer directly. Using the va_list pointer directly makes it possible to perform type coercion directly from the argument array, and the va_list updates are exposed to the optimizers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183292 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 48 +++++++++++++++++++++++++-- test/CodeGen/sparcv9-abi.c | 66 +++++++++++++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 6e5084a149..c4ee7246a5 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -5332,8 +5332,52 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - // FIXME: Implement with va_arg. - return 0; + ABIArgInfo AI = classifyType(Ty, 16 * 8); + llvm::Type *ArgTy = CGT.ConvertType(Ty); + if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) + AI.setCoerceToType(ArgTy); + + llvm::Type *BPP = CGF.Int8PtrPtrTy; + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); + llvm::Value *ArgAddr; + unsigned Stride; + + switch (AI.getKind()) { + case ABIArgInfo::Expand: + llvm_unreachable("Unsupported ABI kind for va_arg"); + + case ABIArgInfo::Extend: + Stride = 8; + ArgAddr = Builder + .CreateConstGEP1_32(Addr, 8 - getDataLayout().getTypeAllocSize(ArgTy), + "extend"); + break; + + case ABIArgInfo::Direct: + Stride = getDataLayout().getTypeAllocSize(AI.getCoerceToType()); + ArgAddr = Addr; + break; + + case ABIArgInfo::Indirect: + Stride = 8; + ArgAddr = Builder.CreateBitCast(Addr, + llvm::PointerType::getUnqual(ArgPtrTy), + "indirect"); + ArgAddr = Builder.CreateLoad(ArgAddr, "indirect.arg"); + break; + + case ABIArgInfo::Ignore: + return llvm::UndefValue::get(ArgPtrTy); + } + + // Update VAList. + Addr = Builder.CreateConstGEP1_32(Addr, Stride, "ap.next"); + Builder.CreateStore(Addr, VAListAddrAsBPP); + + return Builder.CreatePointerCast(ArgAddr, ArgPtrTy, "arg.addr"); } void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const { diff --git a/test/CodeGen/sparcv9-abi.c b/test/CodeGen/sparcv9-abi.c index b58c84689a..22803a6d4c 100644 --- a/test/CodeGen/sparcv9-abi.c +++ b/test/CodeGen/sparcv9-abi.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple sparcv9-unknown-linux -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s +#include // CHECK: define void @f_void() void f_void(void) {} @@ -115,3 +116,66 @@ void call_tiny() { struct tiny x = { 1 }; f_tiny(x); } + +// CHECK: define signext i32 @f_variable(i8* %f, ...) +// CHECK: %ap = alloca i8* +// CHECK: call void @llvm.va_start +// +int f_variable(char *f, ...) { + int s = 0; + char c; + va_list ap; + va_start(ap, f); + while ((c = *f++)) switch (c) { + +// CHECK: %[[CUR:[^ ]+]] = load i8** %ap +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8 +// CHECK-DAG: store i8* %[[NXT]], i8** %ap +// CHECK-DAG: %[[EXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 4 +// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[EXT]] to i32* +// CHECK-DAG: load i32* %[[ADR]] +// CHECK: br + case 'i': + s += va_arg(ap, int); + break; + +// CHECK: %[[CUR:[^ ]+]] = load i8** %ap +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8 +// CHECK-DAG: store i8* %[[NXT]], i8** %ap +// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to i64* +// CHECK-DAG: load i64* %[[ADR]] +// CHECK: br + case 'l': + s += va_arg(ap, long); + break; + +// CHECK: %[[CUR:[^ ]+]] = load i8** %ap +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8 +// CHECK-DAG: store i8* %[[NXT]], i8** %ap +// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.tiny* +// CHECK: br + case 't': + s += va_arg(ap, struct tiny).a; + break; + +// CHECK: %[[CUR:[^ ]+]] = load i8** %ap +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 16 +// CHECK-DAG: store i8* %[[NXT]], i8** %ap +// CHECK-DAG: %[[ADR:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.small* +// CHECK: br + case 's': + s += *va_arg(ap, struct small).a; + break; + +// CHECK: %[[CUR:[^ ]+]] = load i8** %ap +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr i8* %[[CUR]], i32 8 +// CHECK-DAG: store i8* %[[NXT]], i8** %ap +// CHECK-DAG: %[[IND:[^ ]+]] = bitcast i8* %[[CUR]] to %struct.medium** +// CHECK-DAG: %[[ADR:[^ ]+]] = load %struct.medium** %[[IND]] +// CHECK: br + case 'm': + s += *va_arg(ap, struct medium).a; + break; + } + return s; +} -- 2.40.0