Merge remote-tracking branch 'origin/master' into pre-monorepo

Conflicts:
	gen/toir.cpp
	runtime/druntime
This commit is contained in:
Martin Kinkelin 2022-09-15 14:56:49 +02:00
commit dd5f696d2e
32 changed files with 236 additions and 115 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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