From: Chris Lattner Date: Tue, 13 Apr 2010 18:16:19 +0000 (+0000) Subject: Rework the ConstStructBuilder code to emit missing initializer X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ce9e451b421e4c941bc120bcc7f422457656d63;p=clang Rework the ConstStructBuilder code to emit missing initializer elements with explicit zero values instead of with tail padding. On an example like this: struct foo { int a; int b; }; struct foo fooarray[] = { {1, 2}, {4}, }; We now lay this out as: @fooarray = global [2 x %struct.foo] [%struct.foo { i32 1, i32 2 }, %struct.foo { i32 4, i32 0 }] instead of as: @fooarray = global %0 <{ %struct.foo { i32 1, i32 2 }, %1 { i32 4, [4 x i8] zeroinitializer } }> Preserving both the struct type of the second element, but also the array type of the entire thing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101155 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 8d16ed7ad7..7da7554e2c 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -50,10 +50,10 @@ private: LLVMStructAlignment(1) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr); + llvm::Constant *InitExpr); bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr); + llvm::Constant *InitExpr); void AppendPadding(uint64_t NumBytes); @@ -74,18 +74,18 @@ private: }; bool ConstStructBuilder:: -AppendField(const FieldDecl *Field, uint64_t FieldOffset, const Expr *InitExpr){ +AppendField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { uint64_t FieldOffsetInBytes = FieldOffset / 8; assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && "Field offset mismatch!"); // Emit the field. - llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); - if (!C) + if (!InitCst) return false; - unsigned FieldAlignment = getAlignment(C); + unsigned FieldAlignment = getAlignment(InitCst); // Round up the field offset to the alignment of the field type. uint64_t AlignedNextFieldOffsetInBytes = @@ -111,8 +111,9 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, const Expr *InitExpr){ } // Add the field. - Elements.push_back(C); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); + Elements.push_back(InitCst); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + + getSizeInBytes(InitCst); if (Packed) assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); @@ -124,11 +125,8 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, const Expr *InitExpr){ bool ConstStructBuilder:: AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - llvm::ConstantInt *CI = - cast_or_null(CGM.EmitConstantExpr(InitExpr, - Field->getType(), - CGF)); + llvm::Constant *InitCst) { + llvm::ConstantInt *CI = cast_or_null(InitCst); // FIXME: Can this ever happen? if (!CI) return false; @@ -323,26 +321,34 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { unsigned FieldNo = 0; unsigned ElementNo = 0; for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - ElementNo < ILE->getNumInits() && Field != FieldEnd; - ++Field, ++FieldNo) { + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + + // If this is a union, skip all the fields that aren't being initialized. if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) continue; - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isBitField() && !Field->getIdentifier()) + continue; - if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) + // Get the initializer. A struct can include fields without initializers, + // we just use explicit null values for them. + llvm::Constant *EltInit; + if (ElementNo < ILE->getNumInits()) + EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++), + Field->getType(), CGF); + else + EltInit = CGM.EmitNullConstant(Field->getType()); + + if (!Field->isBitField()) { + // Handle non-bitfield members. + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) return false; } else { - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) + // Otherwise we have a bitfield. + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) return false; } - - ElementNo++; } uint64_t LayoutSizeInBytes = Layout.getSize() / 8; diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c index 2b07be24fb..0c7ef5fc97 100644 --- a/test/CodeGen/decl.c +++ b/test/CodeGen/decl.c @@ -5,7 +5,10 @@ // CHECK: @test5w = global %0 { i32 2, [4 x i8] zeroinitializer } // CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 } -// CHECK: @test6.x = internal constant %1 { i8 1, i8 2, i32 3, [4 x i8] zeroinitializer } +// CHECK: @test6.x = internal constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 } + +// CHECK: @test7 = global [2 x %struct.test7s] [%struct.test7s { i32 1, i32 2 }, %struct.test7s { i32 4, i32 0 }] + void test1() { // This should codegen as a "@test1.x" global. const int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23 }; @@ -74,3 +77,10 @@ void test6() { struct SelectDest x = {1, 2, 3}; test6f(&x); } + +// rdar://7657600 +struct test7s { int a; int b; } test7[] = { + {1, 2}, + {4}, +}; +