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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -80,6 +80,7 @@ struct IRAsmStmt {
struct Operands {
std::string c; // contraint
std::vector<LLValue *> ops;
std::vector<Type *> dTypes;
};
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
// 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);
}

View file

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

View file

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

View file

@ -322,7 +322,7 @@ public:
}
// Should be i8.
Ty = CB->getType()->getContainedType(0);
Ty = llvm::Type::getInt8Ty(CB->getContext());
return true;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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