Don't emit init symbol for zero-initialized structs (#3131)

And optimize previous usages of it to direct memset-zero.
This commit is contained in:
Martin Kinkelin 2019-09-12 00:30:09 +02:00 committed by GitHub
parent 25195fb36c
commit 3840a03af4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 22 deletions

View file

@ -141,12 +141,15 @@ public:
// Skip __initZ and typeinfo for @compute device code. // Skip __initZ and typeinfo for @compute device code.
// TODO: support global variables and thus __initZ // TODO: support global variables and thus __initZ
if (!irs->dcomputetarget) { if (!irs->dcomputetarget) {
// Define the __initZ symbol.
IrAggr *ir = getIrAggr(decl); IrAggr *ir = getIrAggr(decl);
auto &initZ = ir->getInitSymbol();
auto initGlobal = llvm::cast<LLGlobalVariable>(initZ); // Define the __initZ symbol.
initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit()); if (!decl->zeroInit) {
setLinkageAndVisibility(decl, initGlobal); auto &initZ = ir->getInitSymbol();
auto initGlobal = llvm::cast<LLGlobalVariable>(initZ);
initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit());
setLinkageAndVisibility(decl, initGlobal);
}
// emit typeinfo // emit typeinfo
if (!ir->suppressTypeInfo()) { if (!ir->suppressTypeInfo()) {

View file

@ -1650,10 +1650,16 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars()); IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct); assert(sdecltype->ty == Tstruct);
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype); TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
assert(ts->sym); StructDeclaration *sd = ts->sym;
DtoResolveStruct(ts->sym); assert(sd);
DtoResolveStruct(sd);
LLValue *initsym = getIrAggr(ts->sym)->getInitSymbol(); if (sd->zeroInit) {
error(loc, "no init symbol for zero-initialized struct");
fatal();
}
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
return new DLValue(type, initsym); return new DLValue(type, initsym);
} }

View file

