diff --git a/driver/toobj.cpp b/driver/toobj.cpp index 087c3da487..8015e031af 100644 --- a/driver/toobj.cpp +++ b/driver/toobj.cpp @@ -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(&val)) { + } else if (auto ai = dyn_cast(&val)) { os << ", size/byte = " - << DL.getTypeAllocSize(val.getType()->getContainedType(0)); + << DL.getTypeAllocSize(ai->getAllocatedType()); } os << ']'; } diff --git a/gen/abi-generic.h b/gen/abi-generic.h index 60b7c6d2f9..f94d3298ed 100644 --- a/gen/abi-generic.h +++ b/gen/abi-generic.h @@ -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; } diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index a00dc93b00..764ace778f 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -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) { diff --git a/gen/abi.cpp b/gen/abi.cpp index c81f1d861e..506c51f861 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -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); } diff --git a/gen/arrays.cpp b/gen/arrays.cpp index cb79aebb38..3840326164 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -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 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. diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index 100466c1c8..9f0019651e 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -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 args; std::vector types; + std::vector 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; @@ -668,6 +677,33 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) { std::vector args; 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 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'; @@ -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"); } diff --git a/gen/classes.cpp b/gen/classes.cpp index ba6e9aec53..5fecad4ae9 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -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); } diff --git a/gen/dcompute/target.h b/gen/dcompute/target.h index b1ca77210c..176f8d5dd4 100644 --- a/gen/dcompute/target.h +++ b/gen/dcompute/target.h @@ -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; diff --git a/gen/dcompute/targetCUDA.cpp b/gen/dcompute/targetCUDA.cpp index b1a5ebe09c..f242f322a5 100644 --- a/gen/dcompute/targetCUDA.cpp +++ b/gen/dcompute/targetCUDA.cpp @@ -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 diff --git a/gen/dcompute/targetOCL.cpp b/gen/dcompute/targetOCL.cpp index 5634df24df..7c70293d2d 100644 --- a/gen/dcompute/targetOCL.cpp +++ b/gen/dcompute/targetOCL.cpp @@ -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}}) { diff --git a/gen/dibuilder.h b/gen/dibuilder.h index 9888c21001..64a50d32e7 100644 --- a/gen/dibuilder.h +++ b/gen/dibuilder.h @@ -213,16 +213,6 @@ public: addr.push_back(offset); } - template 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 void OpDeref(T &addr) { if (!global.params.symdebug) { return; diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index 3b7f5aaa3f..02b4166dd0 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -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(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); +} diff --git a/gen/dvalue.h b/gen/dvalue.h index fefd85d36e..b5131afcab 100644 --- a/gen/dvalue.h +++ b/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); diff --git a/gen/functions.cpp b/gen/functions.cpp index f4afb6a12e..a596c6b0e4 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -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(); diff --git a/gen/irstate.cpp b/gen/irstate.cpp index 581e38ef41..1160b98885 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -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; diff --git a/gen/irstate.h b/gen/irstate.h index 07851e5e49..fbd69cd4a3 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -80,6 +80,7 @@ struct IRAsmStmt { struct Operands { std::string c; // contraint std::vector ops; + std::vector dTypes; }; Operands out, in; diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 769e077948..61338b9528 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -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); } diff --git a/gen/naked.cpp b/gen/naked.cpp index cce45c102c..05c68d6541 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -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 + // make sure the constraints are valid + if (!llvm::InlineAsm::Verify(FT, constraints)) { + error(loc, "inline asm constraints are invalid"); + fatal(); + } #else - verify -#endif - (FT, constraints)) { + 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; diff --git a/gen/nested.cpp b/gen/nested.cpp index cc8abc4819..e3d9c06c82 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -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 } diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index adb7ab9d04..320e6cb78f 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -322,7 +322,7 @@ public: } // Should be i8. - Ty = CB->getType()->getContainedType(0); + Ty = llvm::Type::getInt8Ty(CB->getContext()); return true; } diff --git a/gen/semantic-dcompute.cpp b/gen/semantic-dcompute.cpp index c40ca586e6..157656a02f 100644 --- a/gen/semantic-dcompute.cpp +++ b/gen/semantic-dcompute.cpp @@ -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; } } diff --git a/gen/statements.cpp b/gen/statements.cpp index a6ad29ab1a..29b9fcb942 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -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(dct->tversion)); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 6b353d6427..a1eff2c33b 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -188,7 +188,7 @@ static void addExplicitArguments(std::vector &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; diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp index e2676d7ba4..e62e2f8bac 100644 --- a/gen/toconstelem.cpp +++ b/gen/toconstelem.cpp @@ -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(e->offset), diff --git a/gen/toir.cpp b/gen/toir.cpp index c3710c9331..61ddfbda56 100644 --- a/gen/toir.cpp +++ b/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(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; } } diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 6c95968db9..4225262b61 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -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; } diff --git a/gen/tollvm.h b/gen/tollvm.h index b4e7eac531..57dbc7acc9 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -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); /** diff --git a/ir/irclass.cpp b/ir/irclass.cpp index cfdd7f2413..0447baec85 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -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); diff --git a/ir/irvar.cpp b/ir/irvar.cpp index 7c329020d9..97339d2f9e 100644 --- a/ir/irvar.cpp +++ b/ir/irvar.cpp @@ -51,6 +51,9 @@ LLValue *IrGlobal::getValue(bool define) { return value; } +llvm::Type *IrGlobal::getType() { + return llvm::dyn_cast(value)->getValueType(); +} void IrGlobal::declare() { Logger::println("Declaring global: %s", V->toChars()); LOG_SCOPE diff --git a/ir/irvar.h b/ir/irvar.h index 4ef6ee5b02..ff6732cac6 100644 --- a/ir/irvar.h +++ b/ir/irvar.h @@ -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(); diff --git a/runtime/druntime b/runtime/druntime index 39fccadfd7..673ff369d1 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 39fccadfd706c56688ccece37d3bed008eef8315 +Subproject commit 673ff369d1d7f0fc1a8392413cce99380158989a diff --git a/tests/codegen/gh4134.d b/tests/codegen/gh4134.d new file mode 100644 index 0000000000..dc91a5b0f1 --- /dev/null +++ b/tests/codegen/gh4134.d @@ -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); +}