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:
Martin 2016-07-20 21:31:03 +02:00
parent 9f728a4b4c
commit 126184a8b6
7 changed files with 107 additions and 109 deletions

View file

@ -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));

View file

@ -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);

View file

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;
}

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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));
}
}

View file

@ -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();
}