@ -2293,15 +2293,21 @@ public:
LOG_SCOPE; LOG_SCOPE;
if (e->useStaticInit) { if (e->useStaticInit) {
DtoResolveStruct(e->sd); StructDeclaration *sd = e->sd;
LLValue *initsym = getIrAggr(e->sd)->getInitSymbol(); DtoResolveStruct(sd);
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
if (!dstMem) if (!dstMem)
dstMem = DtoAlloca(e->type, ".structliteral"); dstMem = DtoAlloca(e->type, ".structliteral");
assert(dstMem->getType() == initsym->getType()); if (sd->zeroInit) {
DtoMemCpy(dstMem, initsym); DtoMemSetZero(dstMem);
} else {
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
assert(dstMem->getType() == initsym->getType());
DtoMemCpy(dstMem, initsym);
}
return new DLValue(e->type, dstMem); return new DLValue(e->type, dstMem);
} }
@ -2739,6 +2745,26 @@ bool basetypesAreEqualWithoutModifiers(Type *l, Type *r) {
} }
bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) { bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
// Is the rhs the init symbol of a zero-initialized struct?
// Then aggressively zero-out the lhs, without any type checks, e.g., allowing
// to initialize a `S[1]` lhs with a `S` rhs.
if (auto ve = rhs->isVarExp()) {
if (auto symdecl = ve->var->isSymbolDeclaration()) {
Type *t = symdecl->type->toBasetype();
if (auto ts = t->isTypeStruct()) {
// this is the static initializer for a struct (init symbol)
StructDeclaration *sd = ts->sym;
assert(sd);
DtoResolveStruct(sd);
if (sd->zeroInit) {
DtoMemSetZero(DtoLVal(lhs));
return true;
}
}
}
}
if (!basetypesAreEqualWithoutModifiers(lhs->type, rhs->type)) if (!basetypesAreEqualWithoutModifiers(lhs->type, rhs->type))
return false; return false;

View file

@ -3,16 +3,16 @@
// Fails on Windows_x86, see https://github.com/ldc-developers/ldc/issues/1356 // Fails on Windows_x86, see https://github.com/ldc-developers/ldc/issues/1356
// XFAIL: Windows_x86 // XFAIL: Windows_x86
align(32) struct Outer { int a; } align(32) struct Outer { int a = 1; }
struct Inner { align(32) int a; } // CHECK-DAG: _D5align5Outer6__initZ = constant %align.Outer {{.*}}, align 32
struct Inner { align(32) int a = 1; }
// CHECK-DAG: _D5align5Inner6__initZ = constant %align.Inner {{.*}}, align 32
align(1) ubyte globalByte1; align(1) ubyte globalByte1;
// CHECK-DAG: _D5align11globalByte1h = {{.*}} align 1 // CHECK-DAG: _D5align11globalByte1h = {{.*}} align 1
static Outer globalOuter; static Outer globalOuter;
// CHECK-DAG: constant %align.Outer zeroinitializer{{(, comdat)?}}, align 32
// CHECK-DAG: _D5align11globalOuterSQu5Outer = {{.*}} align 32 // CHECK-DAG: _D5align11globalOuterSQu5Outer = {{.*}} align 32
static Inner globalInner; static Inner globalInner;
// CHECK-DAG: constant %align.Inner zeroinitializer{{(, comdat)?}}, align 32
// CHECK-DAG: _D5align11globalInnerSQu5Inner = {{.*}} align 32 // CHECK-DAG: _D5align11globalInnerSQu5Inner = {{.*}} align 32
Outer passAndReturnOuterByVal(Outer arg) { return arg; } Outer passAndReturnOuterByVal(Outer arg) { return arg; }

View file

@ -28,7 +28,7 @@ interface DefaultI { void foo(); }
// DEFAULT: _D24export_aggregate_symbols8DefaultS6__initZ // DEFAULT: _D24export_aggregate_symbols8DefaultS6__initZ
// HIDDEN-NOT: _D24export_aggregate_symbols8DefaultS6__initZ // HIDDEN-NOT: _D24export_aggregate_symbols8DefaultS6__initZ
struct DefaultS {} struct DefaultS { int nonZero = 1; }
@ -43,7 +43,7 @@ export class ExportedC : ExportedI { void foo() {} }
export interface ExportedI { void foo(); } export interface ExportedI { void foo(); }
// BOTH: _D24export_aggregate_symbols9ExportedS6__initZ // BOTH: _D24export_aggregate_symbols9ExportedS6__initZ
export struct ExportedS {} export struct ExportedS { int nonZero = 1; }

View file

@ -1,13 +1,13 @@
// RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
// RUN: %ldc -run %s // RUN: %ldc -run %s
// CHECK: %gh2235.Foo = type <{ // CHECK-DAG: %gh2235.Foo = type <{
align(2) struct Foo { align(2) struct Foo {
long y; long y;
byte z; byte z;
} }
// CHECK: %gh2235.Bar = type <{ // CHECK-DAG: %gh2235.Bar = type <{
class Bar { class Bar {
union { union {
bool b; bool b;

View file

@ -0,0 +1,13 @@
// RUN: %ldc -output-ll -of=%t.ll %s
// RUN: FileCheck %s < %t.ll
module mod;
// CHECK-NOT: _D3mod5Empty6__initZ
struct Empty {}
// CHECK-NOT: _D3mod7WithInt6__initZ
struct WithInt { int a; }
// CHECK-NOT: _D3mod13WithZeroFloat6__initZ
struct WithZeroFloat { float a = 0; }

View file

@ -15,7 +15,6 @@ struct S17237
int4 globalIntFour; int4 globalIntFour;
// CHECK-DAG: globalIntFour{{.*}} = {{.*}} align 16 // CHECK-DAG: globalIntFour{{.*}} = {{.*}} align 16
S17237 globalStruct; S17237 globalStruct;
// CHECK-DAG: constant %{{.*}}.S17237 zeroinitializer{{(, comdat)?}}, align 32
// CHECK-DAG: @{{.*}}globalStruct{{.*}}S17237{{\"?}} = {{.*}} zeroinitializer{{(, comdat)?}}, align 32 // CHECK-DAG: @{{.*}}globalStruct{{.*}}S17237{{\"?}} = {{.*}} zeroinitializer{{(, comdat)?}}, align 32
// CHECK-LABEL: define <8 x i32> @foo( // CHECK-LABEL: define <8 x i32> @foo(