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.
// TODO: support global variables and thus __initZ
if (!irs->dcomputetarget) {
// Define the __initZ symbol.
IrAggr *ir = getIrAggr(decl);
// Define the __initZ symbol.
if (!decl->zeroInit) {
auto &initZ = ir->getInitSymbol();
auto initGlobal = llvm::cast<LLGlobalVariable>(initZ);
initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit());
setLinkageAndVisibility(decl, initGlobal);
}
// emit typeinfo
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());
assert(sdecltype->ty == Tstruct);
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
assert(ts->sym);
DtoResolveStruct(ts->sym);
StructDeclaration *sd = 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()));
return new DLValue(type, initsym);
}

View file

@ -2293,15 +2293,21 @@ public:
LOG_SCOPE;
if (e->useStaticInit) {
DtoResolveStruct(e->sd);
LLValue *initsym = getIrAggr(e->sd)->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
StructDeclaration *sd = e->sd;
DtoResolveStruct(sd);
if (!dstMem)
dstMem = DtoAlloca(e->type, ".structliteral");
if (sd->zeroInit) {
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);
}
@ -2739,6 +2745,26 @@ bool basetypesAreEqualWithoutModifiers(Type *l, Type *r) {
}
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))
return false;

View file

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

View file

@ -28,7 +28,7 @@ interface DefaultI { void foo(); }
// DEFAULT: _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(); }
// 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 -run %s
// CHECK: %gh2235.Foo = type <{
// CHECK-DAG: %gh2235.Foo = type <{
align(2) struct Foo {
long y;
byte z;
}
// CHECK: %gh2235.Bar = type <{
// CHECK-DAG: %gh2235.Bar = type <{
class Bar {
union {
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;
// CHECK-DAG: globalIntFour{{.*}} = {{.*}} align 16
S17237 globalStruct;
// CHECK-DAG: constant %{{.*}}.S17237 zeroinitializer{{(, comdat)?}}, align 32
// CHECK-DAG: @{{.*}}globalStruct{{.*}}S17237{{\"?}} = {{.*}} zeroinitializer{{(, comdat)?}}, align 32
// CHECK-LABEL: define <8 x i32> @foo(