mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 04:15:58 +03:00
More in-place construction
Also for struct literal fields, array literal elements and associative array literal elements as well as basic types allocated on the heap.
This commit is contained in:
parent
9f728a4b4c
commit
126184a8b6
7 changed files with 107 additions and 109 deletions
10
gen/aa.cpp
10
gen/aa.cpp
|
@ -32,7 +32,8 @@ static LLValue *to_keyti(DValue *aa) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
|
DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
|
||||||
|
bool lvalue) {
|
||||||
// D2:
|
// D2:
|
||||||
// call:
|
// call:
|
||||||
// extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void*
|
// extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void*
|
||||||
|
@ -41,8 +42,8 @@ DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
|
||||||
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
||||||
|
|
||||||
// first get the runtime function
|
// first get the runtime function
|
||||||
llvm::Function *func = getRuntimeFunction(
|
llvm::Function *func =
|
||||||
loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
getRuntimeFunction(loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
// aa param
|
// aa param
|
||||||
|
@ -197,8 +198,7 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
|
||||||
Type *t = l->type->toBasetype();
|
Type *t = l->type->toBasetype();
|
||||||
assert(t == r->type->toBasetype() &&
|
assert(t == r->type->toBasetype() &&
|
||||||
"aa equality is only defined for aas of same type");
|
"aa equality is only defined for aas of same type");
|
||||||
llvm::Function *func =
|
llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaEqual");
|
||||||
getRuntimeFunction(loc, gIR->module, "_aaEqual");
|
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
LLValue *aaval = DtoBitCast(DtoRVal(l), funcTy->getParamType(1));
|
LLValue *aaval = DtoBitCast(DtoRVal(l), funcTy->getParamType(1));
|
||||||
|
|
3
gen/aa.h
3
gen/aa.h
|
@ -18,13 +18,14 @@
|
||||||
|
|
||||||
enum TOK;
|
enum TOK;
|
||||||
class DValue;
|
class DValue;
|
||||||
|
class DLValue;
|
||||||
struct Loc;
|
struct Loc;
|
||||||
class Type;
|
class Type;
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Value;
|
class Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue);
|
DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue);
|
||||||
DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key);
|
DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key);
|
||||||
DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key);
|
DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key);
|
||||||
llvm::Value *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r);
|
llvm::Value *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r);
|
||||||
|
|
|
@ -173,10 +173,9 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
|
||||||
|
|
||||||
LLValue *itr_val = DtoLoad(itr);
|
LLValue *itr_val = DtoLoad(itr);
|
||||||
// assign array element value
|
// assign array element value
|
||||||
DValue *arrayelem =
|
DLValue arrayelem(dvalue->type->toBasetype(),
|
||||||
new DLValue(dvalue->type->toBasetype(),
|
|
||||||
DtoGEP1(ptr, itr_val, true, "arrayinit.arrayelem"));
|
DtoGEP1(ptr, itr_val, true, "arrayinit.arrayelem"));
|
||||||
DtoAssign(loc, arrayelem, dvalue, op);
|
DtoAssign(loc, &arrayelem, dvalue, op);
|
||||||
|
|
||||||
// increment iterator
|
// increment iterator
|
||||||
DtoStore(gIR->ir->CreateAdd(itr_val, DtoConstSize_t(1), "arrayinit.new_itr"),
|
DtoStore(gIR->ir->CreateAdd(itr_val, DtoConstSize_t(1), "arrayinit.new_itr"),
|
||||||
|
@ -562,9 +561,8 @@ void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem) {
|
||||||
|
|
||||||
// Don't try to write nothing to a zero-element array, we might represent it
|
// Don't try to write nothing to a zero-element array, we might represent it
|
||||||
// as a null pointer.
|
// as a null pointer.
|
||||||
if (elemCount == 0) {
|
if (elemCount == 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (isConstLiteral(ale)) {
|
if (isConstLiteral(ale)) {
|
||||||
llvm::Constant *constarr = arrayLiteralToConst(p, ale);
|
llvm::Constant *constarr = arrayLiteralToConst(p, ale);
|
||||||
|
@ -590,11 +588,14 @@ void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem) {
|
||||||
} else {
|
} else {
|
||||||
// Store the elements one by one.
|
// Store the elements one by one.
|
||||||
for (size_t i = 0; i < elemCount; ++i) {
|
for (size_t i = 0; i < elemCount; ++i) {
|
||||||
DValue *rhs = toElem(indexArrayLiteral(ale, i));
|
Expression *rhsExp = indexArrayLiteral(ale, i);
|
||||||
|
|
||||||
LLValue *lhsPtr = DtoGEPi(dstMem, 0, i, "", p->scopebb());
|
LLValue *lhsPtr = DtoGEPi(dstMem, 0, i, "", p->scopebb());
|
||||||
DLValue lhs(rhs->type, DtoBitCast(lhsPtr, DtoPtrToType(rhs->type)));
|
DLValue lhs(rhsExp->type, DtoBitCast(lhsPtr, DtoPtrToType(rhsExp->type)));
|
||||||
DtoAssign(ale->loc, &lhs, rhs, TOKconstruct, true);
|
|
||||||
|
// try to construct it in-place
|
||||||
|
if (!toInPlaceConstruction(&lhs, rhsExp))
|
||||||
|
DtoAssign(ale->loc, &lhs, toElem(rhsExp), TOKconstruct, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,10 +745,10 @@ DSliceValue *DtoResizeDynArray(Loc &loc, Type *arrayType, DValue *array,
|
||||||
getRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT"
|
getRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT"
|
||||||
: "_d_arraysetlengthiT");
|
: "_d_arraysetlengthiT");
|
||||||
|
|
||||||
LLValue *newArray = gIR->CreateCallOrInvoke(
|
LLValue *newArray =
|
||||||
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(arrayType), newdim,
|
fn, DtoTypeInfoOf(arrayType), newdim,
|
||||||
DtoBitCast(DtoLVal(array),
|
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
|
||||||
fn->getFunctionType()->getParamType(2)),
|
|
||||||
".gc_mem")
|
".gc_mem")
|
||||||
.getInstruction();
|
.getInstruction();
|
||||||
|
|
||||||
|
@ -773,16 +774,16 @@ void DtoCatAssignElement(Loc &loc, Type *arrayType, DValue *array,
|
||||||
LLValue *appendedArray =
|
LLValue *appendedArray =
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(arrayType),
|
fn, DtoTypeInfoOf(arrayType),
|
||||||
DtoBitCast(DtoLVal(array),
|
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(1)),
|
||||||
fn->getFunctionType()->getParamType(1)),
|
|
||||||
DtoConstSize_t(1), ".appendedArray")
|
DtoConstSize_t(1), ".appendedArray")
|
||||||
.getInstruction();
|
.getInstruction();
|
||||||
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
|
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
|
||||||
|
|
||||||
LLValue *val = DtoArrayPtr(array);
|
LLValue *ptr = DtoArrayPtr(array);
|
||||||
val = DtoGEP1(val, oldLength, true, ".lastElem");
|
ptr = DtoGEP1(ptr, oldLength, true, ".lastElem");
|
||||||
DtoAssign(loc, new DLValue(arrayType->nextOf(), val), expVal, TOKblit);
|
DLValue lastElem(arrayType->nextOf(), ptr);
|
||||||
callPostblit(loc, exp, val);
|
DtoAssign(loc, &lastElem, expVal, TOKblit);
|
||||||
|
callPostblit(loc, exp, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1090,14 +1090,6 @@ DValue *DtoArgument(Parameter *fnarg, Expression *argexp) {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// byval arg, but expr has no storage yet
|
|
||||||
if (DtoIsInMemoryOnly(argexp->type) && (arg->isSlice() || arg->isNull())) {
|
|
||||||
LLValue *alloc = DtoAlloca(argexp->type, ".tmp_arg");
|
|
||||||
auto vv = new DLValue(argexp->type, alloc);
|
|
||||||
DtoAssign(argexp->loc, vv, arg);
|
|
||||||
arg = vv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ bool isTargetWindowsMSVC() {
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static llvm::ManagedStatic<llvm::LLVMContext> GlobalContext;
|
static llvm::ManagedStatic<llvm::LLVMContext> GlobalContext;
|
||||||
|
|
||||||
llvm::LLVMContext& getGlobalContext() { return *GlobalContext; }
|
llvm::LLVMContext &getGlobalContext() { return *GlobalContext; }
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* DYNAMIC MEMORY HELPERS
|
* DYNAMIC MEMORY HELPERS
|
||||||
|
@ -523,8 +523,7 @@ DValue *DtoCastFloat(Loc &loc, DValue *val, Type *to) {
|
||||||
} else if (fromsz < tosz) {
|
} else if (fromsz < tosz) {
|
||||||
rval = new llvm::FPExtInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
rval = new llvm::FPExtInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
||||||
} else if (fromsz > tosz) {
|
} else if (fromsz > tosz) {
|
||||||
rval =
|
rval = new llvm::FPTruncInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
||||||
new llvm::FPTruncInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
|
||||||
} else {
|
} else {
|
||||||
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
||||||
to->toChars());
|
to->toChars());
|
||||||
|
@ -550,8 +549,8 @@ DValue *DtoCastDelegate(Loc &loc, DValue *val, Type *to) {
|
||||||
return DtoPaintType(loc, val, to);
|
return DtoPaintType(loc, val, to);
|
||||||
}
|
}
|
||||||
if (to->toBasetype()->ty == Tbool) {
|
if (to->toBasetype()->ty == Tbool) {
|
||||||
return new DImValue(
|
return new DImValue(to,
|
||||||
to, DtoDelegateEquals(TOKnotequal, DtoRVal(val), nullptr));
|
DtoDelegateEquals(TOKnotequal, DtoRVal(val), nullptr));
|
||||||
}
|
}
|
||||||
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
||||||
to->toChars());
|
to->toChars());
|
||||||
|
@ -1327,30 +1326,16 @@ Type *stripModifiers(Type *type, bool transitive) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LLValue *makeLValue(Loc &loc, DValue *value) {
|
LLValue *makeLValue(Loc &loc, DValue *value) {
|
||||||
Type *valueType = value->type;
|
if (value->isLVal())
|
||||||
bool needsMemory;
|
return DtoLVal(value);
|
||||||
LLValue *valuePointer;
|
|
||||||
if (value->isIm()) {
|
if (value->isIm() || value->isConst())
|
||||||
valuePointer = DtoRVal(value);
|
return DtoAllocaDump(value, ".makelvaluetmp");
|
||||||
needsMemory = !DtoIsInMemoryOnly(valueType);
|
|
||||||
} else if (value->isLVal()) {
|
LLValue *mem = DtoAlloca(value->type, ".makelvaluetmp");
|
||||||
valuePointer = DtoLVal(value);
|
DLValue var(value->type, mem);
|
||||||
needsMemory = false;
|
|
||||||
} else if (value->isConst()) {
|
|
||||||
valuePointer = DtoRVal(value);
|
|
||||||
needsMemory = true;
|
|
||||||
} else {
|
|
||||||
valuePointer = DtoAlloca(valueType, ".makelvaluetmp");
|
|
||||||
DLValue var(valueType, valuePointer);
|
|
||||||
DtoAssign(loc, &var, value);
|
DtoAssign(loc, &var, value);
|
||||||
needsMemory = false;
|
return mem;
|
||||||
}
|
|
||||||
|
|
||||||
if (needsMemory) {
|
|
||||||
valuePointer = DtoAllocaDump(value, ".makelvaluetmp");
|
|
||||||
}
|
|
||||||
|
|
||||||
return valuePointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
93
gen/toir.cpp
93
gen/toir.cpp
|
@ -74,18 +74,14 @@ static LLValue *write_zeroes(LLValue *mem, unsigned start, unsigned end) {
|
||||||
|
|
||||||
static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
||||||
Expressions *elements) {
|
Expressions *elements) {
|
||||||
// ready elements data
|
|
||||||
assert(elements && "struct literal has null elements");
|
assert(elements && "struct literal has null elements");
|
||||||
const size_t nexprs = elements->dim;
|
|
||||||
Expression **exprs = reinterpret_cast<Expression **>(elements->data);
|
|
||||||
|
|
||||||
// might be reset to an actual i8* value so only a single bitcast is emitted.
|
// might be reset to an actual i8* value so only a single bitcast is emitted
|
||||||
LLValue *voidptr = mem;
|
LLValue *voidptr = mem;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
// go through fields
|
// go through fields
|
||||||
const size_t nfields = sd->fields.dim;
|
for (size_t index = 0; index < sd->fields.dim; ++index) {
|
||||||
for (size_t index = 0; index < nfields; ++index) {
|
|
||||||
VarDeclaration *vd = sd->fields[index];
|
VarDeclaration *vd = sd->fields[index];
|
||||||
|
|
||||||
// Skip zero-sized fields such as zero-length static arrays: `ubyte[0]
|
// Skip zero-sized fields such as zero-length static arrays: `ubyte[0]
|
||||||
|
@ -94,17 +90,17 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// get initializer expression
|
// get initializer expression
|
||||||
Expression *expr = (index < nexprs) ? exprs[index] : nullptr;
|
Expression *expr =
|
||||||
|
(index < elements->dim) ? elements->data[index] : nullptr;
|
||||||
|
|
||||||
if (vd->overlapped && !expr) {
|
if (vd->overlapped && !expr) {
|
||||||
// In case of an union (overlapped field), we can't simply use the default
|
// In case of a union (overlapped field), we can't simply use the default
|
||||||
// initializer.
|
// initializer.
|
||||||
// Consider the type union U7727A1 { int i; double d; } and
|
// Consider the type union U7727A1 { int i; double d; } and
|
||||||
// the declaration U7727A1 u = { d: 1.225 };
|
// the declaration U7727A1 u = { d: 1.225 };
|
||||||
// The loop will first visit variable i and then d. Since d has an
|
// The loop will first visit variable i and then d. Since d has an
|
||||||
// explicit initializer, we must use this one. We should therefore skip
|
// explicit initializer, we must use this one. We should therefore skip
|
||||||
// union fields
|
// union fields with no explicit initializer.
|
||||||
// with no explicit initializer.
|
|
||||||
IF_LOG Logger::println(
|
IF_LOG Logger::println(
|
||||||
"skipping overlapped field without init expr: %s %s (+%u)",
|
"skipping overlapped field without init expr: %s %s (+%u)",
|
||||||
vd->type->toChars(), vd->toChars(), vd->offset);
|
vd->type->toChars(), vd->toChars(), vd->offset);
|
||||||
|
@ -119,49 +115,51 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize any padding so struct comparisons work
|
// initialize any padding so struct comparisons work
|
||||||
if (vd->offset != offset) {
|
if (vd->offset != offset)
|
||||||
voidptr = write_zeroes(voidptr, offset, vd->offset);
|
voidptr = write_zeroes(voidptr, offset, vd->offset);
|
||||||
}
|
|
||||||
offset = vd->offset + vd->type->size();
|
offset = vd->offset + vd->type->size();
|
||||||
|
|
||||||
|
// skip fields with a void initializer
|
||||||
|
if (!expr && vd != sd->vthis && vd->_init &&
|
||||||
|
vd->_init->isVoidInitializer()) {
|
||||||
|
IF_LOG Logger::println(
|
||||||
|
"skipping field with void initializer: %s %s (+%u)",
|
||||||
|
vd->type->toChars(), vd->toChars(), vd->offset);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
IF_LOG Logger::println("initializing field: %s %s (+%u)",
|
IF_LOG Logger::println("initializing field: %s %s (+%u)",
|
||||||
vd->type->toChars(), vd->toChars(), vd->offset);
|
vd->type->toChars(), vd->toChars(), vd->offset);
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
||||||
// get initializer
|
|
||||||
DValue *val;
|
|
||||||
std::unique_ptr<DConstValue> cv;
|
|
||||||
if (expr) {
|
|
||||||
IF_LOG Logger::println("expr %llu = %s",
|
|
||||||
static_cast<unsigned long long>(index),
|
|
||||||
expr->toChars());
|
|
||||||
val = toElem(expr);
|
|
||||||
} else if (vd == sd->vthis) {
|
|
||||||
IF_LOG Logger::println("initializing vthis");
|
|
||||||
LOG_SCOPE
|
|
||||||
val = new DImValue(
|
|
||||||
vd->type, DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type)));
|
|
||||||
} else {
|
|
||||||
if (vd->_init && vd->_init->isVoidInitializer()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
IF_LOG Logger::println("using default initializer");
|
|
||||||
LOG_SCOPE
|
|
||||||
cv.reset(new DConstValue(vd->type, get_default_initializer(vd)));
|
|
||||||
val = cv.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a pointer to this field
|
// get a pointer to this field
|
||||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||||
"vars, although it can easily be made to.");
|
"vars, although it can easily be made to.");
|
||||||
DLValue field(vd->type, DtoIndexAggregate(mem, sd, vd));
|
DLValue field(vd->type, DtoIndexAggregate(mem, sd, vd));
|
||||||
|
|
||||||
// store the initializer there
|
// get initializer
|
||||||
DtoAssign(loc, &field, val, TOKconstruct, true);
|
if (expr) {
|
||||||
|
IF_LOG Logger::println("expr %llu = %s",
|
||||||
if (expr && expr->isLvalue()) {
|
static_cast<unsigned long long>(index),
|
||||||
|
expr->toChars());
|
||||||
|
// try to construct it in-place
|
||||||
|
if (!toInPlaceConstruction(&field, expr)) {
|
||||||
|
DtoAssign(loc, &field, toElem(expr), TOKconstruct, true);
|
||||||
|
if (expr->isLvalue())
|
||||||
callPostblit(loc, expr, DtoLVal(&field));
|
callPostblit(loc, expr, DtoLVal(&field));
|
||||||
}
|
}
|
||||||
|
} else if (vd == sd->vthis) {
|
||||||
|
IF_LOG Logger::println("initializing vthis");
|
||||||
|
LOG_SCOPE
|
||||||
|
DImValue val(vd->type,
|
||||||
|
DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type)));
|
||||||
|
DtoAssign(loc, &field, &val, TOKconstruct, true);
|
||||||
|
} else {
|
||||||
|
IF_LOG Logger::println("using default initializer");
|
||||||
|
LOG_SCOPE
|
||||||
|
DConstValue val(vd->type, get_default_initializer(vd));
|
||||||
|
DtoAssign(loc, &field, &val, TOKconstruct, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Also zero out padding bytes counted as being part of the type in DMD
|
// Also zero out padding bytes counted as being part of the type in DMD
|
||||||
// but not in LLVM; e.g. real/x86_fp80.
|
// but not in LLVM; e.g. real/x86_fp80.
|
||||||
|
@ -173,10 +171,10 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
||||||
voidptr = write_zeroes(voidptr, offset - implicitPadding, offset);
|
voidptr = write_zeroes(voidptr, offset - implicitPadding, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize trailing padding
|
// initialize trailing padding
|
||||||
if (sd->structsize != offset) {
|
if (sd->structsize != offset)
|
||||||
voidptr = write_zeroes(voidptr, offset, sd->structsize);
|
voidptr = write_zeroes(voidptr, offset, sd->structsize);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1522,8 +1520,9 @@ public:
|
||||||
exp = (*e->arguments)[0];
|
exp = (*e->arguments)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
DValue *iv = toElem(exp);
|
// try to construct it in-place
|
||||||
DtoAssign(e->loc, &tmpvar, iv);
|
if (!toInPlaceConstruction(&tmpvar, exp))
|
||||||
|
DtoAssign(e->loc, &tmpvar, toElem(exp));
|
||||||
|
|
||||||
// return as pointer-to
|
// return as pointer-to
|
||||||
result = new DImValue(e->type, mem);
|
result = new DImValue(e->type, mem);
|
||||||
|
@ -2501,11 +2500,11 @@ public:
|
||||||
|
|
||||||
// index
|
// index
|
||||||
DValue *key = toElem(ekey);
|
DValue *key = toElem(ekey);
|
||||||
DValue *mem = DtoAAIndex(e->loc, vtype, result, key, true);
|
DLValue *mem = DtoAAIndex(e->loc, vtype, result, key, true);
|
||||||
|
|
||||||
// store
|
// try to construct it in-place
|
||||||
DValue *val = toElem(eval);
|
if (!toInPlaceConstruction(mem, eval))
|
||||||
DtoAssign(e->loc, mem, val);
|
DtoAssign(e->loc, mem, toElem(eval));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,9 +102,29 @@ void staticArrays()
|
||||||
const(int[2]) sa = [ 1, 2 ];
|
const(int[2]) sa = [ 1, 2 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Container { S s; }
|
||||||
|
|
||||||
|
// CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct19hierarchyOfLiteralsFZv
|
||||||
|
void hierarchyOfLiterals()
|
||||||
|
{
|
||||||
|
// CHECK: %sa = alloca [1 x %in_place_construct.Container]
|
||||||
|
// CHECK: %1 = getelementptr inbounds {{.*}}[1 x %in_place_construct.Container]* %sa, i32 0, i32 0
|
||||||
|
// CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.Container* %1, i32 0, i32 0
|
||||||
|
// CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 0
|
||||||
|
// CHECK: store i64 11, i64* %3
|
||||||
|
// CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 1
|
||||||
|
// CHECK: store i64 12, i64* %4
|
||||||
|
// CHECK: %5 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 2
|
||||||
|
// CHECK: store i64 13, i64* %5
|
||||||
|
// CHECK: %6 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 3
|
||||||
|
// CHECK: store i64 14, i64* %6
|
||||||
|
Container[1] sa = [ Container(S(11, 12, 13, 14)) ];
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: define{{.*}} @{{.*}}_Dmain
|
// CHECK-LABEL: define{{.*}} @{{.*}}_Dmain
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
structs();
|
structs();
|
||||||
staticArrays();
|
staticArrays();
|
||||||
|
hierarchyOfLiterals();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue