mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-08 20:06:03 +03:00
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:
parent
25195fb36c
commit
3840a03af4
8 changed files with 69 additions and 22 deletions
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
36
gen/toir.cpp
36
gen/toir.cpp
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
13
tests/codegen/no_init_symbols_for_zeroinit_structs.d
Normal file
13
tests/codegen/no_init_symbols_for_zeroinit_structs.d
Normal 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; }
|
|
@ -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(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue