From 380b2243595046d472884f7902f6f76749306508 Mon Sep 17 00:00:00 2001 From: Denis Zobnin Date: Thu, 11 Feb 2016 11:26:03 +0000 Subject: [PATCH] [MCU] Fix assertion failure on function returning empty union. Treat empty struct/union in return type as void for MCU ABI. PR26438. Differential Revision: http://reviews.llvm.org/D16808 llvm-svn: 260510 --- clang/lib/CodeGen/TargetInfo.cpp | 6 ++- clang/test/CodeGen/mcu-struct-return.c | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/mcu-struct-return.c diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 1cfdde3..bbc6b3b 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -364,7 +364,7 @@ static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { const RecordType *RT = T->getAs(); if (!RT) - return 0; + return false; const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; @@ -1119,6 +1119,10 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, if (!IsRetSmallStructInRegABI && !RetTy->isAnyComplexType()) return getIndirectReturnResult(RetTy, State); + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), RetTy, true)) + return ABIArgInfo::getIgnore(); + // Small structures which are register sized are generally returned // in a register. if (shouldReturnTypeInRegister(RetTy, getContext())) { diff --git a/clang/test/CodeGen/mcu-struct-return.c b/clang/test/CodeGen/mcu-struct-return.c new file mode 100644 index 0000000..353c963 --- /dev/null +++ b/clang/test/CodeGen/mcu-struct-return.c @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple i386-pc-elfiamcu -emit-llvm %s -o - | FileCheck %s + +// Structure that is more than 8 byte. +struct Big { + double a[10]; +}; + +// Empty union with zero size must be returned as void. +union U1 { +} u1; + +// Too large union (80 bytes) must be returned via memory. +union U2 { + struct Big b; +} u2; + +// Must be returned in register. +union U3 { + int x; +} u3; + +// Empty struct with zero size, must be returned as void. +struct S1 { +} s1; + +// Must be returend in register. +struct S2 { + int x; +} s2; + +// CHECK: [[UNION1_TYPE:%.+]] = type {} +// CHECK: [[UNION2_TYPE:%.+]] = type { [[STRUCT_TYPE:%.+]] } +// CHECK: [[STRUCT_TYPE]] = type { [10 x double] } +// CHECK: [[UNION3_TYPE:%.+]] = type { i32 } +// CHECK: [[STRUCT1_TYPE:%.+]] = type {} +// CHECK: [[STRUCT2_TYPE:%.+]] = type { i32 } + +union U1 foo1() { return u1; } +union U2 foo2() { return u2; } +union U3 foo3() { return u3; } +struct S1 bar1() { return s1; } +struct S2 bar2() { return s2; } +struct S1 bar3(union U1 u) { return s1; } +// CHECK: define void @foo1() +// CHECK: define void @foo2([[UNION2_TYPE]]* noalias sret %{{.+}}) +// CHECK: define i32 @foo3() +// CHECK: define void @bar1() +// CHECK: define i32 @bar2() +// CHECK: define void @bar3() + +void run() { + union U1 x1 = foo1(); + union U2 x2 = foo2(); + union U3 x3 = foo3(); + struct S1 y1 = bar1(); + struct S2 y2 = bar2(); + struct S1 y3 = bar3(x1); + + // CHECK: [[X1:%.+]] = alloca [[UNION1_TYPE]] + // CHECK: [[X2:%.+]] = alloca [[UNION2_TYPE]] + // CHECK: [[X3:%.+]] = alloca [[UNION3_TYPE]] + // CHECK: [[Y1:%.+]] = alloca [[STRUCT1_TYPE]] + // CHECK: [[Y2:%.+]] = alloca [[STRUCT2_TYPE]] + // CHECK: call void @foo1() + // CHECK: call void @foo2([[UNION2_TYPE]]* sret [[X2]]) + // CHECK: {{.+}} = call i32 @foo3() + // CHECK: call void @bar1() + // CHECK: {{.+}} = call i32 @bar2() + // CHECK: call void @bar3() +} -- 2.7.4