mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +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
|
||||
// extended, but GEPs/PHIs are the most common ones.
|
||||
os << ", type = " << *val.getType();
|
||||
} else if (isa<AllocaInst>(&val)) {
|
||||
} else if (auto ai = dyn_cast<AllocaInst>(&val)) {
|
||||
os << ", size/byte = "
|
||||
<< DL.getTypeAllocSize(val.getType()->getContainedType(0));
|
||||
<< DL.getTypeAllocSize(ai->getAllocatedType());
|
||||
}
|
||||
os << ']';
|
||||
}
|
||||
|
|
|
@ -105,7 +105,8 @@ struct RemoveStructPadding : ABIRewrite {
|
|||
LLValue *lval = DtoAlloca(dty, ".RemoveStructPadding_dump");
|
||||
// Make sure the padding is zero, so struct comparisons work.
|
||||
// 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);
|
||||
return lval;
|
||||
}
|
||||
|
|
|
@ -364,7 +364,7 @@ void X86_64TargetABI::vaCopy(DLValue *dest, DValue *src) {
|
|||
DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType())));
|
||||
// Then fill the new struct with a bitcopy of 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) {
|
||||
|
|
|
@ -208,7 +208,7 @@ LLValue *TargetABI::prepareVaStart(DLValue *ap) {
|
|||
void TargetABI::vaCopy(DLValue *dest, DValue *src) {
|
||||
LLValue *llDest = DtoLVal(dest);
|
||||
if (src->isLVal()) {
|
||||
DtoMemCpy(llDest, DtoLVal(src));
|
||||
DtoMemCpy(DtoType(dest->type), llDest, DtoLVal(src));
|
||||
} else {
|
||||
DtoStore(DtoRVal(src), llDest);
|
||||
}
|
||||
|
|
|
@ -28,14 +28,12 @@
|
|||
#include "ir/irfunction.h"
|
||||
#include "ir/irmodule.h"
|
||||
|
||||
static void DtoSetArray(DValue *array, LLValue *dim, LLValue *ptr);
|
||||
static void DtoSetArray(DValue *array, DValue *rhs);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
LLValue *DtoSlice(LLValue *ptr, LLValue *length, LLType *elemType = nullptr) {
|
||||
if (!elemType)
|
||||
elemType = ptr->getType()->getContainedType(0);
|
||||
LLValue *DtoSlice(LLValue *ptr, LLValue *length, LLType *elemType) {
|
||||
elemType = i1ToI8(voidToI8(elemType));
|
||||
return DtoAggrPair(length, DtoBitCast(ptr, elemType->getPointerTo()));
|
||||
}
|
||||
|
@ -44,7 +42,7 @@ LLValue *DtoSlice(Expression *e) {
|
|||
DValue *dval = toElem(e);
|
||||
if (dval->type->toBasetype()->ty == TY::Tsarray) {
|
||||
// Convert static array to slice
|
||||
return DtoSlice(DtoLVal(dval), DtoArrayLen(dval));
|
||||
return DtoSlice(DtoLVal(dval), DtoArrayLen(dval), DtoType(dval->type->nextOf()));
|
||||
}
|
||||
return DtoRVal(dval);
|
||||
}
|
||||
|
@ -218,7 +216,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
|||
if (rhs->isNull()) {
|
||||
DtoSetArrayToNull(lhs);
|
||||
} else {
|
||||
DtoSetArray(lhs, DtoArrayLen(rhs), DtoArrayPtr(rhs));
|
||||
DtoSetArray(lhs, rhs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -254,7 +252,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
|||
const size_t elementSize = getTypeAllocSize(DtoMemType(elemType));
|
||||
if (rhs->isNull()) {
|
||||
LLValue *lhsSize = computeSize(lhsLength, elementSize);
|
||||
DtoMemSetZero(lhsPtr, lhsSize);
|
||||
DtoMemSetZero(getI8Type(), lhsPtr, lhsSize);
|
||||
} else {
|
||||
bool knownInBounds =
|
||||
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) {
|
||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||
gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(loc, elemType),
|
||||
DtoSlice(rhsPtr, rhsLength),
|
||||
DtoSlice(lhsPtr, lhsLength));
|
||||
DtoSlice(rhsPtr, rhsLength, getI8Type()),
|
||||
DtoSlice(lhsPtr, lhsLength, getI8Type()));
|
||||
} else { // assigning
|
||||
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
||||
LLFunction *fn = getRuntimeFunction(
|
||||
loc, gIR->module,
|
||||
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
||||
gIR->CreateCallOrInvoke(
|
||||
fn, DtoTypeInfoOf(loc, elemType), DtoSlice(rhsPtr, rhsLength),
|
||||
DtoSlice(lhsPtr, lhsLength), DtoBitCast(tmpSwap, getVoidPtrType()));
|
||||
fn, DtoTypeInfoOf(loc, elemType), DtoSlice(rhsPtr, rhsLength, getI8Type()),
|
||||
DtoSlice(lhsPtr, lhsLength, getI8Type()), DtoBitCast(tmpSwap, getVoidPtrType()));
|
||||
}
|
||||
} else {
|
||||
// scalar rhs:
|
||||
|
@ -295,7 +293,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
|||
if (!needsDestruction && !needsPostblit) {
|
||||
// fast version
|
||||
const size_t lhsElementSize =
|
||||
getTypeAllocSize(realLhsPtr->getType()->getContainedType(0));
|
||||
getTypeAllocSize(DtoMemType(lhs->type->nextOf()));
|
||||
LLType *rhsType = DtoMemType(t2);
|
||||
const size_t rhsSize = getTypeAllocSize(rhsType);
|
||||
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");
|
||||
LLValue *arr = DtoLVal(array);
|
||||
LLType *s = isaStruct(arr->getType()->getContainedType(0));
|
||||
LLType *s = DtoType(array->type);
|
||||
assert(s);
|
||||
DtoStore(dim, DtoGEP(s, arr, 0u, 0));
|
||||
DtoStore(ptr, DtoGEP(s, arr, 0, 1));
|
||||
DtoStore(DtoArrayLen(rhs), DtoGEP(s, arr, 0u, 0));
|
||||
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(
|
||||
fn, DtoTypeInfoOf(loc, arrayType),
|
||||
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
|
||||
DtoAggrPaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
|
||||
DtoSlicePaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
|
||||
".appendedArray");
|
||||
|
||||
return getSlice(arrayType, newArray);
|
||||
|
@ -921,10 +919,12 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
|
|||
|
||||
auto loadArray = [fn](Expression* e, int paramTypeIdx) {
|
||||
DValue * dval = toElem(e);
|
||||
LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(e));
|
||||
return DtoAggrPaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
|
||||
LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(dval));
|
||||
return DtoSlicePaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
|
||||
};
|
||||
// byte[] x
|
||||
args.push_back(loadArray(exp1,1));
|
||||
// byte[] y
|
||||
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;
|
||||
|
||||
// get values, reinterpret cast to void[]
|
||||
args.push_back(DtoAggrPaint(DtoRVal(l),
|
||||
args.push_back(DtoSlicePaint(DtoRVal(l),
|
||||
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
||||
args.push_back(DtoAggrPaint(DtoRVal(r),
|
||||
args.push_back(DtoSlicePaint(DtoRVal(r),
|
||||
DtoArrayType(LLType::getInt8Ty(gIR->context()))));
|
||||
|
||||
// pass array typeinfo ?
|
||||
|
@ -1066,12 +1066,12 @@ bool validCompareWithMemcmp(DValue *l, DValue *r) {
|
|||
|
||||
// Create a call instruction to memcmp.
|
||||
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);
|
||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "memcmp");
|
||||
assert(fn);
|
||||
auto sizeInBytes = numElements;
|
||||
size_t elementSize = getTypeAllocSize(l_ptr->getType()->getContainedType(0));
|
||||
size_t elementSize = getTypeAllocSize(elemty);
|
||||
if (elementSize != 1) {
|
||||
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);
|
||||
if (staticArrayComparison) {
|
||||
// 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
|
||||
|
@ -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
|
||||
// return 0 (equality) when the length is zero.
|
||||
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);
|
||||
|
||||
// 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;
|
||||
asmStmt->in.ops.push_back(arg_val);
|
||||
input_constraints.push_back(cns);
|
||||
asmStmt->in.dTypes.push_back(arg->expr->type);
|
||||
} else {
|
||||
arg_map[i] = n_outputs++;
|
||||
asmStmt->out.ops.push_back(arg_val);
|
||||
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.
|
||||
input_constraints.push_back(ss.str());
|
||||
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 += ",";
|
||||
|
@ -549,6 +552,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
// FIXME: Store the value -> label mapping somewhere, so it can be
|
||||
// referenced later
|
||||
outSetterStmt->in.ops.push_back(DtoConstUint(n_goto));
|
||||
outSetterStmt->in.dTypes.push_back(Type::tuns32);
|
||||
outSetterStmt->in.c += "i,";
|
||||
code << asmGotoEnd;
|
||||
|
||||
|
@ -564,6 +568,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
// setup variable for output from asm
|
||||
outSetterStmt->out.c = "=*m,";
|
||||
outSetterStmt->out.ops.push_back(jump_target);
|
||||
outSetterStmt->out.dTypes.push_back(Type::tuns32);
|
||||
|
||||
asmblock->s.push_back(outSetterStmt);
|
||||
} else {
|
||||
|
@ -586,8 +591,10 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
|
||||
// build asm block
|
||||
struct ArgBlock {
|
||||
ArgBlock() = default;
|
||||
std::vector<LLValue *> args;
|
||||
std::vector<LLType *> types;
|
||||
std::vector<Type *> dTypes;
|
||||
std::string c;
|
||||
} in, out;
|
||||
std::string clobbers;
|
||||
|
@ -603,6 +610,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
for (size_t j = 0; j < onn; ++j) {
|
||||
out.args.push_back(a->out.ops[j]);
|
||||
out.types.push_back(a->out.ops[j]->getType());
|
||||
out.dTypes.push_back(a->out.dTypes[j]);
|
||||
}
|
||||
if (!a->out.c.empty()) {
|
||||
out.c += a->out.c;
|
||||
|
@ -619,6 +627,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
for (size_t j = 0; j < inn; ++j) {
|
||||
in.args.push_back(a->in.ops[j]);
|
||||
in.types.push_back(a->in.ops[j]->getType());
|
||||
in.dTypes.push_back(a->in.dTypes[j]);
|
||||
}
|
||||
if (!a->in.c.empty()) {
|
||||
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(), 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 {
|
||||
Logger::cout() << "Arguments:" << '\n';
|
||||
Logger::indent();
|
||||
|
@ -685,9 +721,21 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
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);
|
||||
|
||||
auto call = p->createInlineAsmCall(stmt->loc, ia, args, {});
|
||||
auto call = p->createInlineAsmCall(stmt->loc, ia, args, indirectTypes);
|
||||
if (!retty->isVoidTy()) {
|
||||
call->setName("asm");
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
|
|||
LLValue *mem;
|
||||
bool doInit = true;
|
||||
if (newexp->onstack) {
|
||||
mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), tc->sym->alignsize,
|
||||
mem = DtoRawAlloca(getIrAggr(tc->sym)->getLLStructType(), tc->sym->alignsize,
|
||||
".newclass_alloca");
|
||||
} else {
|
||||
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.
|
||||
LLValue *tmp = DtoGEP(st, dst, 0u, 0, "vtbl");
|
||||
LLValue *val =
|
||||
DtoBitCast(irClass->getVtblSymbol(), tmp->getType()->getContainedType(0));
|
||||
LLValue *val = irClass->getVtblSymbol();
|
||||
DtoStore(val, tmp);
|
||||
|
||||
// For D classes, set the monitor field to null.
|
||||
const bool isCPPclass = tc->sym->isCPPclass() ? true : false;
|
||||
if (!isCPPclass) {
|
||||
tmp = DtoGEP(st, dst, 0, 1, "monitor");
|
||||
val = LLConstant::getNullValue(tmp->getType()->getContainedType(0));
|
||||
val = LLConstant::getNullValue(getVoidPtrType());
|
||||
DtoStore(val, tmp);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class DComputeTarget {
|
|||
public:
|
||||
llvm::LLVMContext &ctx;
|
||||
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.
|
||||
const char *short_name;
|
||||
const char *binSuffix;
|
||||
|
|
|
@ -26,7 +26,7 @@ class TargetCUDA : public DComputeTarget {
|
|||
public:
|
||||
TargetCUDA(llvm::LLVMContext &c, int sm)
|
||||
: DComputeTarget(
|
||||
c, sm, CUDA, "cuda", "ptx", createNVPTXABI(),
|
||||
c, sm, ID::CUDA, "cuda", "ptx", createNVPTXABI(),
|
||||
|
||||
// Map from nominal DCompute address space to NVPTX address space.
|
||||
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
|
||||
|
|
|
@ -42,7 +42,7 @@ class TargetOCL : public DComputeTarget {
|
|||
bool usedImage;
|
||||
public:
|
||||
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
|
||||
// address. For OpenCL this is a no-op.
|
||||
{{0, 1, 2, 3, 4}}) {
|
||||
|
|
|
@ -213,16 +213,6 @@ public:
|
|||
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) {
|
||||
if (!global.params.symdebug) {
|
||||
return;
|
||||
|
|
|
@ -131,7 +131,7 @@ DRValue *DLValue::getRVal() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
LLValue *rval = DtoLoad(val->getType()->getPointerElementType(), val);
|
||||
LLValue *rval = DtoLoad(DtoMemType(type), val);
|
||||
|
||||
const auto ty = type->toBasetype()->ty;
|
||||
if (ty == TY::Tbool) {
|
||||
|
@ -220,3 +220,35 @@ void DBitFieldLValue::store(LLValue *value) {
|
|||
const auto newVal = gIR->ir->CreateOr(maskedOldVal, bfVal);
|
||||
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 DSpecialRefValue;
|
||||
class DBitFieldLValue;
|
||||
class DDcomputeLValue;
|
||||
class DSliceValue;
|
||||
class DFuncValue;
|
||||
|
||||
|
@ -61,6 +62,7 @@ public:
|
|||
virtual DLValue *isLVal() { return nullptr; }
|
||||
virtual DSpecialRefValue *isSpecialRef() { return nullptr; }
|
||||
virtual DBitFieldLValue *isBitFieldLVal() { return nullptr; }
|
||||
virtual DDcomputeLValue *isDDcomputeLVal() { return nullptr; }
|
||||
|
||||
virtual DRValue *isRVal() { return nullptr; }
|
||||
virtual DImValue *isIm() { return nullptr; }
|
||||
|
@ -199,5 +201,15 @@ private:
|
|||
// 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; }
|
||||
llvm::Value *DtoLVal(DValue *v);
|
||||
|
|
|
@ -488,7 +488,7 @@ void applyTargetMachineAttributes(llvm::Function &func,
|
|||
const auto dcompute = gIR->dcomputetarget;
|
||||
|
||||
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
|
||||
if (dcompute && dcompute->target == DComputeTarget::OpenCL)
|
||||
if (dcompute && dcompute->target == DComputeTarget::ID::OpenCL)
|
||||
return;
|
||||
const auto cpu = dcompute ? "" : target.getTargetCPU();
|
||||
const auto features = dcompute ? "" : target.getTargetFeatureString();
|
||||
|
|
|
@ -136,7 +136,7 @@ LLConstant *
|
|||
IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
||||
LLConstant *initializer,
|
||||
Dsymbol *symbolForLinkageAndVisibility) {
|
||||
if (initializer->getType() == globalVar->getType()->getContainedType(0)) {
|
||||
if (initializer->getType() == globalVar->getValueType()) {
|
||||
defineGlobal(globalVar, initializer, symbolForLinkageAndVisibility);
|
||||
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
|
||||
// constraint/argument index mapping
|
||||
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()) {
|
||||
if (constraintInfo.isIndirect) {
|
||||
llvm::Type *indirectType = indirectLen != 0 ?
|
||||
indirectTypes[indirectIdx] :
|
||||
args[i]->getType()->getPointerElementType();
|
||||
|
||||
call->addParamAttr(i, llvm::Attribute::get(
|
||||
context(),
|
||||
llvm::Attribute::ElementType,
|
||||
indirectType));
|
||||
indirectTypes[indirectIdx]));
|
||||
++indirectIdx;
|
||||
}
|
||||
++i;
|
||||
|
|
|
@ -80,6 +80,7 @@ struct IRAsmStmt {
|
|||
struct Operands {
|
||||
std::string c; // contraint
|
||||
std::vector<LLValue *> ops;
|
||||
std::vector<Type *> dTypes;
|
||||
};
|
||||
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
|
||||
// struct self-assignments like 'A a; a = a;'.
|
||||
if (src != dst)
|
||||
DtoMemCpy(dst, src);
|
||||
DtoMemCpy(DtoType(lhs->type), dst, src);
|
||||
}
|
||||
} else if (t->ty == TY::Tarray || t->ty == TY::Tsarray) {
|
||||
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() << "r : " << *r << '\n';
|
||||
}
|
||||
r = DtoBitCast(r, l->getType()->getContainedType(0));
|
||||
r = DtoBitCast(r, DtoType(lhs->type));
|
||||
DtoStore(r, l);
|
||||
} else if (t->iscomplex()) {
|
||||
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() << "rhs: " << *r << '\n';
|
||||
}
|
||||
LLType *lit = l->getType()->getContainedType(0);
|
||||
LLType *lit = DtoType(lhs->type);
|
||||
if (r->getType() != lit) {
|
||||
r = DtoRVal(DtoCast(loc, rhs, lhs->type));
|
||||
IF_LOG {
|
||||
|
@ -1882,10 +1882,12 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
|||
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
|
||||
|
||||
LLValue *ptr = src;
|
||||
LLType * ty = nullptr;
|
||||
if (!isFieldIdx) {
|
||||
// Cast to void* to apply byte-wise offset from object start.
|
||||
ptr = DtoBitCast(ptr, getVoidPtrType());
|
||||
ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, off);
|
||||
ty = DtoType(vd->type);
|
||||
} else {
|
||||
if (ad->structsize == 0) { // can happen for extern(C) structs
|
||||
assert(off == 0);
|
||||
|
@ -1904,6 +1906,7 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
|||
}
|
||||
ptr = DtoBitCast(ptr, pst);
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -503,17 +503,20 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
|
|||
llvm::FunctionType *FT =
|
||||
llvm::FunctionType::get(returnType, operandTypes, false);
|
||||
|
||||
// make sure the constraints are valid
|
||||
if (!llvm::InlineAsm::
|
||||
#if LDC_LLVM_VER < 1500
|
||||
Verify
|
||||
#else
|
||||
verify
|
||||
#endif
|
||||
(FT, constraints)) {
|
||||
// make sure the constraints are valid
|
||||
if (!llvm::InlineAsm::Verify(FT, constraints)) {
|
||||
error(loc, "inline asm constraints are invalid");
|
||||
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
|
||||
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 char *name = "") {
|
||||
gIR->DBuilder.OpOffset(dwarfAddrOps, val, fieldIndex);
|
||||
gIR->DBuilder.OpOffset(dwarfAddrOps, currFrame, fieldIndex);
|
||||
val = DtoGEP(currFrame, val, 0, fieldIndex, name);
|
||||
};
|
||||
|
||||
|
@ -538,7 +538,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
|||
// The parameter value is an alloca'd stack slot.
|
||||
// Copy to the nesting frame and leave the alloca for
|
||||
// the optimizers to clean up.
|
||||
DtoMemCpy(gep, parm->value);
|
||||
DtoMemCpy(frameType->getContainedType(irLocal->nestedIndex), gep, parm->value);
|
||||
gep->takeName(parm->value);
|
||||
parm->value = gep; // update variable lvalue
|
||||
}
|
||||
|
|
|
@ -322,7 +322,7 @@ public:
|
|||
}
|
||||
|
||||
// Should be i8.
|
||||
Ty = CB->getType()->getContainedType(0);
|
||||
Ty = llvm::Type::getInt8Ty(CB->getContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ struct DComputeSemanticAnalyser : public StoppableVisitor {
|
|||
if (auto ce = stmt->condition->isCallExp()) {
|
||||
if (ce->f && ce->f->ident == Id::dcReflect) {
|
||||
auto arg1 = (DComputeTarget::ID)(*ce->arguments)[0]->toInteger();
|
||||
if (arg1 == DComputeTarget::Host)
|
||||
if (arg1 == DComputeTarget::ID::Host)
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -364,7 +364,7 @@ public:
|
|||
auto arg2 = (*ce->arguments)[1]->toInteger();
|
||||
auto dct = irs->dcomputetarget;
|
||||
if (!dct) {
|
||||
return arg1 == DComputeTarget::Host;
|
||||
return arg1 == DComputeTarget::ID::Host;
|
||||
} else {
|
||||
return arg1 == dct->target &&
|
||||
(!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';
|
||||
}
|
||||
if (isaStruct(llVal)) {
|
||||
llVal = DtoAggrPaint(llVal, paramType);
|
||||
llVal = DtoSlicePaint(llVal, paramType);
|
||||
} else {
|
||||
llVal = DtoBitCast(llVal, paramType);
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
assert(ap);
|
||||
// variadic extern(D) function with implicit _argptr?
|
||||
if (LLValue *argptrMem = p->func()->_argptr) {
|
||||
DtoMemCpy(DtoLVal(ap), argptrMem); // ap = _argptr
|
||||
DtoMemCpy(DtoType(ap->type), DtoLVal(ap), argptrMem); // ap = _argptr
|
||||
} else {
|
||||
LLValue *llAp = gABI->prepareVaStart(ap);
|
||||
p->ir->CreateCall(GET_INTRINSIC_DECL(vastart), llAp, "");
|
||||
|
@ -395,7 +395,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
|
||||
DValue *dval = toElem(exp1);
|
||||
LLValue *ptr = DtoRVal(exp2);
|
||||
LLType *pointeeType = ptr->getType()->getContainedType(0);
|
||||
LLType *pointeeType = DtoType(exp2->type->isTypePointer()->nextOf());
|
||||
|
||||
LLValue *val = nullptr;
|
||||
if (pointeeType->isIntegerTy()) {
|
||||
|
@ -482,7 +482,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
const bool isWeak = (*e->arguments)[5]->toInteger() != 0;
|
||||
|
||||
LLValue *ptr = DtoRVal(exp1);
|
||||
LLType *pointeeType = ptr->getType()->getContainedType(0);
|
||||
LLType *pointeeType = DtoType(exp1->type->isTypePointer()->nextOf());
|
||||
DValue *dcmp = toElem(exp2);
|
||||
DValue *dval = toElem(exp3);
|
||||
|
||||
|
@ -708,11 +708,9 @@ private:
|
|||
}
|
||||
|
||||
size_t index = args.size();
|
||||
LLType *llArgType = *(llArgTypesBegin + index);
|
||||
|
||||
LLValue *pointer = sretPointer;
|
||||
if (!pointer) {
|
||||
pointer = DtoRawAlloca(llArgType->getContainedType(0),
|
||||
pointer = DtoRawAlloca(DtoType(tf->nextOf()),
|
||||
DtoAlignment(resulttype), ".sret_tmp");
|
||||
}
|
||||
|
||||
|
@ -958,7 +956,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
|
|||
if (tf->isref()) {
|
||||
retllval = DtoBitCast(retllval, DtoType(rbase->pointerTo()));
|
||||
} else {
|
||||
retllval = DtoAggrPaint(retllval, DtoType(rbase));
|
||||
retllval = DtoSlicePaint(retllval, DtoType(rbase));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -341,7 +341,7 @@ public:
|
|||
result = base;
|
||||
} else {
|
||||
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)",
|
||||
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) {
|
||||
mem = DtoBitCast(mem, getVoidPtrType());
|
||||
LLValue *gep = DtoGEP1(LLType::getInt8Ty(gIR->context()), mem, start, ".padding");
|
||||
DtoMemSetZero(gep, DtoConstSize_t(end - start));
|
||||
LLType *i8 = LLType::getInt8Ty(gIR->context());
|
||||
LLValue *gep = DtoGEP1(i8, mem, start, ".padding");
|
||||
DtoMemSetZero(i8, gep, DtoConstSize_t(end - start));
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
@ -546,7 +547,7 @@ public:
|
|||
Logger::println("performing aggregate zero initialization");
|
||||
assert(e->e2->toInteger() == 0);
|
||||
LLValue *lval = DtoLVal(lhs);
|
||||
DtoMemSetZero(lval);
|
||||
DtoMemSetZero(DtoType(lhs->type), lval);
|
||||
TypeStruct *ts = static_cast<TypeStruct *>(e->e1->type);
|
||||
if (ts->sym->isNested() && ts->sym->vthis)
|
||||
DtoResolveNestedContext(e->loc, ts->sym, lval);
|
||||
|
@ -843,7 +844,7 @@ public:
|
|||
if (e->offset == 0) {
|
||||
offsetValue = baseValue;
|
||||
} else {
|
||||
LLType *elemType = baseValue->getType()->getContainedType(0);
|
||||
LLType *elemType = DtoType(base->type);
|
||||
if (elemType->isSized()) {
|
||||
uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType);
|
||||
if (e->offset % elemSize == 0) {
|
||||
|
@ -948,6 +949,14 @@ public:
|
|||
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 {
|
||||
|
@ -985,14 +994,24 @@ public:
|
|||
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()) {
|
||||
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 {
|
||||
ptr = DtoBitCast(ptr, DtoPtrToType(e->type));
|
||||
result = new DLValue(e->type, ptr);
|
||||
LLValue *p = DtoBitCast(DtoLVal(ptr), DtoPtrToType(e->type));
|
||||
result = new DLValue(e->type, p);
|
||||
}
|
||||
} else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) {
|
||||
// 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
|
||||
} else if (dval->isLVal()) {
|
||||
LLValue *lval = DtoLVal(dval);
|
||||
DtoStore(LLConstant::getNullValue(lval->getType()->getContainedType(0)),
|
||||
DtoStore(LLConstant::getNullValue(DtoType(dval->type)),
|
||||
lval);
|
||||
}
|
||||
}
|
||||
|
@ -2301,12 +2320,12 @@ public:
|
|||
dstMem = DtoAlloca(e->type, ".structliteral");
|
||||
|
||||
if (sd->zeroInit()) {
|
||||
DtoMemSetZero(dstMem);
|
||||
DtoMemSetZero(DtoType(e->type), dstMem);
|
||||
} else {
|
||||
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
||||
initsym = DtoBitCast(initsym, DtoType(e->type->pointerTo()));
|
||||
assert(dstMem->getType() == initsym->getType());
|
||||
DtoMemCpy(dstMem, initsym);
|
||||
DtoMemCpy(DtoType(e->type), dstMem, initsym);
|
||||
}
|
||||
|
||||
return new DLValue(e->type, dstMem);
|
||||
|
@ -2456,7 +2475,7 @@ public:
|
|||
LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
|
||||
LLConstant *slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
||||
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);
|
||||
globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false,
|
||||
|
@ -2464,7 +2483,7 @@ public:
|
|||
initval, ".aaValuesStorage");
|
||||
slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
||||
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,
|
||||
valuesArray, "aa");
|
||||
|
@ -2574,7 +2593,7 @@ public:
|
|||
DValue *ep = toElem(el);
|
||||
LLValue *gep = DtoGEP(st, val, 0, i);
|
||||
if (DtoIsInMemoryOnly(el->type)) {
|
||||
DtoMemCpy(gep, DtoLVal(ep));
|
||||
DtoMemCpy(st->getContainedType(i), gep, DtoLVal(ep));
|
||||
} else if (el->type->ty != TY::Tvoid) {
|
||||
DtoStoreZextI8(DtoRVal(ep), gep);
|
||||
} else {
|
||||
|
@ -2651,7 +2670,7 @@ public:
|
|||
Type *srcElementType = tsrc->nextOf();
|
||||
|
||||
if (DtoMemType(elementType) == DtoMemType(srcElementType)) {
|
||||
DtoMemCpy(dstMem, arrayPtr);
|
||||
DtoMemCpy(dstType, dstMem, arrayPtr);
|
||||
} else {
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
LLValue *gep = DtoGEP1(DtoMemType(e1->type->nextOf()), arrayPtr, i);
|
||||
|
@ -2821,7 +2840,7 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
|
|||
DtoResolveStruct(sd);
|
||||
if (sd->zeroInit()) {
|
||||
Logger::println("success, zeroing out");
|
||||
DtoMemSetZero(DtoLVal(lhs));
|
||||
DtoMemSetZero(DtoType(lhs->type) ,DtoLVal(lhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ LLType *DtoType(Type *t) {
|
|||
// 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
|
||||
// better choice, make the outer indirection a void pointer.
|
||||
return getVoidPtrType()->getContainedType(0);
|
||||
return getI8Type();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void DtoMemSetZero(LLValue *dst, unsigned align) {
|
||||
uint64_t n = getTypeStoreSize(dst->getType()->getContainedType(0));
|
||||
DtoMemSetZero(dst, DtoConstSize_t(n), align);
|
||||
void DtoMemSetZero(LLType *type, LLValue *dst, unsigned align) {
|
||||
uint64_t n = getTypeStoreSize(type);
|
||||
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*/);
|
||||
}
|
||||
|
||||
void DtoMemCpy(LLValue *dst, LLValue *src, bool withPadding, unsigned align) {
|
||||
LLType *pointee = dst->getType()->getContainedType(0);
|
||||
void DtoMemCpy(LLType *type, LLValue *dst, LLValue *src, bool withPadding, unsigned align) {
|
||||
uint64_t n =
|
||||
withPadding ? getTypeAllocSize(pointee) : getTypeStoreSize(pointee);
|
||||
withPadding ? getTypeAllocSize(type) : getTypeStoreSize(type);
|
||||
DtoMemCpy(dst, src, DtoConstSize_t(n), align);
|
||||
}
|
||||
|
||||
|
@ -543,7 +542,6 @@ void DtoVolatileStore(LLValue *src, LLValue *dst) {
|
|||
void DtoStoreZextI8(LLValue *src, LLValue *dst) {
|
||||
if (src->getType()->isIntegerTy(1)) {
|
||||
llvm::Type *i8 = llvm::Type::getInt8Ty(gIR->context());
|
||||
assert(dst->getType()->getContainedType(0) == i8);
|
||||
src = gIR->ir->CreateZExt(src, i8);
|
||||
}
|
||||
gIR->ir->CreateStore(src, dst);
|
||||
|
@ -767,7 +765,7 @@ LLValue *DtoAggrPair(LLValue *V1, LLValue *V2, const char *name) {
|
|||
return DtoAggrPair(t, V1, V2, name);
|
||||
}
|
||||
|
||||
LLValue *DtoAggrPaint(LLValue *aggr, LLType *as) {
|
||||
LLValue *DtoSlicePaint(LLValue *aggr, LLType *as) {
|
||||
if (aggr->getType() == as) {
|
||||
return aggr;
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ unsigned int getABITypeAlign(LLType *t);
|
|||
LLValue *DtoAggrPair(LLType *type, 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).
|
||||
|
@ -178,7 +178,7 @@ void DtoMemSet(LLValue *dst, LLValue *val, LLValue *nbytes, unsigned align = 1);
|
|||
* @param nbytes Number of bytes to overwrite.
|
||||
* @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
|
||||
|
@ -186,7 +186,7 @@ void DtoMemSetZero(LLValue *dst, LLValue *nbytes, unsigned align = 1);
|
|||
* @param dst 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).
|
||||
|
@ -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 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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -426,7 +426,7 @@ LLConstant *IrClass::getClassInfoInit() {
|
|||
}
|
||||
|
||||
// build the initializer
|
||||
LLType *initType = getClassInfoSymbol()->getType()->getContainedType(0);
|
||||
LLType *initType = getClassInfoSymbol()->getValueType();
|
||||
constTypeInfo = b.get_constant(isaStruct(initType));
|
||||
|
||||
return constTypeInfo;
|
||||
|
@ -567,7 +567,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
|
|||
needsCOMDAT());
|
||||
const auto callee = irFunc->getLLVMCallee();
|
||||
thunk = LLFunction::Create(
|
||||
isaFunction(callee->getType()->getContainedType(0)), lwc.first,
|
||||
callee->getFunctionType(), lwc.first,
|
||||
thunkIRMangle, &gIR->module);
|
||||
setLinkage(lwc, thunk);
|
||||
thunk->copyAttributesFrom(callee);
|
||||
|
|
|
@ -51,6 +51,9 @@ LLValue *IrGlobal::getValue(bool define) {
|
|||
return value;
|
||||
}
|
||||
|
||||
llvm::Type *IrGlobal::getType() {
|
||||
return llvm::dyn_cast<llvm::GlobalVariable>(value)->getValueType();
|
||||
}
|
||||
void IrGlobal::declare() {
|
||||
Logger::println("Declaring global: %s", V->toChars());
|
||||
LOG_SCOPE
|
||||
|
|
|
@ -38,7 +38,7 @@ struct IrGlobal : IrVar {
|
|||
bool nakedUse = false;
|
||||
|
||||
llvm::Value *getValue(bool define = false);
|
||||
llvm::Type *getType() { return value->getType()->getContainedType(0); }
|
||||
llvm::Type *getType();
|
||||
|
||||
private:
|
||||
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