mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-07 03:16:05 +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:
|
||||
// call:
|
||||
// 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)
|
||||
|
||||
// first get the runtime function
|
||||
llvm::Function *func = getRuntimeFunction(
|
||||
loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
||||
llvm::Function *func =
|
||||
getRuntimeFunction(loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
||||
LLFunctionType *funcTy = func->getFunctionType();
|
||||
|
||||
// aa param
|
||||
|
@ -197,8 +198,7 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
|
|||
Type *t = l->type->toBasetype();
|
||||
assert(t == r->type->toBasetype() &&
|
||||
"aa equality is only defined for aas of same type");
|
||||
llvm::Function *func =
|
||||
getRuntimeFunction(loc, gIR->module, "_aaEqual");
|
||||
llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaEqual");
|
||||
LLFunctionType *funcTy = func->getFunctionType();
|
||||
|
||||
LLValue *aaval = DtoBitCast(DtoRVal(l), funcTy->getParamType(1));
|
||||
|
|
3
gen/aa.h
3
gen/aa.h
|
@ -18,13 +18,14 @@
|
|||
|
||||
enum TOK;
|
||||
class DValue;
|
||||
class DLValue;
|
||||
struct Loc;
|
||||
class Type;
|
||||
namespace llvm {
|
||||
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 *DtoAARemove(Loc &loc, DValue *aa, DValue *key);
|
||||
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);
|
||||
// assign array element value
|
||||
DValue *arrayelem =
|
||||
new DLValue(dvalue->type->toBasetype(),
|
||||
DLValue arrayelem(dvalue->type->toBasetype(),
|
||||
DtoGEP1(ptr, itr_val, true, "arrayinit.arrayelem"));
|
||||
DtoAssign(loc, arrayelem, dvalue, op);
|
||||
DtoAssign(loc, &arrayelem, dvalue, op);
|
||||
|
||||
// increment iterator
|
||||
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
|
||||
// as a null pointer.
|
||||
if (elemCount == 0) {
|
||||
if (elemCount == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConstLiteral(ale)) {
|
||||
llvm::Constant *constarr = arrayLiteralToConst(p, ale);
|
||||
|
@ -590,11 +588,14 @@ void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem) {
|
|||
} else {
|
||||
// Store the elements one by one.
|
||||
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());
|
||||
DLValue lhs(rhs->type, DtoBitCast(lhsPtr, DtoPtrToType(rhs->type)));
|
||||
DtoAssign(ale->loc, &lhs, rhs, TOKconstruct, true);
|
||||
DLValue lhs(rhsExp->type, DtoBitCast(lhsPtr, DtoPtrToType(rhsExp->type)));
|
||||
|
||||
// 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"
|
||||
: "_d_arraysetlengthiT");
|
||||
|
||||
LLValue *newArray = gIR->CreateCallOrInvoke(
|
||||
LLValue *newArray =
|
||||
gIR->CreateCallOrInvoke(
|
||||
fn, DtoTypeInfoOf(arrayType), newdim,
|
||||
DtoBitCast(DtoLVal(array),
|
||||
fn->getFunctionType()->getParamType(2)),
|
||||
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
|
||||
".gc_mem")
|
||||
.getInstruction();
|
||||
|
||||
|
@ -773,16 +774,16 @@ void DtoCatAssignElement(Loc &loc, Type *arrayType, DValue *array,
|
|||
LLValue *appendedArray =
|
||||
gIR->CreateCallOrInvoke(
|
||||
fn, DtoTypeInfoOf(arrayType),
|
||||
DtoBitCast(DtoLVal(array),
|
||||
fn->getFunctionType()->getParamType(1)),
|
||||
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(1)),
|
||||
DtoConstSize_t(1), ".appendedArray")
|
||||
.getInstruction();
|
||||
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
|
||||
|
||||
LLValue *val = DtoArrayPtr(array);
|
||||
val = DtoGEP1(val, oldLength, true, ".lastElem");
|
||||
DtoAssign(loc, new DLValue(arrayType->nextOf(), val), expVal, TOKblit);
|
||||
callPostblit(loc, exp, val);
|
||||
LLValue *ptr = DtoArrayPtr(array);
|
||||
ptr = DtoGEP1(ptr, oldLength, true, ".lastElem");
|
||||
DLValue lastElem(arrayType->nextOf(), ptr);
|
||||
DtoAssign(loc, &lastElem, expVal, TOKblit);
|
||||
callPostblit(loc, exp, ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1090,14 +1090,6 @@ DValue *DtoArgument(Parameter *fnarg, Expression *argexp) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ bool isTargetWindowsMSVC() {
|
|||
******************************************************************************/
|
||||
static llvm::ManagedStatic<llvm::LLVMContext> GlobalContext;
|
||||
|
||||
llvm::LLVMContext& getGlobalContext() { return *GlobalContext; }
|
||||
llvm::LLVMContext &getGlobalContext() { return *GlobalContext; }
|
||||
|
||||
/******************************************************************************
|
||||
* DYNAMIC MEMORY HELPERS
|
||||
|
@ -523,8 +523,7 @@ DValue *DtoCastFloat(Loc &loc, DValue *val, Type *to) {
|
|||
} else if (fromsz < tosz) {
|
||||
rval = new llvm::FPExtInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
||||
} else if (fromsz > tosz) {
|
||||
rval =
|
||||
new llvm::FPTruncInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
||||
rval = new llvm::FPTruncInst(DtoRVal(val), tolltype, "", gIR->scopebb());
|
||||
} else {
|
||||
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
||||
to->toChars());
|
||||
|
@ -550,8 +549,8 @@ DValue *DtoCastDelegate(Loc &loc, DValue *val, Type *to) {
|
|||
return DtoPaintType(loc, val, to);
|
||||
}
|
||||
if (to->toBasetype()->ty == Tbool) {
|
||||
return new DImValue(
|
||||
to, DtoDelegateEquals(TOKnotequal, DtoRVal(val), nullptr));
|
||||
return new DImValue(to,
|
||||
DtoDelegateEquals(TOKnotequal, DtoRVal(val), nullptr));
|
||||
}
|
||||
error(loc, "invalid cast from '%s' to '%s'", val->type->toChars(),
|
||||
to->toChars());
|
||||
|
@ -1327,30 +1326,16 @@ Type *stripModifiers(Type *type, bool transitive) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue *makeLValue(Loc &loc, DValue *value) {
|
||||
Type *valueType = value->type;
|
||||
bool needsMemory;
|
||||
LLValue *valuePointer;
|
||||
if (value->isIm()) {
|
||||
valuePointer = DtoRVal(value);
|
||||
needsMemory = !DtoIsInMemoryOnly(valueType);
|
||||
} else if (value->isLVal()) {
|
||||
valuePointer = DtoLVal(value);
|
||||
needsMemory = false;
|
||||
} else if (value->isConst()) {
|
||||
valuePointer = DtoRVal(value);
|
||||
needsMemory = true;
|
||||
} else {
|
||||
valuePointer = DtoAlloca(valueType, ".makelvaluetmp");
|
||||
DLValue var(valueType, valuePointer);
|
||||
if (value->isLVal())
|
||||
return DtoLVal(value);
|
||||
|
||||
if (value->isIm() || value->isConst())
|
||||
return DtoAllocaDump(value, ".makelvaluetmp");
|
||||
|
||||
LLValue *mem = DtoAlloca(value->type, ".makelvaluetmp");
|
||||
DLValue var(value->type, mem);
|
||||
DtoAssign(loc, &var, value);
|
||||
needsMemory = false;
|
||||
}
|
||||
|
||||
if (needsMemory) {
|
||||
valuePointer = DtoAllocaDump(value, ".makelvaluetmp");
|
||||
}
|
||||
|
||||
return valuePointer;
|
||||
return mem;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
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,
|
||||
Expressions *elements) {
|
||||
// ready elements data
|
||||
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;
|
||||
unsigned offset = 0;
|
||||
|
||||
// go through fields
|
||||
const size_t nfields = sd->fields.dim;
|
||||
for (size_t index = 0; index < nfields; ++index) {
|
||||
for (size_t index = 0; index < sd->fields.dim; ++index) {
|
||||
VarDeclaration *vd = sd->fields[index];
|
||||
|
||||
// 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;
|
||||
|
||||
// get initializer expression
|
||||
Expression *expr = (index < nexprs) ? exprs[index] : nullptr;
|
||||
Expression *expr =
|
||||
(index < elements->dim) ? elements->data[index] : nullptr;
|
||||
|
||||
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.
|
||||
// Consider the type union U7727A1 { int i; double d; } and
|
||||
// the declaration U7727A1 u = { d: 1.225 };
|
||||
// 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
|
||||
// union fields
|
||||
// with no explicit initializer.
|
||||
// union fields with no explicit initializer.
|
||||
IF_LOG Logger::println(
|
||||
"skipping overlapped field without init expr: %s %s (+%u)",
|
||||
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
|
||||
if (vd->offset != offset) {
|
||||
if (vd->offset != offset)
|
||||
voidptr = write_zeroes(voidptr, offset, vd->offset);
|
||||
}
|
||||
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)",
|
||||
vd->type->toChars(), vd->toChars(), vd->offset);
|
||||
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
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||
"vars, although it can easily be made to.");
|
||||
DLValue field(vd->type, DtoIndexAggregate(mem, sd, vd));
|
||||
|
||||
// store the initializer there
|
||||
DtoAssign(loc, &field, val, TOKconstruct, true);
|
||||
|
||||
if (expr && expr->isLvalue()) {
|
||||
// get initializer
|
||||
if (expr) {
|
||||
IF_LOG Logger::println("expr %llu = %s",
|
||||
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));
|
||||
}
|
||||
} 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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize trailing padding
|
||||
if (sd->structsize != offset) {
|
||||
if (sd->structsize != offset)
|
||||
voidptr = write_zeroes(voidptr, offset, sd->structsize);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1522,8 +1520,9 @@ public:
|
|||
exp = (*e->arguments)[0];
|
||||
}
|
||||
|
||||
DValue *iv = toElem(exp);
|
||||
DtoAssign(e->loc, &tmpvar, iv);
|
||||
// try to construct it in-place
|
||||
if (!toInPlaceConstruction(&tmpvar, exp))
|
||||
DtoAssign(e->loc, &tmpvar, toElem(exp));
|
||||
|
||||
// return as pointer-to
|
||||
result = new DImValue(e->type, mem);
|
||||
|
@ -2501,11 +2500,11 @@ public:
|
|||
|
||||
// index
|
||||
DValue *key = toElem(ekey);
|
||||
DValue *mem = DtoAAIndex(e->loc, vtype, result, key, true);
|
||||
DLValue *mem = DtoAAIndex(e->loc, vtype, result, key, true);
|
||||
|
||||
// store
|
||||
DValue *val = toElem(eval);
|
||||
DtoAssign(e->loc, mem, val);
|
||||
// try to construct it in-place
|
||||
if (!toInPlaceConstruction(mem, eval))
|
||||
DtoAssign(e->loc, mem, toElem(eval));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,9 +102,29 @@ void staticArrays()
|
|||
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
|
||||
void main()
|
||||
{
|
||||
structs();
|
||||
staticArrays();
|
||||
hierarchyOfLiterals();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue