mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 09:00:33 +03:00
Merge remote-tracking branch 'origin/master' into pre-monorepo
Conflicts: gen/toir.cpp runtime/druntime
This commit is contained in:
commit
dd5f696d2e
32 changed files with 236 additions and 115 deletions
|
@ -185,9 +185,9 @@ public:
|
||||||
// from being repeated in its parameters. Might need to be
|
// from being repeated in its parameters. Might need to be
|
||||||
// extended, but GEPs/PHIs are the most common ones.
|
// extended, but GEPs/PHIs are the most common ones.
|
||||||
os << ", type = " << *val.getType();
|
os << ", type = " << *val.getType();
|
||||||
} else if (isa<AllocaInst>(&val)) {
|
} else if (auto ai = dyn_cast<AllocaInst>(&val)) {
|
||||||
os << ", size/byte = "
|
os << ", size/byte = "
|
||||||
<< DL.getTypeAllocSize(val.getType()->getContainedType(0));
|
<< DL.getTypeAllocSize(ai->getAllocatedType());
|
||||||
}
|
}
|
||||||
os << ']';
|
os << ']';
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,8 @@ struct RemoveStructPadding : ABIRewrite {
|
||||||
LLValue *lval = DtoAlloca(dty, ".RemoveStructPadding_dump");
|
LLValue *lval = DtoAlloca(dty, ".RemoveStructPadding_dump");
|
||||||
// Make sure the padding is zero, so struct comparisons work.
|
// Make sure the padding is zero, so struct comparisons work.
|
||||||
// TODO: Only do this if there's padding, and/or only initialize padding.
|
// TODO: Only do this if there's padding, and/or only initialize padding.
|
||||||
DtoMemSetZero(lval, DtoConstSize_t(getTypeAllocSize(DtoType(dty))));
|
DtoMemSetZero(DtoType(dty), lval,
|
||||||
|
DtoConstSize_t(getTypeAllocSize(DtoType(dty))));
|
||||||
DtoPaddedStruct(dty->toBasetype(), v, lval);
|
DtoPaddedStruct(dty->toBasetype(), v, lval);
|
||||||
return lval;
|
return lval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,7 +364,7 @@ void X86_64TargetABI::vaCopy(DLValue *dest, DValue *src) {
|
||||||
DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType())));
|
DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType())));
|
||||||
// Then fill the new struct with a bitcopy of the source struct.
|
// Then fill the new struct with a bitcopy of the source struct.
|
||||||
// `src` is a __va_list_tag* pointer to the source struct.
|
// `src` is a __va_list_tag* pointer to the source struct.
|
||||||
DtoMemCpy(valistmem, DtoRVal(src));
|
DtoMemCpy(getValistType(), valistmem, DtoRVal(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *X86_64TargetABI::prepareVaArg(DLValue *ap) {
|
LLValue *X86_64TargetABI::prepareVaArg(DLValue *ap) {
|
||||||
|
|
|
@ -208,7 +208,7 @@ LLValue *TargetABI::prepareVaStart(DLValue *ap) {
|
||||||
void TargetABI::vaCopy(DLValue *dest, DValue *src) {
|
void TargetABI::vaCopy(DLValue *dest, DValue *src) {
|
||||||
LLValue *llDest = DtoLVal(dest);
|
LLValue *llDest = DtoLVal(dest);
|
||||||
if (src->isLVal()) {
|
if (src->isLVal()) {
|
||||||
DtoMemCpy(llDest, DtoLVal(src));
|
DtoMemCpy(DtoType(dest->type), llDest, DtoLVal(src));
|
||||||
} else {
|
} else {
|
||||||
DtoStore(DtoRVal(src), llDest);
|
DtoStore(DtoRVal(src), llDest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,14 +28,12 @@
|
||||||
#include "ir/irfunction.h"
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
|
|
||||||
static void DtoSetArray(DValue *array, LLValue *dim, LLValue *ptr);
|
static void DtoSetArray(DValue *array, DValue *rhs);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
LLValue *DtoSlice(LLValue *ptr, LLValue *length, LLType *elemType = nullptr) {
|
LLValue *DtoSlice(LLValue *ptr, LLValue *length, LLType *elemType) {
|
||||||
if (!elemType)
|
|
||||||
elemType = ptr->getType()->getContainedType(0);
|
|
||||||
elemType = i1ToI8(voidToI8(elemType));
|
elemType = i1ToI8(voidToI8(elemType));
|
||||||
return DtoAggrPair(length, DtoBitCast(ptr, elemType->getPointerTo()));
|
return DtoAggrPair(length, DtoBitCast(ptr, elemType->getPointerTo()));
|
||||||
}
|
}
|
||||||
|
@ -44,7 +42,7 @@ LLValue *DtoSlice(Expression *e) {
|
||||||
DValue *dval = toElem(e);
|
DValue *dval = toElem(e);
|
||||||
if (dval->type->toBasetype()->ty == TY::Tsarray) {
|
if (dval->type->toBasetype()->ty == TY::Tsarray) {
|
||||||
// Convert static array to slice
|
// Convert static array to slice
|
||||||
return DtoSlice(DtoLVal(dval), DtoArrayLen(dval));
|
return DtoSlice(DtoLVal(dval), DtoArrayLen(dval), DtoType(dval->type->nextOf()));
|
||||||
}
|
}
|
||||||
return DtoRVal(dval);
|
return DtoRVal(dval);
|
||||||
}
|
}
|
||||||
|
@ -218,7 +216,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
if (rhs->isNull()) {
|
if (rhs->isNull()) {
|
||||||
DtoSetArrayToNull(lhs);
|
DtoSetArrayToNull(lhs);
|
||||||
} else {
|
} else {
|
||||||
DtoSetArray(lhs, DtoArrayLen(rhs), DtoArrayPtr(rhs));
|
DtoSetArray(lhs, rhs);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +252,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
const size_t elementSize = getTypeAllocSize(DtoMemType(elemType));
|
const size_t elementSize = getTypeAllocSize(DtoMemType(elemType));
|
||||||
if (rhs->isNull()) {
|
if (rhs->isNull()) {
|
||||||
LLValue *lhsSize = computeSize(lhsLength, elementSize);
|
LLValue *lhsSize = computeSize(lhsLength, elementSize);
|
||||||
DtoMemSetZero(lhsPtr, lhsSize);
|
DtoMemSetZero(getI8Type(), lhsPtr, lhsSize);
|
||||||
} else {
|
} else {
|
||||||
bool knownInBounds =
|
bool knownInBounds =
|
||||||
isConstructing || (t->ty == TY::Tsarray && t2->ty == TY::Tsarray);
|
isConstructing || (t->ty == TY::Tsarray && t2->ty == TY::Tsarray);
|
||||||
|
@ -274,16 +272,16 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
} else if (isConstructing) {
|
} else if (isConstructing) {
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||||
gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(loc, elemType),
|
gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(loc, elemType),
|
||||||
DtoSlice(rhsPtr, rhsLength),
|
DtoSlice(rhsPtr, rhsLength, getI8Type()),
|
||||||
DtoSlice(lhsPtr, lhsLength));
|
DtoSlice(lhsPtr, lhsLength, getI8Type()));
|
||||||
} else { // assigning
|
} else { // assigning
|
||||||
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
||||||
LLFunction *fn = getRuntimeFunction(
|
LLFunction *fn = getRuntimeFunction(
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(loc, elemType), DtoSlice(rhsPtr, rhsLength),
|
fn, DtoTypeInfoOf(loc, elemType), DtoSlice(rhsPtr, rhsLength, getI8Type()),
|
||||||
DtoSlice(lhsPtr, lhsLength), DtoBitCast(tmpSwap, getVoidPtrType()));
|
DtoSlice(lhsPtr, lhsLength, getI8Type()), DtoBitCast(tmpSwap, getVoidPtrType()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// scalar rhs:
|
// scalar rhs:
|
||||||
|
@ -295,7 +293,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
if (!needsDestruction && !needsPostblit) {
|
if (!needsDestruction && !needsPostblit) {
|
||||||
// fast version
|
// fast version
|
||||||
const size_t lhsElementSize =
|
const size_t lhsElementSize =
|
||||||
getTypeAllocSize(realLhsPtr->getType()->getContainedType(0));
|
getTypeAllocSize(DtoMemType(lhs->type->nextOf()));
|
||||||
LLType *rhsType = DtoMemType(t2);
|
LLType *rhsType = DtoMemType(t2);
|
||||||
const size_t rhsSize = getTypeAllocSize(rhsType);
|
const size_t rhsSize = getTypeAllocSize(rhsType);
|
||||||
LLValue *actualPtr = DtoBitCast(realLhsPtr, rhsType->getPointerTo());
|
LLValue *actualPtr = DtoBitCast(realLhsPtr, rhsType->getPointerTo());
|
||||||
|
@ -323,13 +321,13 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void DtoSetArray(DValue *array, LLValue *dim, LLValue *ptr) {
|
static void DtoSetArray(DValue *array, DValue *rhs) {
|
||||||
IF_LOG Logger::println("SetArray");
|
IF_LOG Logger::println("SetArray");
|
||||||
LLValue *arr = DtoLVal(array);
|
LLValue *arr = DtoLVal(array);
|
||||||
LLType *s = isaStruct(arr->getType()->getContainedType(0));
|
LLType *s = DtoType(array->type);
|
||||||
assert(s);
|
assert(s);
|
||||||
DtoStore(dim, DtoGEP(s, arr, 0u, 0));
|
DtoStore(DtoArrayLen(rhs), DtoGEP(s, arr, 0u, 0));
|
||||||
DtoStore(ptr, DtoGEP(s, arr, 0, 1));
|
DtoStore(DtoArrayPtr(rhs), DtoGEP(s, arr, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -829,7 +827,7 @@ DSliceValue *DtoCatAssignArray(const Loc &loc, DValue *arr, Expression *exp) {
|
||||||
LLValue *newArray = gIR->CreateCallOrInvoke(
|
LLValue *newArray = gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(loc, arrayType),
|
fn, DtoTypeInfoOf(loc, arrayType),
|
||||||
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
|
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
|
||||||
DtoAggrPaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
|
DtoSlicePaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
|
||||||
".appendedArray");
|
".appendedArray");
|
||||||
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
|
@ -921,10 +919,12 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
|
||||||
|
|
||||||
auto loadArray = [fn](Expression* e, int paramTypeIdx) {
|
auto loadArray = [fn](Expression* e, int paramTypeIdx) {
|
||||||
DValue * dval = toElem(e);
|
DValue * dval = toElem(e);
|
||||||
LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(e));
|
LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(dval));
|
||||||
return DtoAggrPaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
|
return DtoSlicePaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
|
||||||
};
|
};
|
||||||
|
// byte[] x
|
||||||
args.push_back(loadArray(exp1,1));
|
args.push_back(loadArray(exp1,1));
|
||||||
|
// byte[] y
|
||||||
args.push_back(loadArray(exp2,2));
|
args.push_back(loadArray(exp2,2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,9 +988,9 @@ LLValue *DtoArrayEqCmp_impl(const Loc &loc, const char *func, DValue *l,
|
||||||
LLSmallVector<LLValue *, 3> args;
|
LLSmallVector<LLValue *, 3> args;
|
||||||
|
|
||||||
// get values, reinterpret cast to void[]
|
// get values, reinterpret cast to void[]
|
||||||
args.push_back(DtoAggrPaint(DtoRVal(l),
|
args.push_back(DtoSlicePaint(DtoRVal(l),
|
||||||
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
||||||
args.push_back(DtoAggrPaint(DtoRVal(r),
|
args.push_back(DtoSlicePaint(DtoRVal(r),
|
||||||
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
||||||
|
|
||||||
// pass array typeinfo ?
|
// pass array typeinfo ?
|
||||||
|
@ -1066,12 +1066,12 @@ bool validCompareWithMemcmp(DValue *l, DValue *r) {
|
||||||
|
|
||||||
// Create a call instruction to memcmp.
|
// Create a call instruction to memcmp.
|
||||||
llvm::CallInst *callMemcmp(const Loc &loc, IRState &irs, LLValue *l_ptr,
|
llvm::CallInst *callMemcmp(const Loc &loc, IRState &irs, LLValue *l_ptr,
|
||||||
LLValue *r_ptr, LLValue *numElements) {
|
LLValue *r_ptr, LLValue *numElements, LLType *elemty) {
|
||||||
assert(l_ptr && r_ptr && numElements);
|
assert(l_ptr && r_ptr && numElements);
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "memcmp");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "memcmp");
|
||||||
assert(fn);
|
assert(fn);
|
||||||
auto sizeInBytes = numElements;
|
auto sizeInBytes = numElements;
|
||||||
size_t elementSize = getTypeAllocSize(l_ptr->getType()->getContainedType(0));
|
size_t elementSize = getTypeAllocSize(elemty);
|
||||||
if (elementSize != 1) {
|
if (elementSize != 1) {
|
||||||
sizeInBytes = irs.ir->CreateMul(sizeInBytes, DtoConstSize_t(elementSize));
|
sizeInBytes = irs.ir->CreateMul(sizeInBytes, DtoConstSize_t(elementSize));
|
||||||
}
|
}
|
||||||
|
@ -1101,7 +1101,7 @@ LLValue *DtoArrayEqCmp_memcmp(const Loc &loc, DValue *l, DValue *r,
|
||||||
(r->type->toBasetype()->ty == TY::Tsarray);
|
(r->type->toBasetype()->ty == TY::Tsarray);
|
||||||
if (staticArrayComparison) {
|
if (staticArrayComparison) {
|
||||||
// TODO: simply codegen when comparing static arrays with different length (int[3] == int[2])
|
// TODO: simply codegen when comparing static arrays with different length (int[3] == int[2])
|
||||||
return callMemcmp(loc, irs, l_ptr, r_ptr, l_length);
|
return callMemcmp(loc, irs, l_ptr, r_ptr, l_length, DtoMemType(l->type->nextOf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// First compare the array lengths
|
// First compare the array lengths
|
||||||
|
@ -1118,7 +1118,7 @@ LLValue *DtoArrayEqCmp_memcmp(const Loc &loc, DValue *l, DValue *r,
|
||||||
// The array comparison is UB for non-zero length, and memcmp will correctly
|
// The array comparison is UB for non-zero length, and memcmp will correctly
|
||||||
// return 0 (equality) when the length is zero.
|
// return 0 (equality) when the length is zero.
|
||||||
irs.ir->SetInsertPoint(memcmpBB);
|
irs.ir->SetInsertPoint(memcmpBB);
|
||||||
auto memcmpAnswer = callMemcmp(loc, irs, l_ptr, r_ptr, l_length);
|
auto memcmpAnswer = callMemcmp(loc, irs, l_ptr, r_ptr, l_length, DtoMemType(l->type->nextOf()));
|
||||||
irs.ir->CreateBr(memcmpEndBB);
|
irs.ir->CreateBr(memcmpEndBB);
|
||||||
|
|
||||||
// Merge the result of length check and memcmp call into a phi node.
|
// Merge the result of length check and memcmp call into a phi node.
|
||||||
|
|
|
@ -267,10 +267,12 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
||||||
arg_map[i] = --input_idx;
|
arg_map[i] = --input_idx;
|
||||||
asmStmt->in.ops.push_back(arg_val);
|
asmStmt->in.ops.push_back(arg_val);
|
||||||
input_constraints.push_back(cns);
|
input_constraints.push_back(cns);
|
||||||
|
asmStmt->in.dTypes.push_back(arg->expr->type);
|
||||||
} else {
|
} else {
|
||||||
arg_map[i] = n_outputs++;
|
arg_map[i] = n_outputs++;
|
||||||
asmStmt->out.ops.push_back(arg_val);
|
asmStmt->out.ops.push_back(arg_val);
|
||||||
output_constraints.push_back(cns);
|
output_constraints.push_back(cns);
|
||||||
|
asmStmt->out.dTypes.push_back(arg->expr->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +369,7 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
||||||
// numbering.
|
// numbering.
|
||||||
input_constraints.push_back(ss.str());
|
input_constraints.push_back(ss.str());
|
||||||
asmStmt->in.ops.push_back(asmStmt->out.ops[n]);
|
asmStmt->in.ops.push_back(asmStmt->out.ops[n]);
|
||||||
|
asmStmt->in.dTypes.push_back(asmStmt->out.dTypes[n]);
|
||||||
}
|
}
|
||||||
asmStmt->out.c += oc;
|
asmStmt->out.c += oc;
|
||||||
asmStmt->out.c += ",";
|
asmStmt->out.c += ",";
|
||||||
|
@ -549,6 +552,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
// FIXME: Store the value -> label mapping somewhere, so it can be
|
// FIXME: Store the value -> label mapping somewhere, so it can be
|
||||||
// referenced later
|
// referenced later
|
||||||
outSetterStmt->in.ops.push_back(DtoConstUint(n_goto));
|
outSetterStmt->in.ops.push_back(DtoConstUint(n_goto));
|
||||||
|
outSetterStmt->in.dTypes.push_back(Type::tuns32);
|
||||||
outSetterStmt->in.c += "i,";
|
outSetterStmt->in.c += "i,";
|
||||||
code << asmGotoEnd;
|
code << asmGotoEnd;
|
||||||
|
|
||||||
|
@ -564,6 +568,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
// setup variable for output from asm
|
// setup variable for output from asm
|
||||||
outSetterStmt->out.c = "=*m,";
|
outSetterStmt->out.c = "=*m,";
|
||||||
outSetterStmt->out.ops.push_back(jump_target);
|
outSetterStmt->out.ops.push_back(jump_target);
|
||||||
|
outSetterStmt->out.dTypes.push_back(Type::tuns32);
|
||||||
|
|
||||||
asmblock->s.push_back(outSetterStmt);
|
asmblock->s.push_back(outSetterStmt);
|
||||||
} else {
|
} else {
|
||||||
|
@ -586,8 +591,10 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
|
|
||||||
// build asm block
|
// build asm block
|
||||||
struct ArgBlock {
|
struct ArgBlock {
|
||||||
|
ArgBlock() = default;
|
||||||
std::vector<LLValue *> args;
|
std::vector<LLValue *> args;
|
||||||
std::vector<LLType *> types;
|
std::vector<LLType *> types;
|
||||||
|
std::vector<Type *> dTypes;
|
||||||
std::string c;
|
std::string c;
|
||||||
} in, out;
|
} in, out;
|
||||||
std::string clobbers;
|
std::string clobbers;
|
||||||
|
@ -603,6 +610,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
for (size_t j = 0; j < onn; ++j) {
|
for (size_t j = 0; j < onn; ++j) {
|
||||||
out.args.push_back(a->out.ops[j]);
|
out.args.push_back(a->out.ops[j]);
|
||||||
out.types.push_back(a->out.ops[j]->getType());
|
out.types.push_back(a->out.ops[j]->getType());
|
||||||
|
out.dTypes.push_back(a->out.dTypes[j]);
|
||||||
}
|
}
|
||||||
if (!a->out.c.empty()) {
|
if (!a->out.c.empty()) {
|
||||||
out.c += a->out.c;
|
out.c += a->out.c;
|
||||||
|
@ -619,6 +627,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
for (size_t j = 0; j < inn; ++j) {
|
for (size_t j = 0; j < inn; ++j) {
|
||||||
in.args.push_back(a->in.ops[j]);
|
in.args.push_back(a->in.ops[j]);
|
||||||
in.types.push_back(a->in.ops[j]->getType());
|
in.types.push_back(a->in.ops[j]->getType());
|
||||||
|
in.dTypes.push_back(a->in.dTypes[j]);
|
||||||
}
|
}
|
||||||
if (!a->in.c.empty()) {
|
if (!a->in.c.empty()) {
|
||||||
in.c += a->in.c;
|
in.c += a->in.c;
|
||||||
|
@ -669,6 +678,33 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
args.insert(args.end(), out.args.begin(), out.args.end());
|
args.insert(args.end(), out.args.begin(), out.args.end());
|
||||||
args.insert(args.end(), in.args.begin(), in.args.end());
|
args.insert(args.end(), in.args.begin(), in.args.end());
|
||||||
|
|
||||||
|
auto constraintInfo = llvm::InlineAsm::ParseConstraints(out.c);
|
||||||
|
assert(constraintInfo.size() >= out.dTypes.size() + in.dTypes.size());
|
||||||
|
std::vector<LLType *> indirectTypes;
|
||||||
|
indirectTypes.reserve(out.dTypes.size() + in.dTypes.size());
|
||||||
|
size_t i = asmblock->retn;
|
||||||
|
|
||||||
|
for (Type *t : out.dTypes) {
|
||||||
|
assert(constraintInfo[i].Type == llvm::InlineAsm::ConstraintPrefix::isOutput);
|
||||||
|
if (constraintInfo[i].isIndirect) {
|
||||||
|
if (TypePointer *pt = t->isTypePointer())
|
||||||
|
indirectTypes.push_back(DtoMemType(pt->nextOf()));
|
||||||
|
else
|
||||||
|
indirectTypes.push_back(DtoMemType(t));
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (Type *t : in.dTypes) {
|
||||||
|
assert(constraintInfo[i].Type == llvm::InlineAsm::ConstraintPrefix::isInput);
|
||||||
|
if (constraintInfo[i].isIndirect) {
|
||||||
|
if (TypePointer *pt = t->isTypePointer())
|
||||||
|
indirectTypes.push_back(DtoType(pt->nextOf()));
|
||||||
|
else
|
||||||
|
indirectTypes.push_back(DtoType(t));
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
IF_LOG {
|
IF_LOG {
|
||||||
Logger::cout() << "Arguments:" << '\n';
|
Logger::cout() << "Arguments:" << '\n';
|
||||||
Logger::indent();
|
Logger::indent();
|
||||||
|
@ -685,9 +721,21 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
Logger::undent();
|
Logger::undent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (; i < constraintInfo.size(); i++) {
|
||||||
|
if (!constraintInfo[i].isIndirect)
|
||||||
|
continue;
|
||||||
|
llvm::errs() << "unhandled indirect constraint in" << out.c << "\nindex i = " << i << '\n';
|
||||||
|
llvm::errs() << "function type = " << *fty << '\n';
|
||||||
|
for (size_t j = 0; j < indirectTypes.size(); j++) {
|
||||||
|
llvm::errs() << " " << *(indirectTypes[j]) << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("unhandled indirect constraint");
|
||||||
|
}
|
||||||
|
|
||||||
llvm::InlineAsm *ia = llvm::InlineAsm::get(fty, code, out.c, true);
|
llvm::InlineAsm *ia = llvm::InlineAsm::get(fty, code, out.c, true);
|
||||||
|
|
||||||
auto call = p->createInlineAsmCall(stmt->loc, ia, args, {});
|
auto call = p->createInlineAsmCall(stmt->loc, ia, args, indirectTypes);
|
||||||
if (!retty->isVoidTy()) {
|
if (!retty->isVoidTy()) {
|
||||||
call->setName("asm");
|
call->setName("asm");
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
|
||||||
LLValue *mem;
|
LLValue *mem;
|
||||||
bool doInit = true;
|
bool doInit = true;
|
||||||
if (newexp->onstack) {
|
if (newexp->onstack) {
|
||||||
mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), tc->sym->alignsize,
|
mem = DtoRawAlloca(getIrAggr(tc->sym)->getLLStructType(), tc->sym->alignsize,
|
||||||
".newclass_alloca");
|
".newclass_alloca");
|
||||||
} else {
|
} else {
|
||||||
const bool useEHAlloc = global.params.ehnogc && newexp->thrownew;
|
const bool useEHAlloc = global.params.ehnogc && newexp->thrownew;
|
||||||
|
@ -145,15 +145,14 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
|
||||||
|
|
||||||
// Set vtable field. Doing this seperately might be optimized better.
|
// Set vtable field. Doing this seperately might be optimized better.
|
||||||
LLValue *tmp = DtoGEP(st, dst, 0u, 0, "vtbl");
|
LLValue *tmp = DtoGEP(st, dst, 0u, 0, "vtbl");
|
||||||
LLValue *val =
|
LLValue *val = irClass->getVtblSymbol();
|
||||||
DtoBitCast(irClass->getVtblSymbol(), tmp->getType()->getContainedType(0));
|
|
||||||
DtoStore(val, tmp);
|
DtoStore(val, tmp);
|
||||||
|
|
||||||
// For D classes, set the monitor field to null.
|
// For D classes, set the monitor field to null.
|
||||||
const bool isCPPclass = tc->sym->isCPPclass() ? true : false;
|
const bool isCPPclass = tc->sym->isCPPclass() ? true : false;
|
||||||
if (!isCPPclass) {
|
if (!isCPPclass) {
|
||||||
tmp = DtoGEP(st, dst, 0, 1, "monitor");
|
tmp = DtoGEP(st, dst, 0, 1, "monitor");
|
||||||
val = LLConstant::getNullValue(tmp->getType()->getContainedType(0));
|
val = LLConstant::getNullValue(getVoidPtrType());
|
||||||
DtoStore(val, tmp);
|
DtoStore(val, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class DComputeTarget {
|
||||||
public:
|
public:
|
||||||
llvm::LLVMContext &ctx;
|
llvm::LLVMContext &ctx;
|
||||||
int tversion; // OpenCL or CUDA CC version:major*100 + minor*10
|
int tversion; // OpenCL or CUDA CC version:major*100 + minor*10
|
||||||
enum ID { Host = 0, OpenCL = 1, CUDA = 2 };
|
enum class ID { Host = 0, OpenCL = 1, CUDA = 2 };
|
||||||
ID target; // ID for codegen time conditional compilation.
|
ID target; // ID for codegen time conditional compilation.
|
||||||
const char *short_name;
|
const char *short_name;
|
||||||
const char *binSuffix;
|
const char *binSuffix;
|
||||||
|
|
|
@ -26,7 +26,7 @@ class TargetCUDA : public DComputeTarget {
|
||||||
public:
|
public:
|
||||||
TargetCUDA(llvm::LLVMContext &c, int sm)
|
TargetCUDA(llvm::LLVMContext &c, int sm)
|
||||||
: DComputeTarget(
|
: DComputeTarget(
|
||||||
c, sm, CUDA, "cuda", "ptx", createNVPTXABI(),
|
c, sm, ID::CUDA, "cuda", "ptx", createNVPTXABI(),
|
||||||
|
|
||||||
// Map from nominal DCompute address space to NVPTX address space.
|
// Map from nominal DCompute address space to NVPTX address space.
|
||||||
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
|
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
|
||||||
|
|
|
@ -42,7 +42,7 @@ class TargetOCL : public DComputeTarget {
|
||||||
bool usedImage;
|
bool usedImage;
|
||||||
public:
|
public:
|
||||||
TargetOCL(llvm::LLVMContext &c, int oclversion)
|
TargetOCL(llvm::LLVMContext &c, int oclversion)
|
||||||
: DComputeTarget(c, oclversion, OpenCL, "ocl", "spv", createSPIRVABI(),
|
: DComputeTarget(c, oclversion, ID::OpenCL, "ocl", "spv", createSPIRVABI(),
|
||||||
// Map from nomimal DCompute address space to OpenCL
|
// Map from nomimal DCompute address space to OpenCL
|
||||||
// address. For OpenCL this is a no-op.
|
// address. For OpenCL this is a no-op.
|
||||||
{{0, 1, 2, 3, 4}}) {
|
{{0, 1, 2, 3, 4}}) {
|
||||||
|
|
|
@ -213,16 +213,6 @@ public:
|
||||||
addr.push_back(offset);
|
addr.push_back(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void OpOffset(T &addr, llvm::Value *val, int index) {
|
|
||||||
if (!global.params.symdebug) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::StructType *type = isaStruct(val->getType()->getContainedType(0));
|
|
||||||
assert(type);
|
|
||||||
OpOffset(addr, type, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void OpDeref(T &addr) {
|
template <typename T> void OpDeref(T &addr) {
|
||||||
if (!global.params.symdebug) {
|
if (!global.params.symdebug) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -131,7 +131,7 @@ DRValue *DLValue::getRVal() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *rval = DtoLoad(val->getType()->getPointerElementType(), val);
|
LLValue *rval = DtoLoad(DtoMemType(type), val);
|
||||||
|
|
||||||
const auto ty = type->toBasetype()->ty;
|
const auto ty = type->toBasetype()->ty;
|
||||||
if (ty == TY::Tbool) {
|
if (ty == TY::Tbool) {
|
||||||
|
@ -220,3 +220,35 @@ void DBitFieldLValue::store(LLValue *value) {
|
||||||
const auto newVal = gIR->ir->CreateOr(maskedOldVal, bfVal);
|
const auto newVal = gIR->ir->CreateOr(maskedOldVal, bfVal);
|
||||||
gIR->ir->CreateAlignedStore(newVal, ptr, LLMaybeAlign(1));
|
gIR->ir->CreateAlignedStore(newVal, ptr, LLMaybeAlign(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DDcomputeLValue::DDcomputeLValue(Type *t, llvm::Type * llt, LLValue *v) : DLValue(t, v) {
|
||||||
|
lltype = llt;
|
||||||
|
}
|
||||||
|
DRValue *DDcomputeLValue::getRVal() {
|
||||||
|
if (DtoIsInMemoryOnly(type)) {
|
||||||
|
llvm_unreachable("getRVal() for memory-only type");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue *rval = DtoLoad(lltype, val);
|
||||||
|
|
||||||
|
const auto ty = type->toBasetype()->ty;
|
||||||
|
if (ty == TY::Tbool) {
|
||||||
|
assert(rval->getType() == llvm::Type::getInt8Ty(gIR->context()));
|
||||||
|
|
||||||
|
if (isOptimizationEnabled()) {
|
||||||
|
// attach range metadata for i8 being loaded: [0, 2)
|
||||||
|
llvm::MDBuilder mdBuilder(gIR->context());
|
||||||
|
llvm::cast<llvm::LoadInst>(rval)->setMetadata(
|
||||||
|
llvm::LLVMContext::MD_range,
|
||||||
|
mdBuilder.createRange(llvm::APInt(8, 0), llvm::APInt(8, 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate to i1
|
||||||
|
rval = gIR->ir->CreateTrunc(rval, llvm::Type::getInt1Ty(gIR->context()));
|
||||||
|
} else if (ty == TY::Tarray) {
|
||||||
|
return new DSliceValue(type, rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DImValue(type, rval);
|
||||||
|
}
|
||||||
|
|
12
gen/dvalue.h
12
gen/dvalue.h
|
@ -37,6 +37,7 @@ class DNullValue;
|
||||||
class DLValue;
|
class DLValue;
|
||||||
class DSpecialRefValue;
|
class DSpecialRefValue;
|
||||||
class DBitFieldLValue;
|
class DBitFieldLValue;
|
||||||
|
class DDcomputeLValue;
|
||||||
class DSliceValue;
|
class DSliceValue;
|
||||||
class DFuncValue;
|
class DFuncValue;
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ public:
|
||||||
virtual DLValue *isLVal() { return nullptr; }
|
virtual DLValue *isLVal() { return nullptr; }
|
||||||
virtual DSpecialRefValue *isSpecialRef() { return nullptr; }
|
virtual DSpecialRefValue *isSpecialRef() { return nullptr; }
|
||||||
virtual DBitFieldLValue *isBitFieldLVal() { return nullptr; }
|
virtual DBitFieldLValue *isBitFieldLVal() { return nullptr; }
|
||||||
|
virtual DDcomputeLValue *isDDcomputeLVal() { return nullptr; }
|
||||||
|
|
||||||
virtual DRValue *isRVal() { return nullptr; }
|
virtual DRValue *isRVal() { return nullptr; }
|
||||||
virtual DImValue *isIm() { return nullptr; }
|
virtual DImValue *isIm() { return nullptr; }
|
||||||
|
@ -199,5 +201,15 @@ private:
|
||||||
// byte the highest bit is in
|
// byte the highest bit is in
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents lvalues of address spaced pointers and pointers
|
||||||
|
/// to address spaces other then 0
|
||||||
|
class DDcomputeLValue : public DLValue {
|
||||||
|
public:
|
||||||
|
llvm::Type *lltype;
|
||||||
|
DDcomputeLValue *isDDcomputeLVal() override { return this; }
|
||||||
|
DDcomputeLValue(Type *t, llvm::Type * llt, llvm::Value *v);
|
||||||
|
DRValue *getRVal() override;
|
||||||
|
};
|
||||||
|
|
||||||
inline llvm::Value *DtoRVal(DValue *v) { return v->getRVal()->val; }
|
inline llvm::Value *DtoRVal(DValue *v) { return v->getRVal()->val; }
|
||||||
llvm::Value *DtoLVal(DValue *v);
|
llvm::Value *DtoLVal(DValue *v);
|
||||||
|
|
|
@ -488,7 +488,7 @@ void applyTargetMachineAttributes(llvm::Function &func,
|
||||||
const auto dcompute = gIR->dcomputetarget;
|
const auto dcompute = gIR->dcomputetarget;
|
||||||
|
|
||||||
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
|
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
|
||||||
if (dcompute && dcompute->target == DComputeTarget::OpenCL)
|
if (dcompute && dcompute->target == DComputeTarget::ID::OpenCL)
|
||||||
return;
|
return;
|
||||||
const auto cpu = dcompute ? "" : target.getTargetCPU();
|
const auto cpu = dcompute ? "" : target.getTargetCPU();
|
||||||
const auto features = dcompute ? "" : target.getTargetFeatureString();
|
const auto features = dcompute ? "" : target.getTargetFeatureString();
|
||||||
|
|
|
@ -136,7 +136,7 @@ LLConstant *
|
||||||
IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
||||||
LLConstant *initializer,
|
LLConstant *initializer,
|
||||||
Dsymbol *symbolForLinkageAndVisibility) {
|
Dsymbol *symbolForLinkageAndVisibility) {
|
||||||
if (initializer->getType() == globalVar->getType()->getContainedType(0)) {
|
if (initializer->getType() == globalVar->getValueType()) {
|
||||||
defineGlobal(globalVar, initializer, symbolForLinkageAndVisibility);
|
defineGlobal(globalVar, initializer, symbolForLinkageAndVisibility);
|
||||||
return globalVar;
|
return globalVar;
|
||||||
}
|
}
|
||||||
|
@ -273,18 +273,14 @@ IRState::createInlineAsmCall(const Loc &loc, llvm::InlineAsm *ia,
|
||||||
// a non-indirect output constraint (=> return value of call) shifts the
|
// a non-indirect output constraint (=> return value of call) shifts the
|
||||||
// constraint/argument index mapping
|
// constraint/argument index mapping
|
||||||
ptrdiff_t i = call->getType()->isVoidTy() ? 0 : -1;
|
ptrdiff_t i = call->getType()->isVoidTy() ? 0 : -1;
|
||||||
size_t indirectIdx = 0, indirectLen = indirectTypes.size();
|
size_t indirectIdx = 0;
|
||||||
|
|
||||||
for (const auto &constraintInfo : ia->ParseConstraints()) {
|
for (const auto &constraintInfo : ia->ParseConstraints()) {
|
||||||
if (constraintInfo.isIndirect) {
|
if (constraintInfo.isIndirect) {
|
||||||
llvm::Type *indirectType = indirectLen != 0 ?
|
|
||||||
indirectTypes[indirectIdx] :
|
|
||||||
args[i]->getType()->getPointerElementType();
|
|
||||||
|
|
||||||
call->addParamAttr(i, llvm::Attribute::get(
|
call->addParamAttr(i, llvm::Attribute::get(
|
||||||
context(),
|
context(),
|
||||||
llvm::Attribute::ElementType,
|
llvm::Attribute::ElementType,
|
||||||
indirectType));
|
indirectTypes[indirectIdx]));
|
||||||
++indirectIdx;
|
++indirectIdx;
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct IRAsmStmt {
|
||||||
struct Operands {
|
struct Operands {
|
||||||
std::string c; // contraint
|
std::string c; // contraint
|
||||||
std::vector<LLValue *> ops;
|
std::vector<LLValue *> ops;
|
||||||
|
std::vector<Type *> dTypes;
|
||||||
};
|
};
|
||||||
Operands out, in;
|
Operands out, in;
|
||||||
|
|
||||||
|
|
|
@ -414,7 +414,7 @@ void DtoAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
// time as to not emit an invalid (overlapping) memcpy on trivial
|
// time as to not emit an invalid (overlapping) memcpy on trivial
|
||||||
// struct self-assignments like 'A a; a = a;'.
|
// struct self-assignments like 'A a; a = a;'.
|
||||||
if (src != dst)
|
if (src != dst)
|
||||||
DtoMemCpy(dst, src);
|
DtoMemCpy(DtoType(lhs->type), dst, src);
|
||||||
}
|
}
|
||||||
} else if (t->ty == TY::Tarray || t->ty == TY::Tsarray) {
|
} else if (t->ty == TY::Tarray || t->ty == TY::Tsarray) {
|
||||||
DtoArrayAssign(loc, lhs, rhs, op, canSkipPostblit);
|
DtoArrayAssign(loc, lhs, rhs, op, canSkipPostblit);
|
||||||
|
@ -434,7 +434,7 @@ void DtoAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
Logger::cout() << "l : " << *l << '\n';
|
Logger::cout() << "l : " << *l << '\n';
|
||||||
Logger::cout() << "r : " << *r << '\n';
|
Logger::cout() << "r : " << *r << '\n';
|
||||||
}
|
}
|
||||||
r = DtoBitCast(r, l->getType()->getContainedType(0));
|
r = DtoBitCast(r, DtoType(lhs->type));
|
||||||
DtoStore(r, l);
|
DtoStore(r, l);
|
||||||
} else if (t->iscomplex()) {
|
} else if (t->iscomplex()) {
|
||||||
LLValue *dst = DtoLVal(lhs);
|
LLValue *dst = DtoLVal(lhs);
|
||||||
|
@ -447,7 +447,7 @@ void DtoAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
||||||
Logger::cout() << "lhs: " << *l << '\n';
|
Logger::cout() << "lhs: " << *l << '\n';
|
||||||
Logger::cout() << "rhs: " << *r << '\n';
|
Logger::cout() << "rhs: " << *r << '\n';
|
||||||
}
|
}
|
||||||
LLType *lit = l->getType()->getContainedType(0);
|
LLType *lit = DtoType(lhs->type);
|
||||||
if (r->getType() != lit) {
|
if (r->getType() != lit) {
|
||||||
r = DtoRVal(DtoCast(loc, rhs, lhs->type));
|
r = DtoRVal(DtoCast(loc, rhs, lhs->type));
|
||||||
IF_LOG {
|
IF_LOG {
|
||||||
|
@ -1882,10 +1882,12 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||||
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
|
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
|
||||||
|
|
||||||
LLValue *ptr = src;
|
LLValue *ptr = src;
|
||||||
|
LLType * ty = nullptr;
|
||||||
if (!isFieldIdx) {
|
if (!isFieldIdx) {
|
||||||
// Cast to void* to apply byte-wise offset from object start.
|
// Cast to void* to apply byte-wise offset from object start.
|
||||||
ptr = DtoBitCast(ptr, getVoidPtrType());
|
ptr = DtoBitCast(ptr, getVoidPtrType());
|
||||||
ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, off);
|
ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, off);
|
||||||
|
ty = DtoType(vd->type);
|
||||||
} else {
|
} else {
|
||||||
if (ad->structsize == 0) { // can happen for extern(C) structs
|
if (ad->structsize == 0) { // can happen for extern(C) structs
|
||||||
assert(off == 0);
|
assert(off == 0);
|
||||||
|
@ -1904,6 +1906,7 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||||
}
|
}
|
||||||
ptr = DtoBitCast(ptr, pst);
|
ptr = DtoBitCast(ptr, pst);
|
||||||
ptr = DtoGEP(st, ptr, 0, off);
|
ptr = DtoGEP(st, ptr, 0, off);
|
||||||
|
ty = isaStruct(st)->getElementType(off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,6 +1914,10 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||||
ptr = DtoBitCast(ptr, DtoPtrToType(vd->type));
|
ptr = DtoBitCast(ptr, DtoPtrToType(vd->type));
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "Pointer: " << *ptr << '\n';
|
IF_LOG Logger::cout() << "Pointer: " << *ptr << '\n';
|
||||||
|
if (auto p = isaPointer(ty)) {
|
||||||
|
if (p->getAddressSpace())
|
||||||
|
return new DDcomputeLValue(vd->type, p, ptr);
|
||||||
|
}
|
||||||
return new DLValue(vd->type, ptr);
|
return new DLValue(vd->type, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -503,17 +503,20 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
|
||||||
llvm::FunctionType *FT =
|
llvm::FunctionType *FT =
|
||||||
llvm::FunctionType::get(returnType, operandTypes, false);
|
llvm::FunctionType::get(returnType, operandTypes, false);
|
||||||
|
|
||||||
// make sure the constraints are valid
|
|
||||||
if (!llvm::InlineAsm::
|
|
||||||
#if LDC_LLVM_VER < 1500
|
#if LDC_LLVM_VER < 1500
|
||||||
Verify
|
// make sure the constraints are valid
|
||||||
#else
|
if (!llvm::InlineAsm::Verify(FT, constraints)) {
|
||||||
verify
|
|
||||||
#endif
|
|
||||||
(FT, constraints)) {
|
|
||||||
error(loc, "inline asm constraints are invalid");
|
error(loc, "inline asm constraints are invalid");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (auto err = llvm::InlineAsm::verify(FT, constraints)) {
|
||||||
|
error(loc, "inline asm constraints are invalid");
|
||||||
|
llvm::errs() << err;
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// build asm call
|
// build asm call
|
||||||
bool sideeffect = true;
|
bool sideeffect = true;
|
||||||
|
|
|
@ -149,7 +149,7 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
|
||||||
|
|
||||||
const auto offsetToNthField = [&val, &dwarfAddrOps, &currFrame](unsigned fieldIndex,
|
const auto offsetToNthField = [&val, &dwarfAddrOps, &currFrame](unsigned fieldIndex,
|
||||||
const char *name = "") {
|
const char *name = "") {
|
||||||
gIR->DBuilder.OpOffset(dwarfAddrOps, val, fieldIndex);
|
gIR->DBuilder.OpOffset(dwarfAddrOps, currFrame, fieldIndex);
|
||||||
val = DtoGEP(currFrame, val, 0, fieldIndex, name);
|
val = DtoGEP(currFrame, val, 0, fieldIndex, name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
||||||
// The parameter value is an alloca'd stack slot.
|
// The parameter value is an alloca'd stack slot.
|
||||||
// Copy to the nesting frame and leave the alloca for
|
// Copy to the nesting frame and leave the alloca for
|
||||||
// the optimizers to clean up.
|
// the optimizers to clean up.
|
||||||
DtoMemCpy(gep, parm->value);
|
DtoMemCpy(frameType->getContainedType(irLocal->nestedIndex), gep, parm->value);
|
||||||
gep->takeName(parm->value);
|
gep->takeName(parm->value);
|
||||||
parm->value = gep; // update variable lvalue
|
parm->value = gep; // update variable lvalue
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,7 +322,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be i8.
|
// Should be i8.
|
||||||
Ty = CB->getType()->getContainedType(0);
|
Ty = llvm::Type::getInt8Ty(CB->getContext());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ struct DComputeSemanticAnalyser : public StoppableVisitor {
|
||||||
if (auto ce = stmt->condition->isCallExp()) {
|
if (auto ce = stmt->condition->isCallExp()) {
|
||||||
if (ce->f && ce->f->ident == Id::dcReflect) {
|
if (ce->f && ce->f->ident == Id::dcReflect) {
|
||||||
auto arg1 = (DComputeTarget::ID)(*ce->arguments)[0]->toInteger();
|
auto arg1 = (DComputeTarget::ID)(*ce->arguments)[0]->toInteger();
|
||||||
if (arg1 == DComputeTarget::Host)
|
if (arg1 == DComputeTarget::ID::Host)
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,7 +364,7 @@ public:
|
||||||
auto arg2 = (*ce->arguments)[1]->toInteger();
|
auto arg2 = (*ce->arguments)[1]->toInteger();
|
||||||
auto dct = irs->dcomputetarget;
|
auto dct = irs->dcomputetarget;
|
||||||
if (!dct) {
|
if (!dct) {
|
||||||
return arg1 == DComputeTarget::Host;
|
return arg1 == DComputeTarget::ID::Host;
|
||||||
} else {
|
} else {
|
||||||
return arg1 == dct->target &&
|
return arg1 == dct->target &&
|
||||||
(!arg2 || arg2 == static_cast<dinteger_t>(dct->tversion));
|
(!arg2 || arg2 == static_cast<dinteger_t>(dct->tversion));
|
||||||
|
|
|
@ -188,7 +188,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
|
||||||
Logger::cout() << "expects: " << *paramType << '\n';
|
Logger::cout() << "expects: " << *paramType << '\n';
|
||||||
}
|
}
|
||||||
if (isaStruct(llVal)) {
|
if (isaStruct(llVal)) {
|
||||||
llVal = DtoAggrPaint(llVal, paramType);
|
llVal = DtoSlicePaint(llVal, paramType);
|
||||||
} else {
|
} else {
|
||||||
llVal = DtoBitCast(llVal, paramType);
|
llVal = DtoBitCast(llVal, paramType);
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
||||||
assert(ap);
|
assert(ap);
|
||||||
// variadic extern(D) function with implicit _argptr?
|
// variadic extern(D) function with implicit _argptr?
|
||||||
if (LLValue *argptrMem = p->func()->_argptr) {
|
if (LLValue *argptrMem = p->func()->_argptr) {
|
||||||
DtoMemCpy(DtoLVal(ap), argptrMem); // ap = _argptr
|
DtoMemCpy(DtoType(ap->type), DtoLVal(ap), argptrMem); // ap = _argptr
|
||||||
} else {
|
} else {
|
||||||
LLValue *llAp = gABI->prepareVaStart(ap);
|
LLValue *llAp = gABI->prepareVaStart(ap);
|
||||||
p->ir->CreateCall(GET_INTRINSIC_DECL(vastart), llAp, "");
|
p->ir->CreateCall(GET_INTRINSIC_DECL(vastart), llAp, "");
|
||||||
|
@ -395,7 +395,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
||||||
|
|
||||||
DValue *dval = toElem(exp1);
|
DValue *dval = toElem(exp1);
|
||||||
LLValue *ptr = DtoRVal(exp2);
|
LLValue *ptr = DtoRVal(exp2);
|
||||||
LLType *pointeeType = ptr->getType()->getContainedType(0);
|
LLType *pointeeType = DtoType(exp2->type->isTypePointer()->nextOf());
|
||||||
|
|
||||||
LLValue *val = nullptr;
|
LLValue *val = nullptr;
|
||||||
if (pointeeType->isIntegerTy()) {
|
if (pointeeType->isIntegerTy()) {
|
||||||
|
@ -482,7 +482,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
||||||
const bool isWeak = (*e->arguments)[5]->toInteger() != 0;
|
const bool isWeak = (*e->arguments)[5]->toInteger() != 0;
|
||||||
|
|
||||||
LLValue *ptr = DtoRVal(exp1);
|
LLValue *ptr = DtoRVal(exp1);
|
||||||
LLType *pointeeType = ptr->getType()->getContainedType(0);
|
LLType *pointeeType = DtoType(exp1->type->isTypePointer()->nextOf());
|
||||||
DValue *dcmp = toElem(exp2);
|
DValue *dcmp = toElem(exp2);
|
||||||
DValue *dval = toElem(exp3);
|
DValue *dval = toElem(exp3);
|
||||||
|
|
||||||
|
@ -708,11 +708,9 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index = args.size();
|
size_t index = args.size();
|
||||||
LLType *llArgType = *(llArgTypesBegin + index);
|
|
||||||
|
|
||||||
LLValue *pointer = sretPointer;
|
LLValue *pointer = sretPointer;
|
||||||
if (!pointer) {
|
if (!pointer) {
|
||||||
pointer = DtoRawAlloca(llArgType->getContainedType(0),
|
pointer = DtoRawAlloca(DtoType(tf->nextOf()),
|
||||||
DtoAlignment(resulttype), ".sret_tmp");
|
DtoAlignment(resulttype), ".sret_tmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,7 +956,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
if (tf->isref()) {
|
if (tf->isref()) {
|
||||||
retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo()));
|
retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo()));
|
||||||
} else {
|
} else {
|
||||||
retllval = DtoAggrPaint(retllval, DtoType(rbase));
|
retllval = DtoSlicePaint(retllval, DtoType(rbase));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ public:
|
||||||
result = base;
|
result = base;
|
||||||
} else {
|
} else {
|
||||||
const unsigned elemSize =
|
const unsigned elemSize =
|
||||||
gDataLayout->getTypeStoreSize(base->getType()->getContainedType(0));
|
gDataLayout->getTypeStoreSize(DtoType(e->var->type));
|
||||||
|
|
||||||
IF_LOG Logger::println("adding offset: %llu (elem size: %u)",
|
IF_LOG Logger::println("adding offset: %llu (elem size: %u)",
|
||||||
static_cast<unsigned long long>(e->offset),
|
static_cast<unsigned long long>(e->offset),
|
||||||
|
|
53
gen/toir.cpp
53
gen/toir.cpp
|
@ -65,8 +65,9 @@ bool walkPostorder(Expression *e, StoppableVisitor *v);
|
||||||
|
|
||||||
static LLValue *write_zeroes(LLValue *mem, unsigned start, unsigned end) {
|
static LLValue *write_zeroes(LLValue *mem, unsigned start, unsigned end) {
|
||||||
mem = DtoBitCast(mem, getVoidPtrType());
|
mem = DtoBitCast(mem, getVoidPtrType());
|
||||||
LLValue *gep = DtoGEP1(LLType::getInt8Ty(gIR->context()), mem, start, ".padding");
|
LLType *i8 = LLType::getInt8Ty(gIR->context());
|
||||||
DtoMemSetZero(gep, DtoConstSize_t(end - start));
|
LLValue *gep = DtoGEP1(i8, mem, start, ".padding");
|
||||||
|
DtoMemSetZero(i8, gep, DtoConstSize_t(end - start));
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,7 +547,7 @@ public:
|
||||||
Logger::println("performing aggregate zero initialization");
|
Logger::println("performing aggregate zero initialization");
|
||||||
assert(e->e2->toInteger() == 0);
|
assert(e->e2->toInteger() == 0);
|
||||||
LLValue *lval = DtoLVal(lhs);
|
LLValue *lval = DtoLVal(lhs);
|
||||||
DtoMemSetZero(lval);
|
DtoMemSetZero(DtoType(lhs->type), lval);
|
||||||
TypeStruct *ts = static_cast<TypeStruct *>(e->e1->type);
|
TypeStruct *ts = static_cast<TypeStruct *>(e->e1->type);
|
||||||
if (ts->sym->isNested() && ts->sym->vthis)
|
if (ts->sym->isNested() && ts->sym->vthis)
|
||||||
DtoResolveNestedContext(e->loc, ts->sym, lval);
|
DtoResolveNestedContext(e->loc, ts->sym, lval);
|
||||||
|
@ -843,7 +844,7 @@ public:
|
||||||
if (e->offset == 0) {
|
if (e->offset == 0) {
|
||||||
offsetValue = baseValue;
|
offsetValue = baseValue;
|
||||||
} else {
|
} else {
|
||||||
LLType *elemType = baseValue->getType()->getContainedType(0);
|
LLType *elemType = DtoType(base->type);
|
||||||
if (elemType->isSized()) {
|
if (elemType->isSized()) {
|
||||||
uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType);
|
uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType);
|
||||||
if (e->offset % elemSize == 0) {
|
if (e->offset % elemSize == 0) {
|
||||||
|
@ -948,6 +949,14 @@ public:
|
||||||
result = new DLValue(e->type, DtoBitCast(V, DtoPtrToType(e->type)));
|
result = new DLValue(e->type, DtoBitCast(V, DtoPtrToType(e->type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::PointerType * getWithSamePointeeType(llvm::PointerType *p, unsigned as) {
|
||||||
|
#if LDC_LLVM_VER >= 1300
|
||||||
|
return llvm::PointerType::getWithSamePointeeType(p, as);
|
||||||
|
#else
|
||||||
|
return p->getPointerElementType()->getPointerTo(as);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void visit(DotVarExp *e) override {
|
void visit(DotVarExp *e) override {
|
||||||
|
@ -985,14 +994,24 @@ public:
|
||||||
llvm_unreachable("Unknown DotVarExp type for VarDeclaration.");
|
llvm_unreachable("Unknown DotVarExp type for VarDeclaration.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ptr = DtoLVal(DtoIndexAggregate(aggrPtr, ad, vd));
|
auto ptr = DtoIndexAggregate(aggrPtr, ad, vd);
|
||||||
|
|
||||||
// special case for bit fields (no real lvalues)
|
// special case for bit fields (no real lvalues), and address spaced pointers
|
||||||
if (auto bf = vd->isBitFieldDeclaration()) {
|
if (auto bf = vd->isBitFieldDeclaration()) {
|
||||||
result = new DBitFieldLValue(e->type, ptr, bf);
|
result = new DBitFieldLValue(e->type, DtoLVal(ptr), bf);
|
||||||
|
} else if (auto d = ptr->isDDcomputeLVal()) {
|
||||||
|
LLType *ptrty = nullptr;
|
||||||
|
if (llvm::PointerType *p = isaPointer(d->lltype)) {
|
||||||
|
unsigned as = p->getAddressSpace();
|
||||||
|
ptrty = getWithSamePointeeType(isaPointer(DtoType(e->type)), as);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptrty = DtoType(e->type);
|
||||||
|
result = new DDcomputeLValue(e->type, i1ToI8(ptrty),
|
||||||
|
DtoBitCast(DtoLVal(d), DtoPtrToType(e->type)));
|
||||||
} else {
|
} else {
|
||||||
ptr = DtoBitCast(ptr, DtoPtrToType(e->type));
|
LLValue *p = DtoBitCast(DtoLVal(ptr), DtoPtrToType(e->type));
|
||||||
result = new DLValue(e->type, ptr);
|
result = new DLValue(e->type, p);
|
||||||
}
|
}
|
||||||
} else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) {
|
} else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) {
|
||||||
// This is a bit more convoluted than it would need to be, because it
|
// This is a bit more convoluted than it would need to be, because it
|
||||||
|
@ -1622,7 +1641,7 @@ public:
|
||||||
DtoDeleteClass(e->loc, dval); // sets dval to null
|
DtoDeleteClass(e->loc, dval); // sets dval to null
|
||||||
} else if (dval->isLVal()) {
|
} else if (dval->isLVal()) {
|
||||||
LLValue *lval = DtoLVal(dval);
|
LLValue *lval = DtoLVal(dval);
|
||||||
DtoStore(LLConstant::getNullValue(lval->getType()->getContainedType(0)),
|
DtoStore(LLConstant::getNullValue(DtoType(dval->type)),
|
||||||
lval);
|
lval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2301,12 +2320,12 @@ public:
|
||||||
dstMem = DtoAlloca(e->type, ".structliteral");
|
dstMem = DtoAlloca(e->type, ".structliteral");
|
||||||
|
|
||||||
if (sd->zeroInit()) {
|
if (sd->zeroInit()) {
|
||||||
DtoMemSetZero(dstMem);
|
DtoMemSetZero(DtoType(e->type), dstMem);
|
||||||
} else {
|
} else {
|
||||||
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
||||||
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
|
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
|
||||||
assert(dstMem->getType() == initsym->getType());
|
assert(dstMem->getType() == initsym->getType());
|
||||||
DtoMemCpy(dstMem, initsym);
|
DtoMemCpy(DtoType(e->type), dstMem, initsym);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DLValue(e->type, dstMem);
|
return new DLValue(e->type, dstMem);
|
||||||
|
@ -2456,7 +2475,7 @@ public:
|
||||||
LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
|
LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
|
||||||
LLConstant *slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
LLConstant *slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
||||||
slice = DtoConstSlice(DtoConstSize_t(e->keys->length), slice);
|
slice = DtoConstSlice(DtoConstSize_t(e->keys->length), slice);
|
||||||
LLValue *keysArray = DtoAggrPaint(slice, funcTy->getParamType(1));
|
LLValue *keysArray = DtoSlicePaint(slice, funcTy->getParamType(1));
|
||||||
|
|
||||||
initval = arrayConst(valuesInits, vtype);
|
initval = arrayConst(valuesInits, vtype);
|
||||||
globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false,
|
globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false,
|
||||||
|
@ -2464,7 +2483,7 @@ public:
|
||||||
initval, ".aaValuesStorage");
|
initval, ".aaValuesStorage");
|
||||||
slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
||||||
slice = DtoConstSlice(DtoConstSize_t(e->keys->length), slice);
|
slice = DtoConstSlice(DtoConstSize_t(e->keys->length), slice);
|
||||||
LLValue *valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
|
LLValue *valuesArray = DtoSlicePaint(slice, funcTy->getParamType(2));
|
||||||
|
|
||||||
LLValue *aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray,
|
LLValue *aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray,
|
||||||
valuesArray, "aa");
|
valuesArray, "aa");
|
||||||
|
@ -2574,7 +2593,7 @@ public:
|
||||||
DValue *ep = toElem(el);
|
DValue *ep = toElem(el);
|
||||||
LLValue *gep = DtoGEP(st, val, 0, i);
|
LLValue *gep = DtoGEP(st, val, 0, i);
|
||||||
if (DtoIsInMemoryOnly(el->type)) {
|
if (DtoIsInMemoryOnly(el->type)) {
|
||||||
DtoMemCpy(gep, DtoLVal(ep));
|
DtoMemCpy(st->getContainedType(i), gep, DtoLVal(ep));
|
||||||
} else if (el->type->ty != TY::Tvoid) {
|
} else if (el->type->ty != TY::Tvoid) {
|
||||||
DtoStoreZextI8(DtoRVal(ep), gep);
|
DtoStoreZextI8(DtoRVal(ep), gep);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2651,7 +2670,7 @@ public:
|
||||||
Type *srcElementType = tsrc->nextOf();
|
Type *srcElementType = tsrc->nextOf();
|
||||||
|
|
||||||
if (DtoMemType(elementType) == DtoMemType(srcElementType)) {
|
if (DtoMemType(elementType) == DtoMemType(srcElementType)) {
|
||||||
DtoMemCpy(dstMem, arrayPtr);
|
DtoMemCpy(dstType, dstMem, arrayPtr);
|
||||||
} else {
|
} else {
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
LLValue *gep = DtoGEP1(DtoMemType(e1->type->nextOf()), arrayPtr, i);
|
LLValue *gep = DtoGEP1(DtoMemType(e1->type->nextOf()), arrayPtr, i);
|
||||||
|
@ -2821,7 +2840,7 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
|
||||||
DtoResolveStruct(sd);
|
DtoResolveStruct(sd);
|
||||||
if (sd->zeroInit()) {
|
if (sd->zeroInit()) {
|
||||||
Logger::println("success, zeroing out");
|
Logger::println("success, zeroing out");
|
||||||
DtoMemSetZero(DtoLVal(lhs));
|
DtoMemSetZero(DtoType(lhs->type) ,DtoLVal(lhs));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ LLType *DtoType(Type *t) {
|
||||||
// This is an enum forward reference that is only legal when referenced
|
// This is an enum forward reference that is only legal when referenced
|
||||||
// through an indirection (e.g. "enum E; void foo(E* p);"). For lack of a
|
// through an indirection (e.g. "enum E; void foo(E* p);"). For lack of a
|
||||||
// better choice, make the outer indirection a void pointer.
|
// better choice, make the outer indirection a void pointer.
|
||||||
return getVoidPtrType()->getContainedType(0);
|
return getI8Type();
|
||||||
}
|
}
|
||||||
return DtoType(bt);
|
return DtoType(bt);
|
||||||
}
|
}
|
||||||
|
@ -397,13 +397,13 @@ void DtoMemSet(LLValue *dst, LLValue *val, LLValue *nbytes, unsigned align) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void DtoMemSetZero(LLValue *dst, LLValue *nbytes, unsigned align) {
|
void DtoMemSetZero(LLType *type, LLValue *dst, LLValue *nbytes, unsigned align) {
|
||||||
DtoMemSet(dst, DtoConstUbyte(0), nbytes, align);
|
DtoMemSet(dst, DtoConstUbyte(0), nbytes, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoMemSetZero(LLValue *dst, unsigned align) {
|
void DtoMemSetZero(LLType *type, LLValue *dst, unsigned align) {
|
||||||
uint64_t n = getTypeStoreSize(dst->getType()->getContainedType(0));
|
uint64_t n = getTypeStoreSize(type);
|
||||||
DtoMemSetZero(dst, DtoConstSize_t(n), align);
|
DtoMemSetZero(type, dst, DtoConstSize_t(n), align);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -418,10 +418,9 @@ void DtoMemCpy(LLValue *dst, LLValue *src, LLValue *nbytes, unsigned align) {
|
||||||
gIR->ir->CreateMemCpy(dst, A, src, A, nbytes, false /*isVolatile*/);
|
gIR->ir->CreateMemCpy(dst, A, src, A, nbytes, false /*isVolatile*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoMemCpy(LLValue *dst, LLValue *src, bool withPadding, unsigned align) {
|
void DtoMemCpy(LLType *type, LLValue *dst, LLValue *src, bool withPadding, unsigned align) {
|
||||||
LLType *pointee = dst->getType()->getContainedType(0);
|
|
||||||
uint64_t n =
|
uint64_t n =
|
||||||
withPadding ? getTypeAllocSize(pointee) : getTypeStoreSize(pointee);
|
withPadding ? getTypeAllocSize(type) : getTypeStoreSize(type);
|
||||||
DtoMemCpy(dst, src, DtoConstSize_t(n), align);
|
DtoMemCpy(dst, src, DtoConstSize_t(n), align);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +542,6 @@ void DtoVolatileStore(LLValue *src, LLValue *dst) {
|
||||||
void DtoStoreZextI8(LLValue *src, LLValue *dst) {
|
void DtoStoreZextI8(LLValue *src, LLValue *dst) {
|
||||||
if (src->getType()->isIntegerTy(1)) {
|
if (src->getType()->isIntegerTy(1)) {
|
||||||
llvm::Type *i8 = llvm::Type::getInt8Ty(gIR->context());
|
llvm::Type *i8 = llvm::Type::getInt8Ty(gIR->context());
|
||||||
assert(dst->getType()->getContainedType(0) == i8);
|
|
||||||
src = gIR->ir->CreateZExt(src, i8);
|
src = gIR->ir->CreateZExt(src, i8);
|
||||||
}
|
}
|
||||||
gIR->ir->CreateStore(src, dst);
|
gIR->ir->CreateStore(src, dst);
|
||||||
|
@ -767,7 +765,7 @@ LLValue *DtoAggrPair(LLValue *V1, LLValue *V2, const char *name) {
|
||||||
return DtoAggrPair(t, V1, V2, name);
|
return DtoAggrPair(t, V1, V2, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *DtoAggrPaint(LLValue *aggr, LLType *as) {
|
LLValue *DtoSlicePaint(LLValue *aggr, LLType *as) {
|
||||||
if (aggr->getType() == as) {
|
if (aggr->getType() == as) {
|
||||||
return aggr;
|
return aggr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ unsigned int getABITypeAlign(LLType *t);
|
||||||
LLValue *DtoAggrPair(LLType *type, LLValue *V1, LLValue *V2,
|
LLValue *DtoAggrPair(LLType *type, LLValue *V1, LLValue *V2,
|
||||||
const char *name = "");
|
const char *name = "");
|
||||||
LLValue *DtoAggrPair(LLValue *V1, LLValue *V2, const char *name = "");
|
LLValue *DtoAggrPair(LLValue *V1, LLValue *V2, const char *name = "");
|
||||||
LLValue *DtoAggrPaint(LLValue *aggr, LLType *as);
|
LLValue *DtoSlicePaint(LLValue *aggr, LLType *as);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a call to llvm.memset.i32 (or i64 depending on architecture).
|
* Generates a call to llvm.memset.i32 (or i64 depending on architecture).
|
||||||
|
@ -178,7 +178,7 @@ void DtoMemSet(LLValue *dst, LLValue *val, LLValue *nbytes, unsigned align = 1);
|
||||||
* @param nbytes Number of bytes to overwrite.
|
* @param nbytes Number of bytes to overwrite.
|
||||||
* @param align The minimum alignment of the destination memory.
|
* @param align The minimum alignment of the destination memory.
|
||||||
*/
|
*/
|
||||||
void DtoMemSetZero(LLValue *dst, LLValue *nbytes, unsigned align = 1);
|
void DtoMemSetZero(LLType *type, LLValue *dst, LLValue *nbytes, unsigned align = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The same as DtoMemSetZero but figures out the size itself based on the
|
* The same as DtoMemSetZero but figures out the size itself based on the
|
||||||
|
@ -186,7 +186,7 @@ void DtoMemSetZero(LLValue *dst, LLValue *nbytes, unsigned align = 1);
|
||||||
* @param dst Destination memory.
|
* @param dst Destination memory.
|
||||||
* @param align The minimum alignment of the destination memory.
|
* @param align The minimum alignment of the destination memory.
|
||||||
*/
|
*/
|
||||||
void DtoMemSetZero(LLValue *dst, unsigned align = 1);
|
void DtoMemSetZero(LLType *type, LLValue *dst, unsigned align = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a call to llvm.memcpy.i32 (or i64 depending on architecture).
|
* Generates a call to llvm.memcpy.i32 (or i64 depending on architecture).
|
||||||
|
@ -205,7 +205,7 @@ void DtoMemCpy(LLValue *dst, LLValue *src, LLValue *nbytes, unsigned align = 1);
|
||||||
* @param withPadding Use the dst pointee's padded size, not its store size.
|
* @param withPadding Use the dst pointee's padded size, not its store size.
|
||||||
* @param align The minimum alignment of the source and destination memory.
|
* @param align The minimum alignment of the source and destination memory.
|
||||||
*/
|
*/
|
||||||
void DtoMemCpy(LLValue *dst, LLValue *src, bool withPadding = false,
|
void DtoMemCpy(LLType *type, LLValue *dst, LLValue *src, bool withPadding = false,
|
||||||
unsigned align = 1);
|
unsigned align = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -426,7 +426,7 @@ LLConstant *IrClass::getClassInfoInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the initializer
|
// build the initializer
|
||||||
LLType *initType = getClassInfoSymbol()->getType()->getContainedType(0);
|
LLType *initType = getClassInfoSymbol()->getValueType();
|
||||||
constTypeInfo = b.get_constant(isaStruct(initType));
|
constTypeInfo = b.get_constant(isaStruct(initType));
|
||||||
|
|
||||||
return constTypeInfo;
|
return constTypeInfo;
|
||||||
|
@ -567,7 +567,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
|
||||||
needsCOMDAT());
|
needsCOMDAT());
|
||||||
const auto callee = irFunc->getLLVMCallee();
|
const auto callee = irFunc->getLLVMCallee();
|
||||||
thunk = LLFunction::Create(
|
thunk = LLFunction::Create(
|
||||||
isaFunction(callee->getType()->getContainedType(0)), lwc.first,
|
callee->getFunctionType(), lwc.first,
|
||||||
thunkIRMangle, &gIR->module);
|
thunkIRMangle, &gIR->module);
|
||||||
setLinkage(lwc, thunk);
|
setLinkage(lwc, thunk);
|
||||||
thunk->copyAttributesFrom(callee);
|
thunk->copyAttributesFrom(callee);
|
||||||
|
|
|
@ -51,6 +51,9 @@ LLValue *IrGlobal::getValue(bool define) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Type *IrGlobal::getType() {
|
||||||
|
return llvm::dyn_cast<llvm::GlobalVariable>(value)->getValueType();
|
||||||
|
}
|
||||||
void IrGlobal::declare() {
|
void IrGlobal::declare() {
|
||||||
Logger::println("Declaring global: %s", V->toChars());
|
Logger::println("Declaring global: %s", V->toChars());
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct IrGlobal : IrVar {
|
||||||
bool nakedUse = false;
|
bool nakedUse = false;
|
||||||
|
|
||||||
llvm::Value *getValue(bool define = false);
|
llvm::Value *getValue(bool define = false);
|
||||||
llvm::Type *getType() { return value->getType()->getContainedType(0); }
|
llvm::Type *getType();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void declare();
|
void declare();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 39fccadfd706c56688ccece37d3bed008eef8315
|
Subproject commit 673ff369d1d7f0fc1a8392413cce99380158989a
|
14
tests/codegen/gh4134.d
Normal file
14
tests/codegen/gh4134.d
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// https://github.com/ldc-developers/ldc/issues/4134
|
||||||
|
// RUN: %ldc -run %s
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
string getString() {
|
||||||
|
++i;
|
||||||
|
return "Abc";
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const r = getString() ~ getString();
|
||||||
|
assert(i == 2);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue