Merge remote-tracking branch 'origin/master' into bitfields

Conflicts:
	gen/dvalue.cpp
	gen/llvmhelpers.cpp
	gen/structs.cpp
	gen/toir.cpp
	ir/irtypeaggr.cpp
This commit is contained in:
Martin Kinkelin 2022-09-10 16:20:54 +02:00
commit 78fdc135e4
44 changed files with 666 additions and 543 deletions

View file

@ -36,6 +36,7 @@ find_package(LLVM 9.0 REQUIRED
selectiondag support tablegen target transformutils vectorize selectiondag support tablegen target transformutils vectorize
windowsmanifest ${EXTRA_LLVM_MODULES}) windowsmanifest ${EXTRA_LLVM_MODULES})
math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR}) math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
message(STATUS "Using LLVM Version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
# Remove LLVMTableGen library from list of libraries # Remove LLVMTableGen library from list of libraries
string(REGEX MATCH "[^;]*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}") string(REGEX MATCH "[^;]*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
string(REGEX REPLACE "[^;]*LLVMTableGen[^;]*;?" "" LLVM_LIBRARIES "${LLVM_LIBRARIES}") string(REGEX REPLACE "[^;]*LLVMTableGen[^;]*;?" "" LLVM_LIBRARIES "${LLVM_LIBRARIES}")

View file

@ -135,11 +135,11 @@ struct BaseBitcastABIRewrite : ABIRewrite {
if (!dv->isLVal()) { if (!dv->isLVal()) {
LLValue *dump = DtoAllocaDump(dv, asType, alignment, LLValue *dump = DtoAllocaDump(dv, asType, alignment,
".BaseBitcastABIRewrite_arg_storage"); ".BaseBitcastABIRewrite_arg_storage");
return DtoLoad(dump, name); return DtoLoad(asType, dump, name);
} }
LLValue *address = DtoLVal(dv); LLValue *address = DtoLVal(dv);
LLType *pointeeType = address->getType()->getPointerElementType(); LLType *pointeeType = DtoType(dv->type);
if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType) || if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType) ||
alignment > DtoAlignment(dv->type)) { alignment > DtoAlignment(dv->type)) {
@ -148,11 +148,11 @@ struct BaseBitcastABIRewrite : ABIRewrite {
asType, alignment, ".BaseBitcastABIRewrite_padded_arg_storage"); asType, alignment, ".BaseBitcastABIRewrite_padded_arg_storage");
DtoMemCpy(paddedDump, address, DtoMemCpy(paddedDump, address,
DtoConstSize_t(getTypeAllocSize(pointeeType))); DtoConstSize_t(getTypeAllocSize(pointeeType)));
return DtoLoad(paddedDump, name); return DtoLoad(asType, paddedDump, name);
} }
address = DtoBitCast(address, getPtrToType(asType)); address = DtoBitCast(address, getPtrToType(asType));
return DtoLoad(address, name); return DtoLoad(asType, address, name);
} }
LLValue *getLVal(Type *dty, LLValue *v) override { LLValue *getLVal(Type *dty, LLValue *v) override {

View file

@ -267,7 +267,13 @@ struct X86TargetABI : TargetABI {
// Keep alignment for LLVM 13+, to prevent invalid `movaps` etc., // Keep alignment for LLVM 13+, to prevent invalid `movaps` etc.,
// but limit to 4 (required according to runnable/ldc_cabi1.d). // but limit to 4 (required according to runnable/ldc_cabi1.d).
auto align4 = LLAlign(4); auto align4 = LLAlign(4);
if (arg->attrs.getAlignment().getValueOr(align4) > align4) if (arg->attrs.getAlignment().
#if LDC_LLVM_VER >= 1500
value_or
#else
getValueOr
#endif
(align4) > align4)
arg->attrs.addAlignmentAttr(align4); arg->attrs.addAlignmentAttr(align4);
#endif #endif
} }

View file

@ -38,7 +38,8 @@ bool isHFVA(Type *t, int maxNumElements, Type **rewriteType);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
llvm::Value *ABIRewrite::getRVal(Type *dty, LLValue *v) { llvm::Value *ABIRewrite::getRVal(Type *dty, LLValue *v) {
return DtoLoad(DtoBitCast(getLVal(dty, v), DtoType(dty)->getPointerTo())); llvm::Type *t = DtoType(dty);
return DtoLoad(t, DtoBitCast(getLVal(dty, v), t->getPointerTo()));
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View file

@ -52,26 +52,6 @@ LLValue *DtoSlice(Expression *e) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static LLValue *DtoSlicePtr(Expression *e) {
DValue *dval = toElem(e);
Loc loc;
LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
Type *vt = dval->type->toBasetype();
if (vt->ty == TY::Tarray) {
return makeLValue(loc, dval);
}
bool isStaticArray = vt->ty == TY::Tsarray;
LLValue *val = isStaticArray ? DtoLVal(dval) : makeLValue(loc, dval);
LLValue *array = DtoRawAlloca(type, 0, ".array");
LLValue *len = isStaticArray ? DtoArrayLen(dval) : DtoConstSize_t(1);
DtoStore(len, DtoGEP(array, 0u, 0));
DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEP(array, 0, 1));
return array;
}
////////////////////////////////////////////////////////////////////////////////
LLStructType *DtoArrayType(Type *arrayTy) { LLStructType *DtoArrayType(Type *arrayTy) {
assert(arrayTy->nextOf()); assert(arrayTy->nextOf());
llvm::Type *elems[] = {DtoSize_t(), DtoPtrToType(arrayTy->nextOf())}; llvm::Type *elems[] = {DtoSize_t(), DtoPtrToType(arrayTy->nextOf())};
@ -96,11 +76,11 @@ LLArrayType *DtoStaticArrayType(Type *t) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DtoSetArrayToNull(LLValue *v) { void DtoSetArrayToNull(DValue *v) {
IF_LOG Logger::println("DtoSetArrayToNull"); IF_LOG Logger::println("DtoSetArrayToNull");
LOG_SCOPE; LOG_SCOPE;
DtoStore(LLConstant::getNullValue(getPointeeType(v)), v); DtoStore(LLConstant::getNullValue(DtoType(v->type)), DtoLVal(v));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -143,9 +123,10 @@ static void DtoArrayInit(const Loc &loc, LLValue *ptr, LLValue *length,
// replace current scope // replace current scope
gIR->ir->SetInsertPoint(condbb); gIR->ir->SetInsertPoint(condbb);
LLType *sz = DtoSize_t();
// create the condition // create the condition
LLValue *cond_val = LLValue *cond_val =
gIR->ir->CreateICmpNE(DtoLoad(itr), length, "arrayinit.condition"); gIR->ir->CreateICmpNE(DtoLoad(sz, itr), length, "arrayinit.condition");
// conditional branch // conditional branch
assert(!gIR->scopereturned()); assert(!gIR->scopereturned());
@ -154,10 +135,10 @@ static void DtoArrayInit(const Loc &loc, LLValue *ptr, LLValue *length,
// rewrite scope // rewrite scope
gIR->ir->SetInsertPoint(bodybb); gIR->ir->SetInsertPoint(bodybb);
LLValue *itr_val = DtoLoad(itr); LLValue *itr_val = DtoLoad(sz,itr);
// assign array element value // assign array element value
DLValue arrayelem(elementValue->type->toBasetype(), Type *elemty = elementValue->type->toBasetype();
DtoGEP1(ptr, itr_val, "arrayinit.arrayelem")); DLValue arrayelem(elemty, DtoGEP1(i1ToI8(DtoType(elemty)), ptr, itr_val, "arrayinit.arrayelem"));
DtoAssign(loc, &arrayelem, elementValue, EXP::blit); DtoAssign(loc, &arrayelem, elementValue, EXP::blit);
// increment iterator // increment iterator
@ -235,7 +216,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
if (t->ty == TY::Tarray && !lhs->isSlice()) { if (t->ty == TY::Tarray && !lhs->isSlice()) {
assert(t2->ty == TY::Tarray || t2->ty == TY::Tsarray); assert(t2->ty == TY::Tarray || t2->ty == TY::Tsarray);
if (rhs->isNull()) { if (rhs->isNull()) {
DtoSetArrayToNull(DtoLVal(lhs)); DtoSetArrayToNull(lhs);
} else { } else {
DtoSetArray(lhs, DtoArrayLen(rhs), DtoArrayPtr(rhs)); DtoSetArray(lhs, DtoArrayLen(rhs), DtoArrayPtr(rhs));
} }
@ -345,9 +326,10 @@ 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, LLValue *dim, LLValue *ptr) {
IF_LOG Logger::println("SetArray"); IF_LOG Logger::println("SetArray");
LLValue *arr = DtoLVal(array); LLValue *arr = DtoLVal(array);
assert(isaStruct(arr->getType()->getContainedType(0))); LLType *s = isaStruct(arr->getType()->getContainedType(0));
DtoStore(dim, DtoGEP(arr, 0u, 0)); assert(s);
DtoStore(ptr, DtoGEP(arr, 0, 1)); DtoStore(dim, DtoGEP(s, arr, 0u, 0));
DtoStore(ptr, DtoGEP(s, arr, 0, 1));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -486,7 +468,7 @@ LLConstant *DtoConstArrayInitializer(ArrayInitializer *arrinit,
return DtoBitCast(gvar, DtoType(arrty)); return DtoBitCast(gvar, DtoType(arrty));
} }
LLConstant *gep = DtoGEP(gvar, 0u, 0u); LLConstant *gep = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty)); gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty));
return DtoConstSlice(DtoConstSize_t(arrlen), gep, arrty); return DtoConstSlice(DtoConstSize_t(arrlen), gep, arrty);
@ -606,7 +588,8 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem) { void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale,
LLValue *dstMem, LLType *dstType) {
size_t elemCount = ale->elements->length; size_t elemCount = ale->elements->length;
// Don't try to write nothing to a zero-element array, we might represent it // Don't try to write nothing to a zero-element array, we might represent it
@ -636,7 +619,7 @@ void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem) {
for (size_t i = 0; i < elemCount; ++i) { for (size_t i = 0; i < elemCount; ++i) {
Expression *rhsExp = indexArrayLiteral(ale, i); Expression *rhsExp = indexArrayLiteral(ale, i);
LLValue *lhsPtr = DtoGEP(dstMem, 0, i, "", p->scopebb()); LLValue *lhsPtr = DtoGEP(dstType, dstMem, 0, i, "", p->scopebb());
DLValue lhs(rhsExp->type, DtoBitCast(lhsPtr, DtoPtrToType(rhsExp->type))); DLValue lhs(rhsExp->type, DtoBitCast(lhsPtr, DtoPtrToType(rhsExp->type)));
// try to construct it in-place // try to construct it in-place
@ -754,19 +737,19 @@ DSliceValue *DtoNewMulDimDynArray(const Loc &loc, Type *arrayType,
LLArrayType *type = LLArrayType::get(DtoSize_t(), ndims); LLArrayType *type = LLArrayType::get(DtoSize_t(), ndims);
array = DtoRawAlloca(type, 0, ".dimarray"); array = DtoRawAlloca(type, 0, ".dimarray");
for (size_t i = 0; i < ndims; ++i) { for (size_t i = 0; i < ndims; ++i) {
DtoStore(DtoRVal(dims[i]), DtoGEP(array, 0, i, ".ndim")); DtoStore(DtoRVal(dims[i]), DtoGEP(type, array, 0, i, ".ndim"));
} }
} }
LLStructType *dtype = DtoArrayType(DtoSize_t()); LLStructType *dtype = DtoArrayType(DtoSize_t());
LLValue *darray = DtoRawAlloca(dtype, 0, ".array"); LLValue *darray = DtoRawAlloca(dtype, 0, ".array");
DtoStore(DtoConstSize_t(ndims), DtoGEP(darray, 0u, 0, ".len")); DtoStore(DtoConstSize_t(ndims), DtoGEP(dtype, darray, 0u, 0, ".len"));
DtoStore(DtoBitCast(array, getPtrToType(DtoSize_t())), DtoStore(DtoBitCast(array, getPtrToType(DtoSize_t())),
DtoGEP(darray, 0, 1, ".ptr")); DtoGEP(dtype, darray, 0, 1, ".ptr"));
// call allocator // call allocator
LLValue *newptr = LLValue *newptr =
gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(darray), ".gc_mem"); gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(dtype, darray), ".gc_mem");
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n'; IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
@ -825,9 +808,10 @@ void DtoCatAssignElement(const Loc &loc, DValue *array, Expression *exp) {
// Assign to the new last element. // Assign to the new last element.
LLValue *newLength = DtoArrayLen(array); LLValue *newLength = DtoArrayLen(array);
LLValue *ptr = DtoArrayPtr(array); LLValue *ptr = DtoArrayPtr(array);
LLType *ptrty = i1ToI8(DtoType(array->type->nextOf()));
LLValue *lastIndex = LLValue *lastIndex =
gIR->ir->CreateSub(newLength, DtoConstSize_t(1), ".lastIndex"); gIR->ir->CreateSub(newLength, DtoConstSize_t(1), ".lastIndex");
LLValue *lastElemPtr = DtoGEP1(ptr, lastIndex, ".lastElem"); LLValue *lastElemPtr = DtoGEP1(ptrty, ptr, lastIndex, ".lastElem");
DLValue lastElem(arrayType->nextOf(), lastElemPtr); DLValue lastElem(arrayType->nextOf(), lastElemPtr);
DtoAssign(loc, &lastElem, expVal, EXP::blit); DtoAssign(loc, &lastElem, expVal, EXP::blit);
callPostblit(loc, exp, lastElemPtr); callPostblit(loc, exp, lastElemPtr);
@ -853,6 +837,34 @@ DSliceValue *DtoCatAssignArray(const Loc &loc, DValue *arr, Expression *exp) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static LLValue *DtoSlicePtr(DValue *dval) {
Loc loc;
Type *vt = dval->type->toBasetype();
if (vt->ty == TY::Tarray) {
return makeLValue(loc, dval);
}
bool isStaticArray = vt->ty == TY::Tsarray;
LLValue *val = isStaticArray ? DtoLVal(dval) : makeLValue(loc, dval);
LLStructType *i8arrty = DtoArrayType(LLType::getInt8Ty(gIR->context()));
LLValue *array = DtoRawAlloca(i8arrty, 0, ".array");
LLValue *len = isStaticArray ? DtoArrayLen(dval) : DtoConstSize_t(1);
DtoStore(len, DtoGEP(i8arrty, array, 0u, 0));
DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEP(i8arrty, array, 0, 1));
return array;
}
static llvm::StructType *DtoSlicePtrType(DValue *dval) {
if(dval->type->toBasetype()->ty == TY::Tarray)
return isaStruct(DtoType(dval->type->toBasetype()));
else
return DtoArrayType(LLType::getInt8Ty(gIR->context()));
}
static LLValue *DtoSlicePtr(Expression *e) {
return DtoSlicePtr(toElem(e));
}
DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1, DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
Expression *exp2) { Expression *exp2) {
IF_LOG Logger::println("DtoCatAssignArray"); IF_LOG Logger::println("DtoCatAssignArray");
@ -867,7 +879,8 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
// Create array of slices // Create array of slices
typedef llvm::SmallVector<llvm::Value *, 16> ArgVector; typedef llvm::SmallVector<llvm::Value *, 16> ArgVector;
ArgVector arrs; ArgVector arrs;
arrs.push_back(DtoSlicePtr(exp2)); DValue * dval = toElem(exp2);
arrs.push_back(DtoSlicePtr(dval));
do { do {
arrs.push_back(DtoSlicePtr(ce->e2)); arrs.push_back(DtoSlicePtr(ce->e2));
ce = static_cast<CatExp *>(ce->e1); ce = static_cast<CatExp *>(ce->e1);
@ -877,24 +890,24 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
// Create static array from slices // Create static array from slices
LLPointerType *ptrarraytype = isaPointer(arrs[0]); LLPointerType *ptrarraytype = isaPointer(arrs[0]);
assert(ptrarraytype && "Expected pointer type"); assert(ptrarraytype && "Expected pointer type");
LLStructType *arraytype = isaStruct(ptrarraytype->getPointerElementType()); LLStructType *arraytype = DtoSlicePtrType(dval);
assert(arraytype && "Expected struct type"); assert(arraytype && "Expected struct type");
LLArrayType *type = LLArrayType::get(arraytype, arrs.size()); LLArrayType *type = LLArrayType::get(arraytype, arrs.size());
LLValue *array = DtoRawAlloca(type, 0, ".slicearray"); LLValue *array = DtoRawAlloca(type, 0, ".slicearray");
unsigned int i = 0; unsigned int i = 0;
for (ArgVector::reverse_iterator I = arrs.rbegin(), E = arrs.rend(); I != E; for (ArgVector::reverse_iterator I = arrs.rbegin(), E = arrs.rend(); I != E;
++I) { ++I) {
LLValue *v = DtoLoad(DtoBitCast(*I, ptrarraytype)); LLValue *v = DtoLoad(arraytype, DtoBitCast(*I, ptrarraytype));
DtoStore(v, DtoGEP(array, 0, i++, ".slice")); DtoStore(v, DtoGEP(type, array, 0, i++, ".slice"));
} }
LLStructType *type2 = DtoArrayType(arraytype); LLStructType *type2 = DtoArrayType(arraytype);
LLValue *array2 = DtoRawAlloca(type2, 0, ".array"); LLValue *array2 = DtoRawAlloca(type2, 0, ".array");
DtoStore(DtoConstSize_t(arrs.size()), DtoGEP(array2, 0u, 0, ".len")); DtoStore(DtoConstSize_t(arrs.size()), DtoGEP(type2, array2, 0u, 0, ".len"));
DtoStore(DtoBitCast(array, ptrarraytype), DtoGEP(array2, 0, 1, ".ptr")); DtoStore(DtoBitCast(array, ptrarraytype), DtoGEP(type2, array2, 0, 1, ".ptr"));
LLValue *val = LLType *bytearrarr = DtoArrayType(DtoArrayType(LLType::getInt8Ty(gIR->context())));
DtoLoad(DtoBitCast(array2, getPtrToType(DtoArrayType(DtoArrayType( LLType *pbytearrarr = getPtrToType(bytearrarr);
LLType::getInt8Ty(gIR->context())))))); LLValue *val = DtoLoad(bytearrarr, DtoBitCast(array2, pbytearrarr));
// TypeInfo ti // TypeInfo ti
args.push_back(DtoTypeInfoOf(loc, arrayType)); args.push_back(DtoTypeInfoOf(loc, arrayType));
@ -905,14 +918,14 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
// TypeInfo ti // TypeInfo ti
args.push_back(DtoTypeInfoOf(loc, arrayType)); args.push_back(DtoTypeInfoOf(loc, arrayType));
// byte[] x
LLValue *val = DtoLoad(DtoSlicePtr(exp1)); auto loadArray = [fn](Expression* e, int paramTypeIdx) {
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1)); DValue * dval = toElem(e);
args.push_back(val); LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(e));
// byte[] y return DtoAggrPaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
val = DtoLoad(DtoSlicePtr(exp2)); };
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2)); args.push_back(loadArray(exp1,1));
args.push_back(val); args.push_back(loadArray(exp2,2));
} }
auto newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray"); auto newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray");
@ -1168,7 +1181,8 @@ LLValue *DtoArrayLen(DValue *v) {
return DtoConstSize_t(0); return DtoConstSize_t(0);
} }
if (v->isLVal()) { if (v->isLVal()) {
return DtoLoad(DtoGEP(DtoLVal(v), 0u, 0), ".len"); return DtoLoad(DtoSize_t(),
DtoGEP(DtoType(v->type), DtoLVal(v), 0u, 0), ".len");
} }
auto slice = v->isSlice(); auto slice = v->isSlice();
assert(slice); assert(slice);
@ -1198,7 +1212,7 @@ LLValue *DtoArrayPtr(DValue *v) {
if (v->isNull()) { if (v->isNull()) {
ptr = getNullPtr(wantedLLPtrType); ptr = getNullPtr(wantedLLPtrType);
} else if (v->isLVal()) { } else if (v->isLVal()) {
ptr = DtoLoad(DtoGEP(DtoLVal(v), 0, 1), ".ptr"); ptr = DtoLoad(wantedLLPtrType, DtoGEP(DtoType(v->type), DtoLVal(v), 0, 1), ".ptr");
} else { } else {
auto slice = v->isSlice(); auto slice = v->isSlice();
assert(slice); assert(slice);

View file

@ -53,11 +53,12 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale);
/// Initializes a chunk of memory with the contents of an array literal. /// Initializes a chunk of memory with the contents of an array literal.
/// ///
/// dstMem is expected to be a pointer to the array allocation. /// dstMem is expected to be a pointer to the array allocation.
void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale, LLValue *dstMem); void initializeArrayLiteral(IRState *p, ArrayLiteralExp *ale,
LLValue *dstMem, LLType *dstType);
void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op, void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
bool canSkipPostblit); bool canSkipPostblit);
void DtoSetArrayToNull(LLValue *v); void DtoSetArrayToNull(DValue *v);
DSliceValue *DtoNewDynArray(const Loc &loc, Type *arrayType, DValue *dim, DSliceValue *DtoNewDynArray(const Loc &loc, Type *arrayType, DValue *dim,
bool defaultInit = true); bool defaultInit = true);

View file

@ -200,6 +200,7 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
LLSmallVector<LLValue *, 8> outputLVals; LLSmallVector<LLValue *, 8> outputLVals;
LLSmallVector<LLType *, 8> outputTypes; LLSmallVector<LLType *, 8> outputTypes;
LLSmallVector<LLType *, 8> indirectTypes;
LLSmallVector<LLValue *, 8> operands; LLSmallVector<LLValue *, 8> operands;
if (stmt->args) { if (stmt->args) {
for (size_t i = 0; i < stmt->args->length; ++i) { for (size_t i = 0; i < stmt->args->length; ++i) {
@ -212,9 +213,10 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
LLValue *lval = DtoLVal(e); LLValue *lval = DtoLVal(e);
if (isIndirect) { if (isIndirect) {
operands.push_back(lval); operands.push_back(lval);
indirectTypes.push_back(DtoType(e->type));
} else { } else {
outputLVals.push_back(lval); outputLVals.push_back(lval);
outputTypes.push_back(lval->getType()->getPointerElementType()); outputTypes.push_back(DtoType(e->type));
} }
} else { } else {
if (isIndirect && !e->isLvalue()) { if (isIndirect && !e->isLvalue()) {
@ -227,6 +229,8 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
LLValue *inputVal = isIndirect ? DtoLVal(e) : DtoRVal(e); LLValue *inputVal = isIndirect ? DtoLVal(e) : DtoRVal(e);
operands.push_back(inputVal); operands.push_back(inputVal);
if (isIndirect)
indirectTypes.push_back(DtoType(e->type));
} }
} }
} }
@ -238,7 +242,8 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
: LLStructType::get(irs->context(), outputTypes); : LLStructType::get(irs->context(), outputTypes);
LLValue *rval = LLValue *rval =
DtoInlineAsmExpr(stmt->loc, insn, constraints, operands, returnType); DtoInlineAsmExpr(stmt->loc, insn, constraints, operands,
indirectTypes, returnType);
if (N == 1) { if (N == 1) {
DtoStore(rval, outputLVals[0]); DtoStore(rval, outputLVals[0]);

View file

@ -182,9 +182,10 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
static std::string memory_name = "memory"; static std::string memory_name = "memory";
AsmCode *code = static_cast<AsmCode *>(stmt->asmcode); AsmCode *code = static_cast<AsmCode *>(stmt->asmcode);
std::vector<LLValue *> input_values; auto asmStmt = new IRAsmStmt;
asmStmt->isBranchToLabel = stmt->isBranchToLabel;
std::vector<std::string> input_constraints; std::vector<std::string> input_constraints;
std::vector<LLValue *> output_values;
std::vector<std::string> output_constraints; std::vector<std::string> output_constraints;
std::vector<std::string> clobbers; std::vector<std::string> clobbers;
@ -264,11 +265,11 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
if (is_input) { if (is_input) {
arg_map[i] = --input_idx; arg_map[i] = --input_idx;
input_values.push_back(arg_val); asmStmt->in.ops.push_back(arg_val);
input_constraints.push_back(cns); input_constraints.push_back(cns);
} else { } else {
arg_map[i] = n_outputs++; arg_map[i] = n_outputs++;
output_values.push_back(arg_val); asmStmt->out.ops.push_back(arg_val);
output_constraints.push_back(cns); output_constraints.push_back(cns);
} }
} }
@ -346,8 +347,6 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
} }
// rewrite GCC-style constraints to LLVM-style constraints // rewrite GCC-style constraints to LLVM-style constraints
std::string llvmOutConstraints;
std::string llvmInConstraints;
int n = 0; int n = 0;
for (auto &oc : output_constraints) { for (auto &oc : output_constraints) {
// rewrite update constraint to in and out constraints // rewrite update constraint to in and out constraints
@ -367,17 +366,17 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
// Must be at the back; unused operands before used ones screw up // Must be at the back; unused operands before used ones screw up
// numbering. // numbering.
input_constraints.push_back(ss.str()); input_constraints.push_back(ss.str());
input_values.push_back(output_values[n]); asmStmt->in.ops.push_back(asmStmt->out.ops[n]);
} }
llvmOutConstraints += oc; asmStmt->out.c += oc;
llvmOutConstraints += ","; asmStmt->out.c += ",";
n++; n++;
} }
asmblock->outputcount += n; asmblock->outputcount += n;
for (const auto &ic : input_constraints) { for (const auto &ic : input_constraints) {
llvmInConstraints += ic; asmStmt->in.c += ic;
llvmInConstraints += ","; asmStmt->in.c += ",";
} }
std::string clobstr; std::string clobstr;
@ -391,7 +390,7 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
Logger::println("Output values:"); Logger::println("Output values:");
LOG_SCOPE LOG_SCOPE
size_t i = 0; size_t i = 0;
for (auto ov : output_values) { for (auto ov : asmStmt->out.ops) {
Logger::cout() << "Out " << i++ << " = " << *ov << '\n'; Logger::cout() << "Out " << i++ << " = " << *ov << '\n';
} }
} }
@ -399,7 +398,7 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
Logger::println("Input values:"); Logger::println("Input values:");
LOG_SCOPE LOG_SCOPE
size_t i = 0; size_t i = 0;
for (auto iv : input_values) { for (auto iv : asmStmt->in.ops) {
Logger::cout() << "In " << i++ << " = " << *iv << '\n'; Logger::cout() << "In " << i++ << " = " << *iv << '\n';
} }
} }
@ -410,50 +409,20 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
replace_func_name(irs, code->insnTemplate); replace_func_name(irs, code->insnTemplate);
// push asm statement // push asm statement
auto asmStmt = new IRAsmStmt;
asmStmt->code = code->insnTemplate; asmStmt->code = code->insnTemplate;
asmStmt->out_c = llvmOutConstraints;
asmStmt->in_c = llvmInConstraints;
asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(),
output_values.end());
asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(),
input_values.end());
asmStmt->isBranchToLabel = stmt->isBranchToLabel;
asmblock->s.push_back(asmStmt); asmblock->s.push_back(asmStmt);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// rewrite argument indices to the block scope indices // rewrite argument indices to the block scope indices
static void remap_outargs(std::string &insnt, size_t nargs, size_t idx) { static void remap_args(std::string &insnt, size_t nargs, size_t idx,
const std::string& prefix) {
static const std::string digits[10] = {"0", "1", "2", "3", "4", static const std::string digits[10] = {"0", "1", "2", "3", "4",
"5", "6", "7", "8", "9"}; "5", "6", "7", "8", "9"};
assert(nargs <= 10); assert(nargs <= 10);
static const std::string prefix("<<out");
static const std::string suffix(">>");
std::string argnum;
std::string needle;
char buf[10];
for (unsigned i = 0; i < nargs; i++) {
needle = prefix + digits[i] + suffix;
size_t pos = insnt.find(needle);
if (std::string::npos != pos) {
sprintf(buf, "%llu", static_cast<unsigned long long>(idx++));
}
while (std::string::npos != (pos = insnt.find(needle))) {
insnt.replace(pos, needle.size(), buf);
}
}
}
// rewrite argument indices to the block scope indices
static void remap_inargs(std::string &insnt, size_t nargs, size_t idx) {
static const std::string digits[10] = {"0", "1", "2", "3", "4",
"5", "6", "7", "8", "9"};
assert(nargs <= 10);
static const std::string prefix("<<in");
static const std::string suffix(">>"); static const std::string suffix(">>");
std::string argnum; std::string argnum;
std::string needle; std::string needle;
@ -579,8 +548,8 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
code << "movl $<<in" << n_goto << ">>, $<<out0>>\n"; code << "movl $<<in" << n_goto << ">>, $<<out0>>\n";
// 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.push_back(DtoConstUint(n_goto)); outSetterStmt->in.ops.push_back(DtoConstUint(n_goto));
outSetterStmt->in_c += "i,"; outSetterStmt->in.c += "i,";
code << asmGotoEnd; code << asmGotoEnd;
++n_goto; ++n_goto;
@ -593,8 +562,8 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
// create storage for and initialize the temporary // create storage for and initialize the temporary
jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target"); jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target");
// setup variable for output from asm // setup variable for output from asm
outSetterStmt->out_c = "=*m,"; outSetterStmt->out.c = "=*m,";
outSetterStmt->out.push_back(jump_target); outSetterStmt->out.ops.push_back(jump_target);
asmblock->s.push_back(outSetterStmt); asmblock->s.push_back(outSetterStmt);
} else { } else {
@ -616,12 +585,11 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
} }
// build asm block // build asm block
std::vector<LLValue *> outargs; struct ArgBlock {
std::vector<LLValue *> inargs; std::vector<LLValue *> args;
std::vector<LLType *> outtypes; std::vector<LLType *> types;
std::vector<LLType *> intypes; std::string c;
std::string out_c; } in, out;
std::string in_c;
std::string clobbers; std::string clobbers;
std::string code; std::string code;
size_t asmIdx = asmblock->retn; size_t asmIdx = asmblock->retn;
@ -631,15 +599,15 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
IRAsmStmt *a = asmblock->s[i]; IRAsmStmt *a = asmblock->s[i];
assert(a); assert(a);
size_t onn = a->out.size(); size_t onn = a->out.ops.size();
for (size_t j = 0; j < onn; ++j) { for (size_t j = 0; j < onn; ++j) {
outargs.push_back(a->out[j]); out.args.push_back(a->out.ops[j]);
outtypes.push_back(a->out[j]->getType()); out.types.push_back(a->out.ops[j]->getType());
} }
if (!a->out_c.empty()) { if (!a->out.c.empty()) {
out_c += a->out_c; out.c += a->out.c;
} }
remap_outargs(a->code, onn + a->in.size(), asmIdx); remap_args(a->code, onn + a->in.ops.size(), asmIdx, "<<out");
asmIdx += onn; asmIdx += onn;
} }
@ -647,15 +615,15 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
IRAsmStmt *a = asmblock->s[i]; IRAsmStmt *a = asmblock->s[i];
assert(a); assert(a);
size_t inn = a->in.size(); size_t inn = a->in.ops.size();
for (size_t j = 0; j < inn; ++j) { for (size_t j = 0; j < inn; ++j) {
inargs.push_back(a->in[j]); in.args.push_back(a->in.ops[j]);
intypes.push_back(a->in[j]->getType()); in.types.push_back(a->in.ops[j]->getType());
} }
if (!a->in_c.empty()) { if (!a->in.c.empty()) {
in_c += a->in_c; in.c += a->in.c;
} }
remap_inargs(a->code, inn + a->out.size(), asmIdx); remap_args(a->code, inn + a->out.ops.size(), asmIdx, "<<in");
asmIdx += inn; asmIdx += inn;
if (!code.empty()) { if (!code.empty()) {
code += "\n\t"; code += "\n\t";
@ -665,21 +633,21 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
asmblock->s.clear(); asmblock->s.clear();
// append inputs // append inputs
out_c += in_c; out.c += in.c;
// append clobbers // append clobbers
for (const auto &c : asmblock->clobs) { for (const auto &c : asmblock->clobs) {
out_c += c; out.c += c;
} }
// remove excessive comma // remove excessive comma
if (!out_c.empty()) { if (!out.c.empty()) {
out_c.resize(out_c.size() - 1); out.c.resize(out.c.size() - 1);
} }
IF_LOG { IF_LOG {
Logger::println("code = \"%s\"", code.c_str()); Logger::println("code = \"%s\"", code.c_str());
Logger::println("constraints = \"%s\"", out_c.c_str()); Logger::println("constraints = \"%s\"", out.c.c_str());
} }
// build return types // build return types
@ -692,14 +660,14 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
// build argument types // build argument types
std::vector<LLType *> types; std::vector<LLType *> types;
types.insert(types.end(), outtypes.begin(), outtypes.end()); types.insert(types.end(), out.types.begin(), out.types.end());
types.insert(types.end(), intypes.begin(), intypes.end()); types.insert(types.end(), in.types.begin(), in.types.end());
llvm::FunctionType *fty = llvm::FunctionType::get(retty, types, false); llvm::FunctionType *fty = llvm::FunctionType::get(retty, types, false);
IF_LOG Logger::cout() << "function type = " << *fty << '\n'; IF_LOG Logger::cout() << "function type = " << *fty << '\n';
std::vector<LLValue *> args; std::vector<LLValue *> args;
args.insert(args.end(), outargs.begin(), outargs.end()); args.insert(args.end(), out.args.begin(), out.args.end());
args.insert(args.end(), inargs.begin(), inargs.end()); args.insert(args.end(), in.args.begin(), in.args.end());
IF_LOG { IF_LOG {
Logger::cout() << "Arguments:" << '\n'; Logger::cout() << "Arguments:" << '\n';
@ -717,9 +685,9 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
Logger::undent(); Logger::undent();
} }
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, {});
if (!retty->isVoidTy()) { if (!retty->isVoidTy()) {
call->setName("asm"); call->setName("asm");
} }
@ -732,7 +700,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
if (block->retfixup) { if (block->retfixup) {
block->asmBlock->abiret = (*block->retfixup)(p->ir, call); block->asmBlock->abiret = (*block->retfixup)(p->ir, call);
} else if (p->asmBlock->retemu) { } else if (p->asmBlock->retemu) {
block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret); block->asmBlock->abiret = DtoLoad(block->retty, block->asmBlock->abiret);
} else { } else {
block->asmBlock->abiret = call; block->asmBlock->abiret = call;
} }
@ -747,7 +715,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
// make new blocks // make new blocks
llvm::BasicBlock *bb = p->insertBB("afterasmgotoforwarder"); llvm::BasicBlock *bb = p->insertBB("afterasmgotoforwarder");
auto val = DtoLoad(jump_target, "__llvm_jump_target_value"); auto val = DtoLoad(LLType::getInt32Ty(gIR->context()), jump_target, "__llvm_jump_target_value");
llvm::SwitchInst *sw = p->ir->CreateSwitch(val, bb, gotoToVal.size()); llvm::SwitchInst *sw = p->ir->CreateSwitch(val, bb, gotoToVal.size());
// add all cases // add all cases

View file

@ -89,12 +89,14 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset,
// pointer elements. We try to undo this before resorting to // pointer elements. We try to undo this before resorting to
// temporarily bitcasting the pointer to i8. // temporarily bitcasting the pointer to i8.
LLType * llBaseTy = nullptr;
LLValue *llBase = nullptr; LLValue *llBase = nullptr;
LLValue *llOffset = nullptr; LLValue *llOffset = nullptr;
LLValue *llResult = nullptr; LLValue *llResult = nullptr;
if (offset->isConst()) { if (offset->isConst()) {
llBase = DtoRVal(base); llBase = DtoRVal(base);
llBaseTy = DtoMemType(base->type->nextOf());
dinteger_t byteOffset = offset->toInteger(); dinteger_t byteOffset = offset->toInteger();
if (byteOffset == 0) { if (byteOffset == 0) {
llResult = llBase; llResult = llBase;
@ -107,15 +109,18 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset,
auto rvals = auto rvals =
evalSides(base, noStrideInc ? noStrideInc : offset, loadLhsAfterRhs); evalSides(base, noStrideInc ? noStrideInc : offset, loadLhsAfterRhs);
llBase = DtoRVal(rvals.lhs); llBase = DtoRVal(rvals.lhs);
llBaseTy = DtoMemType(rvals.lhs->type->nextOf());
llOffset = DtoRVal(rvals.rhs); llOffset = DtoRVal(rvals.rhs);
if (!noStrideInc) // byte offset => cast base to i8* if (!noStrideInc) { // byte offset => cast base to i8*
llBaseTy = LLType::getInt8Ty(gIR->context());
llBase = DtoBitCast(llBase, getVoidPtrType()); llBase = DtoBitCast(llBase, getVoidPtrType());
}
} }
if (!llResult) { if (!llResult) {
if (negateOffset) if (negateOffset)
llOffset = gIR->ir->CreateNeg(llOffset); llOffset = gIR->ir->CreateNeg(llOffset);
llResult = DtoGEP1(llBase, llOffset); llResult = DtoGEP1(llBaseTy, llBase, llOffset);
} }
return new DImValue(resultType, DtoBitCast(llResult, DtoType(resultType))); return new DImValue(resultType, DtoBitCast(llResult, DtoType(resultType)));

View file

@ -157,6 +157,7 @@ class MultiSetter {
public: public:
// end with a nullptr // end with a nullptr
MultiSetter(bool invert, CHECKENABLE *p, ...); MultiSetter(bool invert, CHECKENABLE *p, ...);
MultiSetter() = default;
void operator=(bool val); void operator=(bool val);
}; };

View file

@ -105,7 +105,7 @@ DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
LOG_SCOPE; LOG_SCOPE;
unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
LLValue *src = DtoRVal(newexp->thisexp); LLValue *src = DtoRVal(newexp->thisexp);
LLValue *dst = DtoGEP(mem, 0, idx); LLValue *dst = DtoGEP(getIrAggr(tc->sym)->getLLStructType(), mem, 0, idx);
IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
} }
@ -141,9 +141,10 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
DtoResolveClass(tc->sym); DtoResolveClass(tc->sym);
IrClass *irClass = getIrAggr(tc->sym); IrClass *irClass = getIrAggr(tc->sym);
llvm::StructType *st = irClass->getLLStructType();
// Set vtable field. Doing this seperately might be optimized better. // Set vtable field. Doing this seperately might be optimized better.
LLValue *tmp = DtoGEP(dst, 0u, 0, "vtbl"); LLValue *tmp = DtoGEP(st, dst, 0u, 0, "vtbl");
LLValue *val = LLValue *val =
DtoBitCast(irClass->getVtblSymbol(), tmp->getType()->getContainedType(0)); DtoBitCast(irClass->getVtblSymbol(), tmp->getType()->getContainedType(0));
DtoStore(val, tmp); DtoStore(val, tmp);
@ -151,7 +152,7 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
// 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(dst, 0, 1, "monitor"); tmp = DtoGEP(st, dst, 0, 1, "monitor");
val = LLConstant::getNullValue(tmp->getType()->getContainedType(0)); val = LLConstant::getNullValue(tmp->getType()->getContainedType(0));
DtoStore(val, tmp); DtoStore(val, tmp);
} }
@ -164,12 +165,12 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
return; return;
} }
LLValue *dstarr = DtoGEP(dst, 0, firstDataIdx); LLValue *dstarr = DtoGEP(st, dst, 0, firstDataIdx);
// init symbols might not have valid types // init symbols might not have valid types
LLValue *initsym = irClass->getInitSymbol(); LLValue *initsym = irClass->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(tc)); initsym = DtoBitCast(initsym, DtoType(tc));
LLValue *srcarr = DtoGEP(initsym, 0, firstDataIdx); LLValue *srcarr = DtoGEP(st, initsym, 0, firstDataIdx);
DtoMemCpy(dstarr, srcarr, DtoConstSize_t(dataBytes)); DtoMemCpy(dstarr, srcarr, DtoConstSize_t(dataBytes));
} }
@ -187,7 +188,8 @@ void DtoFinalizeClass(const Loc &loc, LLValue *inst) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DtoFinalizeScopeClass(const Loc &loc, LLValue *inst, bool hasDtor) { void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor) {
llvm::Value* inst = DtoRVal(dval);
if (!isOptimizationEnabled() || hasDtor) { if (!isOptimizationEnabled() || hasDtor) {
DtoFinalizeClass(loc, inst); DtoFinalizeClass(loc, inst);
return; return;
@ -198,7 +200,9 @@ void DtoFinalizeScopeClass(const Loc &loc, LLValue *inst, bool hasDtor) {
llvm::BasicBlock *ifbb = gIR->insertBB("if"); llvm::BasicBlock *ifbb = gIR->insertBB("if");
llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif"); llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif");
const auto monitor = DtoLoad(DtoGEP(inst, 0, 1), ".monitor"); llvm::StructType *st = getIrAggr(static_cast<TypeClass *>(dval->type)->sym)
->getLLStructType();
const auto monitor = DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor");
const auto hasMonitor = const auto hasMonitor =
gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor, gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor,
getNullValue(monitor->getType()), ".hasMonitor"); getNullValue(monitor->getType()), ".hasMonitor");
@ -280,7 +284,7 @@ DValue *DtoCastClass(const Loc &loc, DValue *val, Type *_to) {
if (offset != 0) { if (offset != 0) {
assert(offset > 0); assert(offset > 0);
v = DtoBitCast(v, getVoidPtrType()); v = DtoBitCast(v, getVoidPtrType());
v = DtoGEP1(v, DtoConstUint(offset)); v = DtoGEP1(LLType::getInt8Ty(gIR->context()), v, DtoConstUint(offset));
} }
IF_LOG { IF_LOG {
Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "V = " << *v << std::endl;
@ -405,7 +409,8 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
// sanity checks // sanity checks
assert(fdecl->isVirtual()); assert(fdecl->isVirtual());
assert(!fdecl->isFinalFunc()); assert(!fdecl->isFinalFunc());
assert(inst->type->toBasetype()->ty == TY::Tclass); TypeClass * tc = inst->type->toBasetype()->isTypeClass();
assert(tc);
// slot 0 is always ClassInfo/Interface* unless it is a CPP class // slot 0 is always ClassInfo/Interface* unless it is a CPP class
assert(fdecl->vtblIndex > 0 || assert(fdecl->vtblIndex > 0 ||
(fdecl->vtblIndex == 0 && (fdecl->vtblIndex == 0 &&
@ -415,17 +420,20 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
LLValue *vthis = DtoRVal(inst); LLValue *vthis = DtoRVal(inst);
IF_LOG Logger::cout() << "vthis: " << *vthis << '\n'; IF_LOG Logger::cout() << "vthis: " << *vthis << '\n';
IrClass * irc = getIrAggr(tc->sym, true);
LLValue *funcval = vthis; LLValue *funcval = vthis;
// get the vtbl for objects // get the vtbl for objects
funcval = DtoGEP(funcval, 0u, 0); llvm::GlobalVariable* vtblsym = irc->getVtblSymbol();
funcval = DtoGEP(irc->getLLStructType(), funcval, 0u, 0);
// load vtbl ptr // load vtbl ptr
funcval = DtoLoad(funcval); funcval = DtoLoad(vtblsym->getType(), funcval);
// index vtbl // index vtbl
const std::string name = fdecl->toChars(); const std::string name = fdecl->toChars();
const auto vtblname = name + "@vtbl"; const auto vtblname = name + "@vtbl";
funcval = DtoGEP(funcval, 0, fdecl->vtblIndex, vtblname.c_str()); funcval = DtoGEP(vtblsym->getValueType(),
funcval, 0, fdecl->vtblIndex, vtblname.c_str());
// load opaque pointer // load opaque pointer
funcval = DtoAlignedLoad(funcval); funcval = DtoAlignedLoad(getVoidPtrType(), funcval);
IF_LOG Logger::cout() << "funcval: " << *funcval << '\n'; IF_LOG Logger::cout() << "funcval: " << *funcval << '\n';

View file

@ -18,6 +18,7 @@
class ClassDeclaration; class ClassDeclaration;
class CtorDeclaration; class CtorDeclaration;
class DValue;
class FuncDeclaration; class FuncDeclaration;
class NewExp; class NewExp;
class TypeClass; class TypeClass;
@ -28,7 +29,7 @@ void DtoResolveClass(ClassDeclaration *cd);
DValue *DtoNewClass(const Loc &loc, TypeClass *type, NewExp *newexp); DValue *DtoNewClass(const Loc &loc, TypeClass *type, NewExp *newexp);
void DtoInitClass(TypeClass *tc, llvm::Value *dst); void DtoInitClass(TypeClass *tc, llvm::Value *dst);
void DtoFinalizeClass(const Loc &loc, llvm::Value *inst); void DtoFinalizeClass(const Loc &loc, llvm::Value *inst);
void DtoFinalizeScopeClass(const Loc &loc, llvm::Value *inst, bool hasDtor); void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor);
DValue *DtoCastClass(const Loc &loc, DValue *val, Type *to); DValue *DtoCastClass(const Loc &loc, DValue *val, Type *to);
DValue *DtoDynamicCastObject(const Loc &loc, DValue *val, Type *to); DValue *DtoDynamicCastObject(const Loc &loc, DValue *val, Type *to);

View file

@ -107,9 +107,9 @@ DValue *DtoComplex(const Loc &loc, Type *to, DValue *val) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DtoComplexSet(LLValue *c, LLValue *re, LLValue *im) { void DtoComplexSet(LLType* ty, LLValue *c, LLValue *re, LLValue *im) {
DtoStore(re, DtoGEP(c, 0u, 0)); DtoStore(re, DtoGEP(ty, c, 0u, 0));
DtoStore(im, DtoGEP(c, 0, 1)); DtoStore(im, DtoGEP(ty, c, 0, 1));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -141,8 +141,8 @@ void DtoGetComplexParts(const Loc &loc, Type *to, DValue *val, DValue *&re,
DValue *v = DtoCastComplex(loc, val, to); DValue *v = DtoCastComplex(loc, val, to);
if (to->iscomplex()) { if (to->iscomplex()) {
if (v->isLVal()) { if (v->isLVal()) {
LLValue *reVal = DtoGEP(DtoLVal(v), 0u, 0, ".re_part"); LLValue *reVal = DtoGEP(DtoType(v->type), DtoLVal(v), 0u, 0, ".re_part");
LLValue *imVal = DtoGEP(DtoLVal(v), 0, 1, ".im_part"); LLValue *imVal = DtoGEP(DtoType(v->type), DtoLVal(v), 0, 1, ".im_part");
re = new DLValue(baserety, reVal); re = new DLValue(baserety, reVal);
im = new DLValue(baseimty, imVal); im = new DLValue(baseimty, imVal);
} else { } else {

View file

@ -34,7 +34,7 @@ llvm::Constant *DtoComplexShuffleMask(unsigned a, unsigned b);
DValue *DtoComplex(const Loc &loc, Type *to, DValue *val); DValue *DtoComplex(const Loc &loc, Type *to, DValue *val);
void DtoComplexSet(llvm::Value *c, llvm::Value *re, llvm::Value *im); void DtoComplexSet(llvm::Type*, llvm::Value *c, llvm::Value *re, llvm::Value *im);
void DtoGetComplexParts(const Loc &loc, Type *to, DValue *c, DValue *&re, void DtoGetComplexParts(const Loc &loc, Type *to, DValue *c, DValue *&re,
DValue *&im); DValue *&im);

View file

@ -18,13 +18,13 @@
struct DComputePointerRewrite : ABIRewrite { struct DComputePointerRewrite : ABIRewrite {
LLValue *put(DValue *v, bool isLValueExp, bool) override { LLValue *put(DValue *v, bool isLValueExp, bool) override {
LLValue *address = DtoLVal(v); LLValue *address = DtoLVal(v);
address = DtoGEP(address, 0u, 0u); address = DtoGEP(DtoType(v->type), address, 0u, 0u);
return DtoLoad(address, ".DComputePointerRewrite_arg"); return DtoLoad(type(v->type), address, ".DComputePointerRewrite_arg");
} }
LLValue *getLVal(Type *dty, LLValue *v) override { LLValue *getLVal(Type *dty, LLValue *v) override {
LLValue *mem = DtoAlloca(dty, ".DComputePointerRewrite_param_storage"); LLValue *mem = DtoAlloca(dty, ".DComputePointerRewrite_param_storage");
DtoStore(v, DtoGEP(mem, 0u, 0u)); DtoStore(v, DtoGEP(DtoType(dty), mem, 0u, 0u));
return mem; return mem;
} }

View file

@ -545,10 +545,9 @@ DIType DIBuilder::CreateCompositeType(Type *t) {
// Use the actual type associated with the declaration, ignoring any // Use the actual type associated with the declaration, ignoring any
// const/wrappers. // const/wrappers.
LLType *T = DtoType(ad->type); DtoType(ad->type);
if (t->ty == TY::Tclass)
T = T->getPointerElementType();
IrAggr *irAggr = getIrAggr(ad, true); IrAggr *irAggr = getIrAggr(ad, true);
LLType *T = irAggr->getLLStructType();
if (irAggr->diCompositeType) { if (irAggr->diCompositeType) {
return irAggr->diCompositeType; return irAggr->diCompositeType;

View file

@ -131,7 +131,7 @@ DRValue *DLValue::getRVal() {
return nullptr; return nullptr;
} }
LLValue *rval = DtoLoad(val); LLValue *rval = DtoLoad(val->getType()->getPointerElementType(), val);
const auto ty = type->toBasetype()->ty; const auto ty = type->toBasetype()->ty;
if (ty == TY::Tbool) { if (ty == TY::Tbool) {
@ -161,10 +161,12 @@ DSpecialRefValue::DSpecialRefValue(Type *t, LLValue *v) : DLValue(v, t) {
} }
DRValue *DSpecialRefValue::getRVal() { DRValue *DSpecialRefValue::getRVal() {
return DLValue(type, DtoLoad(val)).getRVal(); return DLValue(type, DtoLoad(DtoPtrToType(type), val)).getRVal();
} }
DLValue *DSpecialRefValue::getLVal() { return new DLValue(type, DtoLoad(val)); } DLValue *DSpecialRefValue::getLVal() {
return new DLValue(type, DtoLoad(DtoPtrToType(type), val));
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -355,12 +355,12 @@ void replaceDynamicThreadLocals(llvm::Module &oldModule,
} }
} }
llvm::Constant *getArrayPtr(llvm::Constant *array) { llvm::Constant *getArrayPtr(llvm::Type *type, llvm::Constant *array) {
assert(nullptr != array); assert(nullptr != array);
llvm::ConstantInt *zero = llvm::ConstantInt::get( llvm::ConstantInt *zero = llvm::ConstantInt::get(
llvm::Type::getInt32Ty(array->getContext()), 0, false); llvm::Type::getInt32Ty(array->getContext()), 0, false);
llvm::Constant *idxs[] = {zero, zero}; llvm::Constant *idxs[] = {zero, zero};
return llvm::ConstantExpr::getGetElementPtr(getPointeeType(array), array, return llvm::ConstantExpr::getGetElementPtr(type, array,
idxs, true); idxs, true);
} }
@ -379,7 +379,7 @@ getArrayAndSize(llvm::Module &module, llvm::Type *elemType,
module, arrayType, true, llvm::GlobalValue::PrivateLinkage, module, arrayType, true, llvm::GlobalValue::PrivateLinkage,
llvm::ConstantArray::get(arrayType, elements), ".str"); llvm::ConstantArray::get(arrayType, elements), ".str");
return std::make_pair( return std::make_pair(
getArrayPtr(arrVar), getArrayPtr(arrVar->getValueType() ,arrVar),
llvm::ConstantInt::get(module.getContext(), APInt(32, elements.size()))); llvm::ConstantInt::get(module.getContext(), APInt(32, elements.size())));
} }
@ -394,7 +394,7 @@ void createStaticI8Array(llvm::Module &mod, llvm::GlobalVariable *var,
dataLen), dataLen),
true, llvm::GlobalValue::InternalLinkage, true, llvm::GlobalValue::InternalLinkage,
llvm::ConstantDataArray::get(mod.getContext(), arr), ".str"); llvm::ConstantDataArray::get(mod.getContext(), arr), ".str");
var->setInitializer(getArrayPtr(gvar)); var->setInitializer(getArrayPtr(gvar->getValueType(), gvar));
if (nullptr != varLen) { if (nullptr != varLen) {
varLen->setInitializer( varLen->setInitializer(
llvm::ConstantInt::get(mod.getContext(), APInt(32, dataLen))); llvm::ConstantInt::get(mod.getContext(), APInt(32, dataLen)));

View file

@ -1291,7 +1291,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
LLType *targetThisType = thismem->getType(); LLType *targetThisType = thismem->getType();
thismem = DtoBitCast(thismem, getVoidPtrType()); thismem = DtoBitCast(thismem, getVoidPtrType());
auto off = DtoConstInt(-fd->interfaceVirtual->offset); auto off = DtoConstInt(-fd->interfaceVirtual->offset);
thismem = DtoGEP1(thismem, off); thismem = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), thismem, off);
thismem = DtoBitCast(thismem, targetThisType); thismem = DtoBitCast(thismem, targetThisType);
} }
thismem = DtoAllocaDump(thismem, 0, "this"); thismem = DtoAllocaDump(thismem, 0, "this");

View file

@ -264,7 +264,8 @@ void IRState::addLinkerDependentLib(llvm::StringRef libraryName) {
llvm::CallInst * llvm::CallInst *
IRState::createInlineAsmCall(const Loc &loc, llvm::InlineAsm *ia, IRState::createInlineAsmCall(const Loc &loc, llvm::InlineAsm *ia,
llvm::ArrayRef<llvm::Value *> args) { llvm::ArrayRef<llvm::Value *> args,
llvm::ArrayRef<llvm::Type *> indirectTypes) {
llvm::CallInst *call = ir->CreateCall(ia, args); llvm::CallInst *call = ir->CreateCall(ia, args);
addInlineAsmSrcLoc(loc, call); addInlineAsmSrcLoc(loc, call);
@ -272,11 +273,19 @@ 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();
for (const auto &constraintInfo : ia->ParseConstraints()) { for (const auto &constraintInfo : ia->ParseConstraints()) {
if (constraintInfo.isIndirect) { if (constraintInfo.isIndirect) {
call->addParamAttr(i, llvm::Attribute::get(context(), llvm::Type *indirectType = indirectLen != 0 ?
llvm::Attribute::ElementType, indirectTypes[indirectIdx] :
getPointeeType(args[i]))); args[i]->getType()->getPointerElementType();
call->addParamAttr(i, llvm::Attribute::get(
context(),
llvm::Attribute::ElementType,
indirectType));
++indirectIdx;
} }
++i; ++i;
} }

View file

@ -77,10 +77,11 @@ struct IRAsmStmt {
IRAsmStmt() : isBranchToLabel(nullptr) {} IRAsmStmt() : isBranchToLabel(nullptr) {}
std::string code; std::string code;
std::string out_c; struct Operands {
std::string in_c; std::string c; // contraint
std::vector<LLValue *> out; std::vector<LLValue *> ops;
std::vector<LLValue *> in; };
Operands out, in;
// if this is nonzero, it contains the target label // if this is nonzero, it contains the target label
LabelDsymbol *isBranchToLabel; LabelDsymbol *isBranchToLabel;
@ -267,7 +268,8 @@ public:
void addLinkerDependentLib(llvm::StringRef libraryName); void addLinkerDependentLib(llvm::StringRef libraryName);
llvm::CallInst *createInlineAsmCall(const Loc &loc, llvm::InlineAsm *ia, llvm::CallInst *createInlineAsmCall(const Loc &loc, llvm::InlineAsm *ia,
llvm::ArrayRef<llvm::Value *> args); llvm::ArrayRef<llvm::Value *> args,
llvm::ArrayRef<llvm::Type *> indirectTypes);
void addInlineAsmSrcLoc(const Loc &loc, llvm::CallInst *inlineAsmCall); void addInlineAsmSrcLoc(const Loc &loc, llvm::CallInst *inlineAsmCall);
const Loc &getInlineAsmSrcLoc(unsigned srcLocCookie) const; const Loc &getInlineAsmSrcLoc(unsigned srcLocCookie) const;

View file

@ -237,7 +237,7 @@ LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment,
LLType *asMemType = i1ToI8(voidToI8(asType)); LLType *asMemType = i1ToI8(voidToI8(asType));
LLValue *copy = DtoRawAlloca(asMemType, alignment, name); LLValue *copy = DtoRawAlloca(asMemType, alignment, name);
const auto minSize = const auto minSize =
std::min(getTypeAllocSize(lval->getType()->getPointerElementType()), std::min(getTypeAllocSize(DtoType(val->type)),
getTypeAllocSize(asMemType)); getTypeAllocSize(asMemType));
const auto minAlignment = const auto minAlignment =
std::min(DtoAlignment(val->type), static_cast<unsigned>(alignment)); std::min(DtoAlignment(val->type), static_cast<unsigned>(alignment));
@ -1865,7 +1865,7 @@ FuncDeclaration *getParentFunc(Dsymbol *sym) {
return nullptr; return nullptr;
} }
LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
VarDeclaration *vd) { VarDeclaration *vd) {
IF_LOG Logger::println("Indexing aggregate field %s:", vd->toPrettyChars()); IF_LOG Logger::println("Indexing aggregate field %s:", vd->toPrettyChars());
LOG_SCOPE; LOG_SCOPE;
@ -1876,45 +1876,51 @@ LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
DtoResolveDsymbol(ad); DtoResolveDsymbol(ad);
// Look up field to index or offset to apply. // Look up field to index or offset to apply.
unsigned fieldIndex;
unsigned byteOffset;
auto irTypeAggr = getIrType(ad->type)->isAggr(); auto irTypeAggr = getIrType(ad->type)->isAggr();
assert(irTypeAggr); assert(irTypeAggr);
irTypeAggr->getMemberLocation(vd, fieldIndex, byteOffset); bool isFieldIdx;
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
LLValue *ptr = src; LLValue *ptr = src;
if (byteOffset) { if (!isFieldIdx) {
assert(fieldIndex == 0);
// 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(ptr, byteOffset); ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, off);
} else { } else {
if (ad->structsize == 0) { // can happen for extern(C) structs if (ad->structsize == 0) { // can happen for extern(C) structs
assert(fieldIndex == 0); assert(off == 0);
} else { } else {
// Cast the pointer we got to the canonical struct type the indices are // Cast the pointer we got to the canonical struct type the indices are
// based on. // based on.
LLType *st = DtoType(ad->type); LLType *st = nullptr;
if (ad->isStructDeclaration()) { LLType *pst = nullptr;
st = getPtrToType(st); if (ad->isClassDeclaration()) {
st = getIrAggr(ad)->getLLStructType();
pst = DtoType(ad->type);
} }
ptr = DtoBitCast(ptr, st); else {
ptr = DtoGEP(ptr, 0, fieldIndex); st = DtoType(ad->type);
pst = getPtrToType(st);
}
ptr = DtoBitCast(ptr, pst);
ptr = DtoGEP(st, ptr, 0, off);
} }
} }
// Cast the (possibly void*) pointer to the canonical variable type.
ptr = DtoBitCast(ptr, DtoPtrToType(vd->type));
IF_LOG Logger::cout() << "Pointer: " << *ptr << '\n'; IF_LOG Logger::cout() << "Pointer: " << *ptr << '\n';
return ptr; return new DLValue(vd->type, ptr);
} }
unsigned getFieldGEPIndex(AggregateDeclaration *ad, VarDeclaration *vd) { unsigned getFieldGEPIndex(AggregateDeclaration *ad, VarDeclaration *vd) {
unsigned fieldIndex;
unsigned byteOffset;
auto irTypeAggr = getIrType(ad->type)->isAggr(); auto irTypeAggr = getIrType(ad->type)->isAggr();
assert(irTypeAggr); assert(irTypeAggr);
irTypeAggr->getMemberLocation(vd, fieldIndex, byteOffset); bool isFieldIdx;
assert(byteOffset == 0 && "Cannot address field by a simple GEP."); unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
return fieldIndex; assert(isFieldIdx && "Cannot address field by a simple GEP.");
return off;
} }
DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) { DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
@ -1931,6 +1937,7 @@ DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
expectedType = expectedType->getPointerTo(); expectedType = expectedType->getPointerTo();
if (val->getType() != expectedType) { if (val->getType() != expectedType) {
#if LDC_LLVM_VER < 1500
// The type of globals is determined by their initializer, and the front-end // The type of globals is determined by their initializer, and the front-end
// may inject implicit casts for class references and static arrays. // may inject implicit casts for class references and static arrays.
assert(vd->isDataseg() || (vd->storage_class & STCextern) || assert(vd->isDataseg() || (vd->storage_class & STCextern) ||
@ -1943,6 +1950,7 @@ DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
// work as well. // work as well.
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(pointeeType) && assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(pointeeType) &&
"LValue type mismatch, encountered type too small."); "LValue type mismatch, encountered type too small.");
#endif
val = DtoBitCast(val, expectedType); val = DtoBitCast(val, expectedType);
} }

View file

@ -132,7 +132,7 @@ void findDefaultTarget();
/// Returns a pointer to the given member field of an aggregate. /// Returns a pointer to the given member field of an aggregate.
/// ///
/// 'src' is a pointer to the start of the memory of an 'ad' instance. /// 'src' is a pointer to the start of the memory of an 'ad' instance.
LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
VarDeclaration *vd); VarDeclaration *vd);
/// Returns the index of a given member variable in the resulting LLVM type of /// Returns the index of a given member variable in the resulting LLVM type of
@ -150,6 +150,7 @@ DValue *DtoInlineAsmExpr(const Loc &loc, FuncDeclaration *fd,
llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code, llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
llvm::StringRef constraints, llvm::StringRef constraints,
llvm::ArrayRef<llvm::Value *> operands, llvm::ArrayRef<llvm::Value *> operands,
llvm::ArrayRef<llvm::Type *> indirectTypes,
llvm::Type *returnType); llvm::Type *returnType);
/// Returns the llvm::Value of the passed DValue, making sure that it is an /// Returns the llvm::Value of the passed DValue, making sure that it is an
@ -197,12 +198,6 @@ IrFuncTy &DtoIrTypeFunction(DValue *fnval);
/// ///
TypeFunction *DtoTypeFunction(DValue *fnval); TypeFunction *DtoTypeFunction(DValue *fnval);
///
LLValue *DtoCallableValue(DValue *fn);
///
LLFunctionType *DtoExtractFunctionType(LLType *type);
/// Checks whether fndecl is an intrinsic that requires special lowering. If so, /// Checks whether fndecl is an intrinsic that requires special lowering. If so,
/// emits the code for it and returns true, settings result to the resulting /// emits the code for it and returns true, settings result to the resulting
/// DValue (if any). If the call does not correspond to a "magic" intrinsic, /// DValue (if any). If the call does not correspond to a "magic" intrinsic,

View file

@ -85,9 +85,10 @@ llvm::Function *buildForwarderFunction(
// ... incrementing the gate variables. // ... incrementing the gate variables.
for (auto gate : gates) { for (auto gate : gates) {
assert(getIrGlobal(gate)); const auto glob = getIrGlobal(gate);
const auto val = getIrGlobal(gate)->value; assert(glob);
const auto rval = builder.CreateLoad(getPointeeType(val), val, "vgate"); const auto val = glob->value;
const auto rval = builder.CreateLoad(glob->getType(), val, "vgate");
const auto res = builder.CreateAdd(rval, DtoConstUint(1), "vgate"); const auto res = builder.CreateAdd(rval, DtoConstUint(1), "vgate");
builder.CreateStore(res, val); builder.CreateStore(res, val);
} }

View file

@ -268,7 +268,8 @@ void addCoverageAnalysis(Module *m) {
init, "_d_cover_data"); init, "_d_cover_data");
d_cover_data_slice = DtoConstSlice(DtoConstSize_t(m->numlines), d_cover_data_slice = DtoConstSlice(DtoConstSize_t(m->numlines),
DtoGEP(m->d_cover_data, 0, 0)); DtoGEP(m->d_cover_data->getValueType(),
m->d_cover_data, 0, 0));
} }
// Create "static constructor" that calls _d_cover_register2(string filename, // Create "static constructor" that calls _d_cover_register2(string filename,

View file

@ -271,19 +271,19 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass || if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass ||
rt->ty == TY::Taarray) { rt->ty == TY::Taarray) {
if (rt->size() == 8) { if (rt->size() == 8) {
as->out_c = "=A,"; as->out.c = "=A,";
} else { } else {
as->out_c = "={ax},"; as->out.c = "={ax},";
} }
} else if (rt->isfloating()) { } else if (rt->isfloating()) {
if (rt->iscomplex()) { if (rt->iscomplex()) {
if (fdecl->_linkage == LINK::d) { if (fdecl->_linkage == LINK::d) {
// extern(D) always returns on the FPU stack // extern(D) always returns on the FPU stack
as->out_c = "={st},={st(1)},"; as->out.c = "={st},={st(1)},";
asmblock->retn = 2; asmblock->retn = 2;
} else if (rt->ty == TY::Tcomplex32) { } else if (rt->ty == TY::Tcomplex32) {
// non-extern(D) cfloat is returned as i64 // non-extern(D) cfloat is returned as i64
as->out_c = "=A,"; as->out.c = "=A,";
asmblock->retty = LLType::getInt64Ty(gIR->context()); asmblock->retty = LLType::getInt64Ty(gIR->context());
} else { } else {
// non-extern(D) cdouble and creal are returned via sret // non-extern(D) cdouble and creal are returned via sret
@ -293,10 +293,10 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
return; return;
} }
} else { } else {
as->out_c = "={st},"; as->out.c = "={st},";
} }
} else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) { } else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) {
as->out_c = "={ax},={dx},"; as->out.c = "={ax},={dx},";
asmblock->retn = 2; asmblock->retn = 2;
#if 0 #if 0
// this is to show how to allocate a temporary for the return value // this is to show how to allocate a temporary for the return value
@ -306,7 +306,7 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
// numbered output when the asm block in finalized // numbered output when the asm block in finalized
// generate asm // generate asm
as->out_c = "=*m,=*m,"; as->out.c = "=*m,=*m,";
LLValue* tmp = DtoRawAlloca(llretTy, 0, ".tmp_asm_ret"); LLValue* tmp = DtoRawAlloca(llretTy, 0, ".tmp_asm_ret");
as->out.push_back( tmp ); as->out.push_back( tmp );
as->out.push_back( DtoGEP(tmp, 0, 1) ); as->out.push_back( DtoGEP(tmp, 0, 1) );
@ -334,26 +334,26 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
else if (triple.getArch() == llvm::Triple::x86_64) { else if (triple.getArch() == llvm::Triple::x86_64) {
if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass || if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass ||
rt->ty == TY::Taarray) { rt->ty == TY::Taarray) {
as->out_c = "={ax},"; as->out.c = "={ax},";
} else if (rt->isfloating()) { } else if (rt->isfloating()) {
const bool isWin64 = triple.isOSWindows(); const bool isWin64 = triple.isOSWindows();
if (rt == Type::tcomplex80 && !isWin64) { if (rt == Type::tcomplex80 && !isWin64) {
// On x87 stack, re=st, im=st(1) // On x87 stack, re=st, im=st(1)
as->out_c = "={st},={st(1)},"; as->out.c = "={st},={st(1)},";
asmblock->retn = 2; asmblock->retn = 2;
} else if ((rt == Type::tfloat80 || rt == Type::timaginary80) && } else if ((rt == Type::tfloat80 || rt == Type::timaginary80) &&
!triple.isWindowsMSVCEnvironment()) { !triple.isWindowsMSVCEnvironment()) {
// On x87 stack // On x87 stack
as->out_c = "={st},"; as->out.c = "={st},";
} else if (rt == Type::tcomplex32) { } else if (rt == Type::tcomplex32) {
if (isWin64) { if (isWin64) {
// cfloat on Win64 -> %rax // cfloat on Win64 -> %rax
as->out_c = "={ax},"; as->out.c = "={ax},";
asmblock->retty = LLType::getInt64Ty(gIR->context()); asmblock->retty = LLType::getInt64Ty(gIR->context());
} else { } else {
// cfloat on Posix -> %xmm0 (extract two floats) // cfloat on Posix -> %xmm0 (extract two floats)
as->out_c = "={xmm0},"; as->out.c = "={xmm0},";
asmblock->retty = LLType::getDoubleTy(gIR->context()); asmblock->retty = LLType::getDoubleTy(gIR->context());
} }
} else if (rt->iscomplex()) { } else if (rt->iscomplex()) {
@ -365,15 +365,15 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
return; return;
} else { } else {
// cdouble on Posix -> re=%xmm0, im=%xmm1 // cdouble on Posix -> re=%xmm0, im=%xmm1
as->out_c = "={xmm0},={xmm1},"; as->out.c = "={xmm0},={xmm1},";
asmblock->retn = 2; asmblock->retn = 2;
} }
} else { } else {
// Plain float/double/ifloat/idouble // Plain float/double/ifloat/idouble
as->out_c = "={xmm0},"; as->out.c = "={xmm0},";
} }
} else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) { } else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) {
as->out_c = "={ax},={dx},"; as->out.c = "={ax},={dx},";
asmblock->retn = 2; asmblock->retn = 2;
} else { } else {
error(loc, "unimplemented return type `%s` for implicit abi return", error(loc, "unimplemented return type `%s` for implicit abi return",
@ -427,19 +427,51 @@ DValue *DtoInlineAsmExpr(const Loc &loc, FuncDeclaration *fd,
const llvm::StringRef constraints = {constraintsStr.ptr, const llvm::StringRef constraints = {constraintsStr.ptr,
constraintsStr.length}; constraintsStr.length};
auto constraintInfo = llvm::InlineAsm::ParseConstraints(constraints);
// build runtime arguments // build runtime arguments
const size_t n = arguments->length - 2; const size_t n = arguments->length - 2;
LLSmallVector<LLValue *, 8> operands; LLSmallVector<LLValue *, 8> operands;
LLSmallVector<LLType *, 8> indirectTypes;
operands.reserve(n); operands.reserve(n);
for (size_t i = 0; i < n; i++) {
operands.push_back(DtoRVal((*arguments)[2 + i]));
}
Type *returnType = fd->type->nextOf(); Type *returnType = fd->type->nextOf();
const size_t cisize = constraintInfo.size();
const size_t minRequired = n + (returnType->ty == TY::Tvoid ? 0 : 1);
if (cisize < minRequired) {
se->error("insufficient number of constraints (%d) for number of additional arguments %s(%d)",
cisize,
returnType->ty == TY::Tvoid ? "" : "and return type ",
minRequired);
fatal();
}
size_t i = 0;
for (; i < n; i++) {
Expression *ee = (*arguments)[2 + i];
operands.push_back(DtoRVal(ee));
if (constraintInfo[i].isIndirect) {
if (TypePointer *pt = ee->type->isTypePointer())
indirectTypes.push_back(DtoType(pt->nextOf()));
else
indirectTypes.push_back(DtoType(ee->type));
}
}
LLType *irReturnType = DtoType(returnType->toBasetype()); LLType *irReturnType = DtoType(returnType->toBasetype());
for (; i < cisize; i++) {
if (!constraintInfo[i].isIndirect)
continue;
if (constraintInfo[i].Type == llvm::InlineAsm::ConstraintPrefix::isOutput) {
indirectTypes.push_back(DtoType(returnType));
} else {
error(loc, "indirect constraint %d doesn't correspond to an argument or output", (unsigned)i);
fatal();
}
}
LLValue *rv = LLValue *rv =
DtoInlineAsmExpr(loc, code, constraints, operands, irReturnType); DtoInlineAsmExpr(loc, code, constraints, operands, indirectTypes, irReturnType);
// work around missing tuple support for users of the return value // work around missing tuple support for users of the return value
if (sretPointer || returnType->ty == TY::Tstruct) { if (sretPointer || returnType->ty == TY::Tstruct) {
@ -457,6 +489,7 @@ DValue *DtoInlineAsmExpr(const Loc &loc, FuncDeclaration *fd,
llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code, llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
llvm::StringRef constraints, llvm::StringRef constraints,
llvm::ArrayRef<llvm::Value *> operands, llvm::ArrayRef<llvm::Value *> operands,
llvm::ArrayRef<llvm::Type *> indirectTypes,
llvm::Type *returnType) { llvm::Type *returnType) {
IF_LOG Logger::println("DtoInlineAsmExpr @ %s", loc.toChars()); IF_LOG Logger::println("DtoInlineAsmExpr @ %s", loc.toChars());
LOG_SCOPE; LOG_SCOPE;
@ -471,7 +504,13 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
llvm::FunctionType::get(returnType, operandTypes, false); llvm::FunctionType::get(returnType, operandTypes, false);
// make sure the constraints are valid // make sure the constraints are valid
if (!llvm::InlineAsm::Verify(FT, constraints)) { if (!llvm::InlineAsm::
#if LDC_LLVM_VER < 1500
Verify
#else
verify
#endif
(FT, constraints)) {
error(loc, "inline asm constraints are invalid"); error(loc, "inline asm constraints are invalid");
fatal(); fatal();
} }
@ -480,7 +519,7 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
bool sideeffect = true; bool sideeffect = true;
llvm::InlineAsm *ia = llvm::InlineAsm::get(FT, code, constraints, sideeffect); llvm::InlineAsm *ia = llvm::InlineAsm::get(FT, code, constraints, sideeffect);
auto call = gIR->createInlineAsmCall(loc, ia, operands); auto call = gIR->createInlineAsmCall(loc, ia, operands, indirectTypes);
return call; return call;
} }

View file

@ -36,6 +36,22 @@ bool isNRVOVar(VarDeclaration *vd) {
bool captureByRef(VarDeclaration *vd) { bool captureByRef(VarDeclaration *vd) {
return vd->isReference() || isNRVOVar(vd); return vd->isReference() || isNRVOVar(vd);
} }
LLValue *loadThisPtr(AggregateDeclaration *ad, IrFunction &irfunc) {
if (ad->isClassDeclaration()) {
return DtoLoad(DtoType(irfunc.irFty.arg_this->type),
irfunc.thisArg);
}
return irfunc.thisArg;
}
LLValue *indexVThis(AggregateDeclaration *ad, LLValue* val) {
llvm::StructType *st = getIrAggr(ad, true)->getLLStructType();
unsigned idx = getVthisIdx(ad);
return DtoLoad(st->getElementType(idx),
DtoGEP(st, val, 0, idx, ".vthis"));
}
} // anonymous namespace } // anonymous namespace
static void DtoCreateNestedContextType(FuncDeclaration *fd); static void DtoCreateNestedContextType(FuncDeclaration *fd);
@ -80,11 +96,11 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
} else if (AggregateDeclaration *ad = irfunc->decl->isMember2()) { } else if (AggregateDeclaration *ad = irfunc->decl->isMember2()) {
Logger::println( Logger::println(
"Current function is member of nested class, loading vthis"); "Current function is member of nested class, loading vthis");
LLValue *val = LLValue *val = loadThisPtr(ad, *irfunc);
ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg;
for (; ad; ad = ad->toParent2()->isAggregateDeclaration()) { for (; ad; ad = ad->toParent2()->isAggregateDeclaration()) {
assert(ad->vthis); assert(ad->vthis);
val = DtoLoad(DtoGEP(val, 0, getVthisIdx(ad), ".vthis")); val = indexVThis(ad, val);
} }
ctx = val; ctx = val;
skipDIDeclaration = true; skipDIDeclaration = true;
@ -118,10 +134,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
// Extract variable from nested context // Extract variable from nested context
assert(irfunc->frameType); assert(irfunc->frameType);
const auto frameType = LLPointerType::getUnqual(irfunc->frameType); const auto pframeType = LLPointerType::getUnqual(irfunc->frameType);
IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; } IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; }
LLValue *val = DtoBitCast(ctx, frameType); LLValue *val = DtoBitCast(ctx, pframeType);
llvm::StructType *currFrame = irfunc->frameType;
// Make the DWARF variable address relative to the context pointer (ctx); // Make the DWARF variable address relative to the context pointer (ctx);
// register all ops (offsetting, dereferencing) required to get there in the // register all ops (offsetting, dereferencing) required to get there in the
// following list. // following list.
@ -131,14 +147,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
LLSmallVector<int64_t, 4> dwarfAddrOps; LLSmallVector<int64_t, 4> dwarfAddrOps;
#endif #endif
const auto offsetToNthField = [&val, &dwarfAddrOps](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, val, fieldIndex);
val = DtoGEP(val, 0, fieldIndex, name); val = DtoGEP(currFrame, val, 0, fieldIndex, name);
};
const auto dereference = [&val, &dwarfAddrOps](const char *name = "") {
gIR->DBuilder.OpDeref(dwarfAddrOps);
val = DtoAlignedLoad(val, name);
}; };
const auto vardepth = irLocal->nestedDepth; const auto vardepth = irLocal->nestedDepth;
@ -160,7 +172,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
IF_LOG Logger::println("Lower depth"); IF_LOG Logger::println("Lower depth");
offsetToNthField(vardepth); offsetToNthField(vardepth);
IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; IF_LOG Logger::cout() << "Frame index: " << *val << '\n';
dereference((std::string(".frame.") + vdparent->toChars()).c_str()); currFrame = getIrFunc(fd)->frameType;
gIR->DBuilder.OpDeref(dwarfAddrOps);
val = DtoAlignedLoad(currFrame->getPointerTo(), val,
(std::string(".frame.") + vdparent->toChars()).c_str());
IF_LOG Logger::cout() << "Frame: " << *val << '\n'; IF_LOG Logger::cout() << "Frame: " << *val << '\n';
} }
@ -173,7 +188,7 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
// Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass // Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass
// storage of pointer (reference lvalue). // storage of pointer (reference lvalue).
} else if (byref || captureByRef(vd)) { } else if (byref || captureByRef(vd)) {
val = DtoAlignedLoad(val); val = DtoAlignedLoad(irLocal->value->getType(), val);
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable() // ref/out variables get a reference-debuginfo-type in EmitLocalVariable()
// => don't dereference, use reference lvalue as address // => don't dereference, use reference lvalue as address
if (!vd->isReference()) if (!vd->isReference())
@ -211,7 +226,8 @@ void DtoResolveNestedContext(const Loc &loc, AggregateDeclaration *decl,
DtoResolveDsymbol(decl); DtoResolveDsymbol(decl);
unsigned idx = getVthisIdx(decl); unsigned idx = getVthisIdx(decl);
LLValue *gep = DtoGEP(value, 0, idx, ".vthis"); llvm::StructType *st = getIrAggr(decl, true)->getLLStructType();
LLValue *gep = DtoGEP(st, value, 0, idx, ".vthis");
DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep); DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep);
} }
} }
@ -262,13 +278,13 @@ LLValue *DtoNestedContext(const Loc &loc, Dsymbol *sym) {
} else if (irFunc.thisArg) { } else if (irFunc.thisArg) {
// or just have a this argument // or just have a this argument
AggregateDeclaration *ad = irFunc.decl->isMember2(); AggregateDeclaration *ad = irFunc.decl->isMember2();
val = ad->isClassDeclaration() ? DtoLoad(irFunc.thisArg) : irFunc.thisArg; val = loadThisPtr(ad, irFunc);
if (!ad->vthis) { if (!ad->vthis) {
// This is just a plain 'outer' reference of a class nested in a // This is just a plain 'outer' reference of a class nested in a
// function (but without any variables in the nested context). // function (but without any variables in the nested context).
return val; return val;
} }
val = DtoLoad(DtoGEP(val, 0, getVthisIdx(ad), ".vthis")); val = indexVThis(ad, val);
} else { } else {
if (sym->isFuncDeclaration()) { if (sym->isFuncDeclaration()) {
// If we are here, the function actually needs its nested context // If we are here, the function actually needs its nested context
@ -310,10 +326,10 @@ LLValue *DtoNestedContext(const Loc &loc, Dsymbol *sym) {
IF_LOG Logger::println( IF_LOG Logger::println(
"Calling sibling function or directly nested function"); "Calling sibling function or directly nested function");
} else { } else {
val = DtoBitCast(val, llvm::StructType *type = getIrFunc(ctxfd)->frameType;
LLPointerType::getUnqual(getIrFunc(ctxfd)->frameType)); val = DtoBitCast(val, LLPointerType::getUnqual(type));
val = DtoGEP(val, 0, neededDepth); val = DtoGEP(type, val, 0, neededDepth);
val = DtoAlignedLoad( val = DtoAlignedLoad(type->getElementType(neededDepth),
val, (std::string(".frame.") + frameToPass->toChars()).c_str()); val, (std::string(".frame.") + frameToPass->toChars()).c_str());
} }
} }
@ -476,10 +492,9 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
AggregateDeclaration *ad = fd->isMember2(); AggregateDeclaration *ad = fd->isMember2();
assert(ad); assert(ad);
assert(ad->vthis); assert(ad->vthis);
LLValue *thisptr = LLValue *thisptr = loadThisPtr(ad, irFunc);
ad->isClassDeclaration() ? DtoLoad(irFunc.thisArg) : irFunc.thisArg;
IF_LOG Logger::println("Indexing to 'this'"); IF_LOG Logger::println("Indexing to 'this'");
src = DtoLoad(DtoGEP(thisptr, 0, getVthisIdx(ad), ".vthis")); src = indexVThis(ad, thisptr);
} }
if (depth > 1) { if (depth > 1) {
src = DtoBitCast(src, getVoidPtrType()); src = DtoBitCast(src, getVoidPtrType());
@ -490,7 +505,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
// Copy nestArg into framelist; the outer frame is not in the list of // Copy nestArg into framelist; the outer frame is not in the list of
// pointers // pointers
src = DtoBitCast(src, frameType->getContainedType(depth - 1)); src = DtoBitCast(src, frameType->getContainedType(depth - 1));
LLValue *gep = DtoGEP(frame, 0, depth - 1); LLValue *gep = DtoGEP(frameType, frame, 0, depth - 1);
DtoAlignedStore(src, gep); DtoAlignedStore(src, gep);
} }
@ -505,7 +520,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
} }
IrLocal *irLocal = getIrLocal(vd); IrLocal *irLocal = getIrLocal(vd);
LLValue *gep = DtoGEP(frame, 0, irLocal->nestedIndex, vd->toChars()); LLValue *gep = DtoGEP(frameType, frame, 0, irLocal->nestedIndex, vd->toChars());
if (vd->isParameter()) { if (vd->isParameter()) {
IF_LOG Logger::println("nested param: %s", vd->toChars()); IF_LOG Logger::println("nested param: %s", vd->toChars());
LOG_SCOPE LOG_SCOPE

View file

@ -149,7 +149,7 @@ llvm::CodeGenOpt::Level codeGenOptLevel() {
return llvm::CodeGenOpt::Default; return llvm::CodeGenOpt::Default;
} }
static inline void addPass(PassManagerBase &pm, Pass *pass) { static inline void legacyAddPass(PassManagerBase &pm, Pass *pass) {
pm.add(pass); pm.add(pass);
if (verifyEach) { if (verifyEach) {
@ -157,35 +157,35 @@ static inline void addPass(PassManagerBase &pm, Pass *pass) {
} }
} }
static void addStripExternalsPass(const PassManagerBuilder &builder, static void legacyAddStripExternalsPass(const PassManagerBuilder &builder,
PassManagerBase &pm) { PassManagerBase &pm) {
if (builder.OptLevel >= 1) { if (builder.OptLevel >= 1) {
addPass(pm, createStripExternalsPass()); legacyAddPass(pm, createStripExternalsPass());
addPass(pm, createGlobalDCEPass()); legacyAddPass(pm, createGlobalDCEPass());
} }
} }
static void addSimplifyDRuntimeCallsPass(const PassManagerBuilder &builder, static void legacyAddSimplifyDRuntimeCallsPass(const PassManagerBuilder &builder,
PassManagerBase &pm) { PassManagerBase &pm) {
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) { if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
addPass(pm, createSimplifyDRuntimeCalls()); legacyAddPass(pm, createSimplifyDRuntimeCalls());
} }
} }
static void addGarbageCollect2StackPass(const PassManagerBuilder &builder, static void legacyAddGarbageCollect2StackPass(const PassManagerBuilder &builder,
PassManagerBase &pm) { PassManagerBase &pm) {
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) { if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
addPass(pm, createGarbageCollect2Stack()); legacyAddPass(pm, createGarbageCollect2Stack());
} }
} }
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, static void legacyAddAddressSanitizerPasses(const PassManagerBuilder &Builder,
PassManagerBase &PM) { PassManagerBase &PM) {
PM.add(createAddressSanitizerFunctionPass()); PM.add(createAddressSanitizerFunctionPass());
PM.add(createModuleAddressSanitizerLegacyPassPass()); PM.add(createModuleAddressSanitizerLegacyPassPass());
} }
static void addMemorySanitizerPass(const PassManagerBuilder &Builder, static void legacyAddMemorySanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) { PassManagerBase &PM) {
int trackOrigins = fSanitizeMemoryTrackOrigins; int trackOrigins = fSanitizeMemoryTrackOrigins;
bool recover = false; bool recover = false;
@ -206,12 +206,12 @@ static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
} }
} }
static void addThreadSanitizerPass(const PassManagerBuilder &Builder, static void legacyAddThreadSanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) { PassManagerBase &PM) {
PM.add(createThreadSanitizerLegacyPassPass()); PM.add(createThreadSanitizerLegacyPassPass());
} }
static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, static void legacyAddSanitizerCoveragePass(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
#if LDC_LLVM_VER >= 1000 #if LDC_LLVM_VER >= 1000
PM.add(createModuleSanitizerCoverageLegacyPassPass( PM.add(createModuleSanitizerCoverageLegacyPassPass(
@ -223,7 +223,7 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
} }
// Adds PGO instrumentation generation and use passes. // Adds PGO instrumentation generation and use passes.
static void addPGOPasses(PassManagerBuilder &builder, static void legacyAddPGOPasses(PassManagerBuilder &builder,
legacy::PassManagerBase &mpm, unsigned optLevel) { legacy::PassManagerBase &mpm, unsigned optLevel) {
if (opts::isInstrumentingForASTBasedPGO()) { if (opts::isInstrumentingForASTBasedPGO()) {
InstrProfOptions options; InstrProfOptions options;
@ -252,7 +252,7 @@ static void addPGOPasses(PassManagerBuilder &builder,
* The selection mirrors Clang behavior and is based on LLVM's * The selection mirrors Clang behavior and is based on LLVM's
* PassManagerBuilder. * PassManagerBuilder.
*/ */
static void addOptimizationPasses(legacy::PassManagerBase &mpm, static void legacyAddOptimizationPasses(legacy::PassManagerBase &mpm,
legacy::FunctionPassManager &fpm, legacy::FunctionPassManager &fpm,
unsigned optLevel, unsigned sizeLevel) { unsigned optLevel, unsigned sizeLevel) {
if (!noVerify) { if (!noVerify) {
@ -291,49 +291,49 @@ static void addOptimizationPasses(legacy::PassManagerBase &mpm,
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) { if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addAddressSanitizerPasses); legacyAddAddressSanitizerPasses);
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addAddressSanitizerPasses); legacyAddAddressSanitizerPasses);
} }
if (opts::isSanitizerEnabled(opts::MemorySanitizer)) { if (opts::isSanitizerEnabled(opts::MemorySanitizer)) {
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addMemorySanitizerPass); legacyAddMemorySanitizerPass);
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addMemorySanitizerPass); legacyAddMemorySanitizerPass);
} }
if (opts::isSanitizerEnabled(opts::ThreadSanitizer)) { if (opts::isSanitizerEnabled(opts::ThreadSanitizer)) {
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass); legacyAddThreadSanitizerPass);
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addThreadSanitizerPass); legacyAddThreadSanitizerPass);
} }
if (opts::isSanitizerEnabled(opts::CoverageSanitizer)) { if (opts::isSanitizerEnabled(opts::CoverageSanitizer)) {
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addSanitizerCoveragePass); legacyAddSanitizerCoveragePass);
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addSanitizerCoveragePass); legacyAddSanitizerCoveragePass);
} }
if (!disableLangSpecificPasses) { if (!disableLangSpecificPasses) {
if (!disableSimplifyDruntimeCalls) { if (!disableSimplifyDruntimeCalls) {
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd,
addSimplifyDRuntimeCallsPass); legacyAddSimplifyDRuntimeCallsPass);
} }
if (!disableGCToStack) { if (!disableGCToStack) {
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd,
addGarbageCollect2StackPass); legacyAddGarbageCollect2StackPass);
} }
} }
// EP_OptimizerLast does not exist in LLVM 3.0, add it manually below. // EP_OptimizerLast does not exist in LLVM 3.0, add it manually below.
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addStripExternalsPass); legacyAddStripExternalsPass);
addPGOPasses(builder, mpm, optLevel); legacyAddPGOPasses(builder, mpm, optLevel);
builder.populateFunctionPassManager(fpm); builder.populateFunctionPassManager(fpm);
builder.populateModulePassManager(mpm); builder.populateModulePassManager(mpm);
@ -389,7 +389,7 @@ bool ldc_optimize_module(llvm::Module *M) {
mpm.add(createStripSymbolsPass(true)); mpm.add(createStripSymbolsPass(true));
} }
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel()); legacyAddOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
if (global.params.dllimport != DLLImport::none) { if (global.params.dllimport != DLLImport::none) {
mpm.add(createDLLImportRelocationPass()); mpm.add(createDLLImportRelocationPass());

View file

@ -188,18 +188,23 @@ private:
IRBuilder<> b(&ctor->back()); IRBuilder<> b(&ctor->back());
Value *address = currentGlobal; Value *address = currentGlobal;
Type * t = currentGlobal->getValueType();
for (auto i : currentGepPath) { for (auto i : currentGepPath) {
auto t = address->getType()->getPointerElementType();
if (i <= 0xFFFFFFFFu) { if (i <= 0xFFFFFFFFu) {
address = b.CreateConstInBoundsGEP2_32(t, address, 0, address = b.CreateConstInBoundsGEP2_32(t, address, 0,
static_cast<unsigned>(i)); static_cast<unsigned>(i));
} else { } else {
address = b.CreateConstInBoundsGEP2_64(t, address, 0, i); address = b.CreateConstInBoundsGEP2_64(t, address, 0, i);
} }
if (StructType *st = dyn_cast<StructType>(t))
t = st->getElementType(i);
else if (ArrayType *at = dyn_cast<ArrayType>(t))
t = at->getElementType();
else if (PointerType *pt = dyn_cast<PointerType>(t))
llvm_unreachable("Shouldn't be trying to GEP a pointer in initializer");
} }
Constant *value = importedVar; Constant *value = importedVar;
auto t = address->getType()->getPointerElementType();
if (auto gep = isGEP(skipOverCast(originalInitializer))) { if (auto gep = isGEP(skipOverCast(originalInitializer))) {
Constant *newOperand = Constant *newOperand =
createConstPointerCast(importedVar, gep->getOperand(0)->getType()); createConstPointerCast(importedVar, gep->getOperand(0)->getType());

View file

@ -60,7 +60,7 @@ struct Analysis {
CallGraph *CG; CallGraph *CG;
CallGraphNode *CGNode; CallGraphNode *CGNode;
llvm::Type *getTypeFor(Value *typeinfo) const; llvm::Type *getTypeFor(Value *typeinfo, unsigned OperandNo) const;
}; };
} }
@ -157,15 +157,15 @@ static bool isKnownLessThan(Value *Val, uint64_t Limit, const Analysis &A) {
} }
class TypeInfoFI : public FunctionInfo { class TypeInfoFI : public FunctionInfo {
public:
unsigned TypeInfoArgNr; unsigned TypeInfoArgNr;
public:
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr) TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {} : FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
bool analyze(LLCallBasePtr CB, const Analysis &A) override { bool analyze(LLCallBasePtr CB, const Analysis &A) override {
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr); Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
Ty = A.getTypeFor(TypeInfo); Ty = A.getTypeFor(TypeInfo, 0);
if (!Ty) { if (!Ty) {
return false; return false;
} }
@ -190,14 +190,8 @@ public:
} }
arrSize = CB->getArgOperand(ArrSizeArgNr); arrSize = CB->getArgOperand(ArrSizeArgNr);
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
// Extract the element type from the array type. Ty = A.getTypeFor(TypeInfo, 1);
const StructType *ArrTy = dyn_cast<StructType>(Ty);
assert(ArrTy && "Dynamic array type not a struct?");
assert(isa<IntegerType>(ArrTy->getElementType(0)));
const PointerType *PtrTy = cast<PointerType>(ArrTy->getElementType(1));
Ty = PtrTy->getPointerElementType();
// If the user explicitly disabled the limits, don't even check // If the user explicitly disabled the limits, don't even check
// whether the element count fits in 32 bits. This could cause // whether the element count fits in 32 bits. This could cause
// miscompilations for humongous arrays, but as the value "range" // miscompilations for humongous arrays, but as the value "range"
@ -551,7 +545,7 @@ bool GarbageCollect2Stack::run(Function &F, DominatorTree &DT, CallGraphWrapperP
return Changed; return Changed;
} }
llvm::Type *Analysis::getTypeFor(Value *typeinfo) const { llvm::Type *Analysis::getTypeFor(Value *typeinfo, unsigned OperandNo) const {
GlobalVariable *ti_global = GlobalVariable *ti_global =
dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts()); dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts());
if (!ti_global) { if (!ti_global) {
@ -561,11 +555,11 @@ llvm::Type *Analysis::getTypeFor(Value *typeinfo) const {
const auto metaname = getMetadataName(TD_PREFIX, ti_global); const auto metaname = getMetadataName(TD_PREFIX, ti_global);
NamedMDNode *meta = M.getNamedMetadata(metaname); NamedMDNode *meta = M.getNamedMetadata(metaname);
if (!meta || meta->getNumOperands() != 1) { if (!meta || (meta->getNumOperands() != 1 && meta->getNumOperands() != 2) ) {
return nullptr; return nullptr;
} }
MDNode *node = meta->getOperand(0); MDNode *node = meta->getOperand(OperandNo);
return llvm::cast<llvm::ConstantAsMetadata>(node->getOperand(0))->getType(); return llvm::cast<llvm::ConstantAsMetadata>(node->getOperand(0))->getType();
} }

View file

@ -258,7 +258,7 @@ public:
if (returnValue->getType() != funcType->getReturnType() && if (returnValue->getType() != funcType->getReturnType() &&
DtoIsInMemoryOnly(rt) && isaPointer(returnValue)) { DtoIsInMemoryOnly(rt) && isaPointer(returnValue)) {
Logger::println("Loading value for return"); Logger::println("Loading value for return");
returnValue = DtoLoad(returnValue); returnValue = DtoLoad(funcType->getReturnType(), returnValue);
} }
// can happen for classes // can happen for classes
@ -313,8 +313,9 @@ public:
irs->DBuilder.EmitStopPoint(fd->endloc); irs->DBuilder.EmitStopPoint(fd->endloc);
} }
irs->ir->CreateRet(useRetValSlot ? DtoLoad(funcGen.retValSlot) irs->ir->CreateRet(
: returnValue); useRetValSlot ? DtoLoad(funcType->getReturnType(), funcGen.retValSlot)
: returnValue);
} else { } else {
irs->ir->CreateRetVoid(); irs->ir->CreateRetVoid();
} }
@ -1345,7 +1346,7 @@ public:
irs->ir->SetInsertPoint(condbb); irs->ir->SetInsertPoint(condbb);
LLValue *done = nullptr; LLValue *done = nullptr;
LLValue *load = DtoLoad(keyvar); LLValue *load = DtoLoad(keytype, keyvar);
if (stmt->op == TOK::foreach_) { if (stmt->op == TOK::foreach_) {
done = irs->ir->CreateICmpULT(load, niters); done = irs->ir->CreateICmpULT(load, niters);
} else if (stmt->op == TOK::foreach_reverse_) { } else if (stmt->op == TOK::foreach_reverse_) {
@ -1365,8 +1366,8 @@ public:
PGO.emitCounterIncrement(stmt); PGO.emitCounterIncrement(stmt);
// get value for this iteration // get value for this iteration
LLValue *loadedKey = DtoLoad(keyvar); LLValue *loadedKey = DtoLoad(keytype, keyvar);
LLValue *gep = DtoGEP1(val, loadedKey); LLValue *gep = DtoGEP1(DtoMemType(aggrval->type->nextOf()), val, loadedKey);
if (!stmt->value->isRef() && !stmt->value->isOut()) { if (!stmt->value->isRef() && !stmt->value->isOut()) {
// Copy value to local variable, and use it as the value variable. // Copy value to local variable, and use it as the value variable.
@ -1393,7 +1394,7 @@ public:
// next // next
irs->ir->SetInsertPoint(nextbb); irs->ir->SetInsertPoint(nextbb);
if (stmt->op == TOK::foreach_) { if (stmt->op == TOK::foreach_) {
LLValue *load = DtoLoad(keyvar); LLValue *load = DtoLoad(keytype, keyvar);
load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false)); load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false));
DtoStore(load, keyvar); DtoStore(load, keyvar);
} }
@ -1427,8 +1428,8 @@ public:
// handle key // handle key
assert(stmt->key->type->isintegral()); assert(stmt->key->type->isintegral());
LLValue *keyval = DtoRawVarDeclaration(stmt->key); LLValue *keyval = DtoRawVarDeclaration(stmt->key);
LLType *keytype = DtoType(stmt->key->type);
// store initial value in key // store initial value in key
if (stmt->op == TOK::foreach_) { if (stmt->op == TOK::foreach_) {
DtoStore(lower, keyval); DtoStore(lower, keyval);
@ -1449,7 +1450,7 @@ public:
irs->ir->SetInsertPoint(condbb); irs->ir->SetInsertPoint(condbb);
// first we test that lwr < upr // first we test that lwr < upr
lower = DtoLoad(keyval); lower = DtoLoad(keytype, keyval);
assert(lower->getType() == upper->getType()); assert(lower->getType() == upper->getType());
llvm::ICmpInst::Predicate cmpop; llvm::ICmpInst::Predicate cmpop;
if (isLLVMUnsigned(stmt->key->type)) { if (isLLVMUnsigned(stmt->key->type)) {
@ -1475,7 +1476,7 @@ public:
// reverse foreach decrements here // reverse foreach decrements here
if (stmt->op == TOK::foreach_reverse_) { if (stmt->op == TOK::foreach_reverse_) {
LLValue *v = DtoLoad(keyval); LLValue *v = DtoLoad(keytype, keyval);
LLValue *one = LLConstantInt::get(v->getType(), 1, false); LLValue *one = LLConstantInt::get(v->getType(), 1, false);
v = irs->ir->CreateSub(v, one); v = irs->ir->CreateSub(v, one);
DtoStore(v, keyval); DtoStore(v, keyval);
@ -1498,7 +1499,7 @@ public:
// forward foreach increments here // forward foreach increments here
if (stmt->op == TOK::foreach_) { if (stmt->op == TOK::foreach_) {
LLValue *v = DtoLoad(keyval); LLValue *v = DtoLoad(keytype, keyval);
LLValue *one = LLConstantInt::get(v->getType(), 1, false); LLValue *one = LLConstantInt::get(v->getType(), 1, false);
v = irs->ir->CreateAdd(v, one); v = irs->ir->CreateAdd(v, one);
DtoStore(v, keyval); DtoStore(v, keyval);

View file

@ -145,7 +145,7 @@ LLValue *DtoUnpaddedStruct(Type *dty, LLValue *v) {
LLValue *newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty)); LLValue *newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty));
for (unsigned i = 0; i < fields.length; i++) { for (unsigned i = 0; i < fields.length; i++) {
LLValue *fieldptr = DtoIndexAggregate(v, sty->sym, fields[i]); LLValue *fieldptr = DtoLVal(DtoIndexAggregate(v, sty->sym, fields[i]));
LLValue *fieldval; LLValue *fieldval;
if (fields[i]->type->ty == TY::Tstruct) { if (fields[i]->type->ty == TY::Tstruct) {
// Nested structs are the only members that can contain padding // Nested structs are the only members that can contain padding
@ -153,7 +153,7 @@ LLValue *DtoUnpaddedStruct(Type *dty, LLValue *v) {
} else { } else {
assert(!fields[i]->isBitFieldDeclaration()); assert(!fields[i]->isBitFieldDeclaration());
fieldptr = DtoBitCast(fieldptr, DtoPtrToType(fields[i]->type)); fieldptr = DtoBitCast(fieldptr, DtoPtrToType(fields[i]->type));
fieldval = DtoLoad(fieldptr); fieldval = DtoLoad(DtoType(fields[i]->type), fieldptr);
} }
newval = DtoInsertValue(newval, fieldval, i); newval = DtoInsertValue(newval, fieldval, i);
} }
@ -167,7 +167,7 @@ void DtoPaddedStruct(Type *dty, LLValue *v, LLValue *lval) {
VarDeclarations &fields = sty->sym->fields; VarDeclarations &fields = sty->sym->fields;
for (unsigned i = 0; i < fields.length; i++) { for (unsigned i = 0; i < fields.length; i++) {
LLValue *fieldptr = DtoIndexAggregate(lval, sty->sym, fields[i]); LLValue *fieldptr = DtoLVal(DtoIndexAggregate(lval, sty->sym, fields[i]));
LLValue *fieldval = DtoExtractValue(v, i); LLValue *fieldval = DtoExtractValue(v, i);
if (fields[i]->type->ty == TY::Tstruct) { if (fields[i]->type->ty == TY::Tstruct) {
// Nested structs are the only members that can contain padding // Nested structs are the only members that can contain padding

View file

@ -24,6 +24,7 @@
#include "gen/llvmhelpers.h" #include "gen/llvmhelpers.h"
#include "gen/logger.h" #include "gen/logger.h"
#include "gen/nested.h" #include "gen/nested.h"
#include "gen/mangling.h"
#include "gen/pragma.h" #include "gen/pragma.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "gen/runtime.h" #include "gen/runtime.h"
@ -72,41 +73,6 @@ TypeFunction *DtoTypeFunction(DValue *fnval) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
LLValue *DtoCallableValue(DValue *fn) {
Type *type = fn->type->toBasetype();
if (type->ty == TY::Tfunction) {
return DtoRVal(fn);
}
if (type->ty == TY::Tdelegate) {
if (fn->isLVal()) {
LLValue *dg = DtoLVal(fn);
LLValue *funcptr = DtoGEP(dg, 0, 1);
return DtoLoad(funcptr, ".funcptr");
}
LLValue *dg = DtoRVal(fn);
assert(isaStruct(dg));
return gIR->ir->CreateExtractValue(dg, 1, ".funcptr");
}
llvm_unreachable("Not a callable type.");
}
////////////////////////////////////////////////////////////////////////////////
LLFunctionType *DtoExtractFunctionType(LLType *type) {
if (LLFunctionType *fty = isaFunction(type)) {
return fty;
}
if (LLPointerType *pty = isaPointer(type)) {
if (LLFunctionType *fty = isaFunction(pty->getPointerElementType())) {
return fty;
}
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs, static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
IrFuncTy &irFty, LLFunctionType *calleeType, IrFuncTy &irFty, LLFunctionType *calleeType,
Expressions &argexps, Expressions &argexps,
@ -212,7 +178,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
((!isVararg && !isaPointer(paramType)) || ((!isVararg && !isaPointer(paramType)) ||
(isVararg && !irArg->byref && !irArg->isByVal()))) { (isVararg && !irArg->byref && !irArg->isByVal()))) {
Logger::println("Loading struct type for function argument"); Logger::println("Loading struct type for function argument");
llVal = DtoLoad(llVal); llVal = DtoLoad(DtoType(dval->type), llVal);
} }
// parameter type mismatch, this is hard to get rid of // parameter type mismatch, this is hard to get rid of
@ -286,7 +252,7 @@ static LLValue *getTypeinfoArrayArgumentForDVarArg(Expressions *argexps,
gIR->module, tiarrty, true, llvm::GlobalValue::InternalLinkage, tiinits, gIR->module, tiarrty, true, llvm::GlobalValue::InternalLinkage, tiinits,
"._arguments.array"); "._arguments.array");
return DtoLoad(typeinfoarrayparam); return DtoLoad(tiarrty, typeinfoarrayparam);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -304,6 +270,19 @@ static LLType *getPtrToAtomicType(LLType *type) {
} }
} }
static LLType *getAtomicType(LLType *type) {
switch (const size_t N = getTypeBitSize(type)) {
case 8:
case 16:
case 32:
case 64:
case 128:
return llvm::IntegerType::get(gIR->context(), static_cast<unsigned>(N));
default:
return nullptr;
}
}
bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e, bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
DValue *&result) { DValue *&result) {
// va_start instruction // va_start instruction
@ -422,9 +401,10 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
if (pointeeType->isIntegerTy()) { if (pointeeType->isIntegerTy()) {
val = DtoRVal(dval); val = DtoRVal(dval);
} else if (auto intPtrType = getPtrToAtomicType(pointeeType)) { } else if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
LLType *atype = getAtomicType(pointeeType);
ptr = DtoBitCast(ptr, intPtrType); ptr = DtoBitCast(ptr, intPtrType);
auto lval = makeLValue(exp1->loc, dval); auto lval = makeLValue(exp1->loc, dval);
val = DtoLoad(DtoBitCast(lval, intPtrType)); val = DtoLoad(atype, DtoBitCast(lval, intPtrType));
} else { } else {
e->error( e->error(
"atomic store only supports types of size 1/2/4/8/16 bytes, not `%s`", "atomic store only supports types of size 1/2/4/8/16 bytes, not `%s`",
@ -451,12 +431,14 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
int atomicOrdering = (*e->arguments)[1]->toInteger(); int atomicOrdering = (*e->arguments)[1]->toInteger();
LLValue *ptr = DtoRVal(exp); LLValue *ptr = DtoRVal(exp);
LLType *pointeeType = getPointeeType(ptr); LLType *pointeeType = DtoType(e->type);
LLType *loadedType = pointeeType;
Type *retType = exp->type->nextOf(); Type *retType = exp->type->nextOf();
if (!pointeeType->isIntegerTy()) { if (!pointeeType->isIntegerTy()) {
if (auto intPtrType = getPtrToAtomicType(pointeeType)) { if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
ptr = DtoBitCast(ptr, intPtrType); ptr = DtoBitCast(ptr, intPtrType);
loadedType = getAtomicType(pointeeType);
} else { } else {
e->error("atomic load only supports types of size 1/2/4/8/16 bytes, " e->error("atomic load only supports types of size 1/2/4/8/16 bytes, "
"not `%s`", "not `%s`",
@ -465,7 +447,6 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
} }
} }
const auto loadedType = getPointeeType(ptr);
llvm::LoadInst *load = p->ir->CreateLoad(loadedType, ptr); llvm::LoadInst *load = p->ir->CreateLoad(loadedType, ptr);
if (auto alignment = getTypeAllocSize(loadedType)) { if (auto alignment = getTypeAllocSize(loadedType)) {
load->setAlignment(LLAlign(alignment)); load->setAlignment(LLAlign(alignment));
@ -511,11 +492,12 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
cmp = DtoRVal(dcmp); cmp = DtoRVal(dcmp);
val = DtoRVal(dval); val = DtoRVal(dval);
} else if (auto intPtrType = getPtrToAtomicType(pointeeType)) { } else if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
LLType *atype = getAtomicType(pointeeType);
ptr = DtoBitCast(ptr, intPtrType); ptr = DtoBitCast(ptr, intPtrType);
auto cmpLVal = makeLValue(exp2->loc, dcmp); auto cmpLVal = makeLValue(exp2->loc, dcmp);
cmp = DtoLoad(DtoBitCast(cmpLVal, intPtrType)); cmp = DtoLoad(atype, DtoBitCast(cmpLVal, intPtrType));
auto lval = makeLValue(exp3->loc, dval); auto lval = makeLValue(exp3->loc, dval);
val = DtoLoad(DtoBitCast(lval, intPtrType)); val = DtoLoad(atype, DtoBitCast(lval, intPtrType));
} else { } else {
e->error( e->error(
"`cmpxchg` only supports types of size 1/2/4/8/16 bytes, not `%s`", "`cmpxchg` only supports types of size 1/2/4/8/16 bytes, not `%s`",
@ -535,9 +517,10 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
// (avoiding DtoAllocaDump() due to bad optimized codegen, most likely // (avoiding DtoAllocaDump() due to bad optimized codegen, most likely
// because of i1) // because of i1)
auto mem = DtoAlloca(e->type); auto mem = DtoAlloca(e->type);
llvm::Type* memty = DtoType(e->type);
DtoStore(p->ir->CreateExtractValue(ret, 0), DtoStore(p->ir->CreateExtractValue(ret, 0),
DtoBitCast(DtoGEP(mem, 0u, 0), ptr->getType())); DtoBitCast(DtoGEP(memty, mem, 0u, 0), ptr->getType()));
DtoStoreZextI8(p->ir->CreateExtractValue(ret, 1), DtoGEP(mem, 0, 1)); DtoStoreZextI8(p->ir->CreateExtractValue(ret, 1), DtoGEP(memty, mem, 0, 1));
result = new DLValue(e->type, mem); result = new DLValue(e->type, mem);
return true; return true;
@ -600,7 +583,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
assert(bitmask == 31 || bitmask == 63); assert(bitmask == 31 || bitmask == 63);
// auto q = cast(size_t*)ptr + (bitnum >> (64bit ? 6 : 5)); // auto q = cast(size_t*)ptr + (bitnum >> (64bit ? 6 : 5));
LLValue *q = DtoBitCast(ptr, DtoSize_t()->getPointerTo()); LLValue *q = DtoBitCast(ptr, DtoSize_t()->getPointerTo());
q = DtoGEP1(q, p->ir->CreateLShr(bitnum, bitmask == 63 ? 6 : 5), "bitop.q"); q = DtoGEP1(DtoSize_t(), q, p->ir->CreateLShr(bitnum, bitmask == 63 ? 6 : 5), "bitop.q");
// auto mask = 1 << (bitnum & bitmask); // auto mask = 1 << (bitnum & bitmask);
LLValue *mask = LLValue *mask =
@ -609,7 +592,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
// auto result = (*q & mask) ? -1 : 0; // auto result = (*q & mask) ? -1 : 0;
LLValue *val = LLValue *val =
p->ir->CreateZExt(DtoLoad(q, "bitop.tmp"), DtoSize_t(), "bitop.val"); p->ir->CreateZExt(DtoLoad(DtoSize_t(), q, "bitop.tmp"), DtoSize_t(), "bitop.val");
LLValue *ret = p->ir->CreateAnd(val, mask, "bitop.tmp"); LLValue *ret = p->ir->CreateAnd(val, mask, "bitop.tmp");
ret = p->ir->CreateICmpNE(ret, DtoConstSize_t(0), "bitop.tmp"); ret = p->ir->CreateICmpNE(ret, DtoConstSize_t(0), "bitop.tmp");
ret = p->ir->CreateSelect(ret, DtoConstInt(-1), DtoConstInt(0), ret = p->ir->CreateSelect(ret, DtoConstInt(-1), DtoConstInt(0),
@ -649,7 +632,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
Expression *exp1 = (*e->arguments)[0]; Expression *exp1 = (*e->arguments)[0];
LLValue *ptr = DtoRVal(exp1); LLValue *ptr = DtoRVal(exp1);
result = new DImValue(e->type, DtoVolatileLoad(ptr)); result = new DImValue(e->type, DtoVolatileLoad(DtoType(e->type), ptr));
return true; return true;
} }
@ -769,7 +752,7 @@ private:
// class pointer // class pointer
Type *thistype = gIR->func()->decl->vthis->type; Type *thistype = gIR->func()->decl->vthis->type;
if (thistype != iface->type) { if (thistype != iface->type) {
DImValue *dthis = new DImValue(thistype, DtoLoad(thisptrLval)); DImValue *dthis = new DImValue(thistype, DtoLoad(DtoType(thistype),thisptrLval));
thisptrLval = DtoAllocaDump(DtoCastClass(loc, dthis, iface->type)); thisptrLval = DtoAllocaDump(DtoCastClass(loc, dthis, iface->type));
} }
} }
@ -784,7 +767,7 @@ private:
// ... or a delegate context arg // ... or a delegate context arg
LLValue *ctxarg; LLValue *ctxarg;
if (fnval->isLVal()) { if (fnval->isLVal()) {
ctxarg = DtoLoad(DtoGEP(DtoLVal(fnval), 0u, 0), ".ptr"); ctxarg = DtoLoad(getVoidPtrType(), DtoGEP(DtoType(fnval->type), DtoLVal(fnval), 0u, 0), ".ptr");
} else { } else {
ctxarg = gIR->ir->CreateExtractValue(DtoRVal(fnval), 0, ".ptr"); ctxarg = gIR->ir->CreateExtractValue(DtoRVal(fnval), 0, ".ptr");
} }
@ -816,7 +799,8 @@ private:
const auto selector = dfnval->func->objc.selector; const auto selector = dfnval->func->objc.selector;
assert(selector); assert(selector);
LLGlobalVariable *selptr = gIR->objc.getMethVarRef(*selector); LLGlobalVariable *selptr = gIR->objc.getMethVarRef(*selector);
args.push_back(DtoBitCast(DtoLoad(selptr), getVoidPtrType())); args.push_back(DtoBitCast(DtoLoad(selptr->getValueType(), selptr),
getVoidPtrType()));
} }
} }
@ -837,6 +821,26 @@ private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static LLValue *DtoCallableValue(llvm::FunctionType * ft,DValue *fn) {
Type *type = fn->type->toBasetype();
if (type->ty == TY::Tfunction) {
return DtoRVal(fn);
}
if (type->ty == TY::Tdelegate) {
if (fn->isLVal()) {
LLValue *dg = DtoLVal(fn);
llvm::StructType *st = isaStruct(DtoType(fn->type));
LLValue *funcptr = DtoGEP(st, dg, 0, 1);
return DtoLoad(ft->getPointerTo(), funcptr, ".funcptr");
}
LLValue *dg = DtoRVal(fn);
assert(isaStruct(dg));
return gIR->ir->CreateExtractValue(dg, 1, ".funcptr");
}
llvm_unreachable("Not a callable type.");
}
// FIXME: this function is a mess ! // FIXME: this function is a mess !
DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval, DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
Expressions *arguments, LLValue *sretPointer) { Expressions *arguments, LLValue *sretPointer) {
@ -860,10 +864,15 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
} }
// get callee llvm value // get callee llvm value
LLValue *callable = DtoCallableValue(fnval); LLValue *callable = DtoCallableValue(irFty.funcType, fnval);
LLFunctionType *const callableTy = LLFunctionType *callableTy = irFty.funcType;
DtoExtractFunctionType(callable->getType()); if (dfnval && dfnval->func->isCsymbol()) {
assert(callableTy); // See note in DtoDeclareFunction about K&R foward declared (void) functions
// later defined as (...) functions. We want to use the non-variadic one.
if (irFty.funcType->getNumParams() == 0 && irFty.funcType->isVarArg())
callableTy = gIR->module.getFunction(getIRMangledName(dfnval->func, LINK::c))
->getFunctionType();
}
// IF_LOG Logger::cout() << "callable: " << *callable << '\n'; // IF_LOG Logger::cout() << "callable: " << *callable << '\n';

View file

@ -171,7 +171,7 @@ public:
} }
llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e); llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e);
LLConstant *arrptr = DtoGEP(gvar, 0u, 0u); LLConstant *arrptr = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
if (t->ty == TY::Tpointer) { if (t->ty == TY::Tpointer) {
result = DtoBitCast(arrptr, DtoType(t)); result = DtoBitCast(arrptr, DtoType(t));
@ -196,7 +196,7 @@ public:
if (t1b->ty == TY::Tpointer && e->e2->type->isintegral()) { if (t1b->ty == TY::Tpointer && e->e2->type->isintegral()) {
llvm::Constant *ptr = toConstElem(e->e1, p); llvm::Constant *ptr = toConstElem(e->e1, p);
dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger()); dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger());
result = llvm::ConstantExpr::getGetElementPtr(getPointeeType(ptr), ptr, result = llvm::ConstantExpr::getGetElementPtr(DtoType(e->e1->type), ptr,
DtoConstSize_t(idx)); DtoConstSize_t(idx));
return; return;
} }
@ -215,7 +215,7 @@ public:
dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger()); dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger());
llvm::Constant *negIdx = llvm::ConstantExpr::getNeg(DtoConstSize_t(idx)); llvm::Constant *negIdx = llvm::ConstantExpr::getNeg(DtoConstSize_t(idx));
result = llvm::ConstantExpr::getGetElementPtr(getPointeeType(ptr), ptr, result = llvm::ConstantExpr::getGetElementPtr(DtoType(e->e1->type), ptr,
negIdx); negIdx);
return; return;
} }
@ -284,14 +284,15 @@ public:
static_cast<VarExp *>(e->e1)->var->isVarDeclaration(); static_cast<VarExp *>(e->e1)->var->isVarDeclaration();
assert(vd); assert(vd);
DtoResolveVariable(vd); DtoResolveVariable(vd);
IrGlobal *irg = getIrGlobal(vd);
LLConstant *value = LLConstant *value =
isIrGlobalCreated(vd) ? isaConstant(getIrGlobal(vd)->value) : nullptr; isIrGlobalCreated(vd) ? isaConstant(irg->value) : nullptr;
if (!value) { if (!value) {
goto Lerr; goto Lerr;
} }
Type *type = vd->type->toBasetype(); Type *type = vd->type->toBasetype();
if (type->ty == TY::Tarray || type->ty == TY::Tdelegate) { if (type->ty == TY::Tarray || type->ty == TY::Tdelegate) {
value = DtoGEP(value, 0u, 1u); value = DtoGEP(irg->getType(), value, 0u, 1u);
} }
result = DtoBitCast(value, DtoType(tb)); result = DtoBitCast(value, DtoType(tb));
} else if (tb->ty == TY::Tclass && e->e1->type->ty == TY::Tclass && } else if (tb->ty == TY::Tclass && e->e1->type->ty == TY::Tclass &&
@ -309,7 +310,7 @@ public:
assert(i_index != ~0UL); assert(i_index != ~0UL);
// offset pointer // offset pointer
instance = DtoGEP(instance, 0, i_index); instance = DtoGEP(DtoType(e->e1->type), instance, 0, i_index);
} }
result = DtoBitCast(instance, DtoType(tb)); result = DtoBitCast(instance, DtoType(tb));
} else { } else {
@ -350,7 +351,7 @@ public:
if (elemSize && e->offset % elemSize == 0) { if (elemSize && e->offset % elemSize == 0) {
// We can turn this into a "nice" GEP. // We can turn this into a "nice" GEP.
result = llvm::ConstantExpr::getGetElementPtr( result = llvm::ConstantExpr::getGetElementPtr(
getPointeeType(base), base, DtoConstSize_t(e->offset / elemSize)); DtoType(e->var->type), base, DtoConstSize_t(e->offset / elemSize));
} else { } else {
// Offset isn't a multiple of base type size, just cast to i8* and // Offset isn't a multiple of base type size, just cast to i8* and
// apply the byte offset. // apply the byte offset.
@ -400,7 +401,7 @@ public:
LLConstant *val = isaConstant(getIrGlobal(vd)->value); LLConstant *val = isaConstant(getIrGlobal(vd)->value);
val = DtoBitCast(val, DtoType(vd->type->pointerTo())); val = DtoBitCast(val, DtoType(vd->type->pointerTo()));
LLConstant *gep = llvm::ConstantExpr::getGetElementPtr( LLConstant *gep = llvm::ConstantExpr::getGetElementPtr(
getPointeeType(val), val, idxs, true); DtoType(vd->type), val, idxs, true);
// bitcast to requested type // bitcast to requested type
assert(e->type->toBasetype()->ty == TY::Tpointer); assert(e->type->toBasetype()->ty == TY::Tpointer);
@ -527,7 +528,7 @@ public:
// build a constant dynamic array reference with the .ptr field pointing // build a constant dynamic array reference with the .ptr field pointing
// into store // into store
LLConstant *globalstorePtr = DtoGEP(store, 0u, 0u); LLConstant *globalstorePtr = DtoGEP(arrtype, store, 0u, 0u);
result = DtoConstSlice(DtoConstSize_t(e->elements->length), globalstorePtr); result = DtoConstSlice(DtoConstSize_t(e->elements->length), globalstorePtr);
} }
@ -634,13 +635,13 @@ public:
if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) { if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) {
assert(it->isBaseOf(origClass, NULL)); assert(it->isBaseOf(origClass, NULL));
IrTypeClass *itc = getIrType(origClass->type)->isClass();
// find interface impl // find interface impl
size_t i_index = size_t i_index = itc->getInterfaceIndex(it);
getIrType(origClass->type)->isClass()->getInterfaceIndex(it);
assert(i_index != ~0UL); assert(i_index != ~0UL);
// offset pointer // offset pointer
result = DtoGEP(result, 0, i_index); result = DtoGEP(itc->getMemoryLLType(), result, 0, i_index);
} }
} }

View file

@ -65,7 +65,7 @@ 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(mem, start, ".padding"); LLValue *gep = DtoGEP1(LLType::getInt8Ty(gIR->context()), mem, start, ".padding");
DtoMemSetZero(gep, DtoConstSize_t(end - start)); DtoMemSetZero(gep, DtoConstSize_t(end - start));
return mem; return mem;
} }
@ -134,7 +134,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
LOG_SCOPE LOG_SCOPE
// get a pointer to this group's IR field // get a pointer to this group's IR field
const auto ptr = DtoIndexAggregate(mem, sd, vd); const auto ptr = DtoLVal(DtoIndexAggregate(mem, sd, vd));
// merge all initializers to a single value // merge all initializers to a single value
const auto intType = const auto intType =
@ -172,18 +172,16 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
vd->type->toChars(), vd->toChars(), vd->offset); vd->type->toChars(), vd->toChars(), vd->offset);
LOG_SCOPE LOG_SCOPE
// get a pointer to this field const auto field = DtoIndexAggregate(mem, sd, vd);
const auto ptr = DtoIndexAggregate(mem, sd, vd);
DLValue field(vd->type, DtoBitCast(ptr, DtoPtrToType(vd->type)));
// initialize the field // initialize the field
if (expr) { if (expr) {
IF_LOG Logger::println("expr = %s", expr->toChars()); IF_LOG Logger::println("expr = %s", expr->toChars());
// try to construct it in-place // try to construct it in-place
if (!toInPlaceConstruction(&field, expr)) { if (!toInPlaceConstruction(field, expr)) {
DtoAssign(loc, &field, toElem(expr), EXP::blit); DtoAssign(loc, field, toElem(expr), EXP::blit);
if (expr->isLvalue()) if (expr->isLvalue())
callPostblit(loc, expr, DtoLVal(&field)); callPostblit(loc, expr, DtoLVal(field));
} }
} else { } else {
assert(vd == sd->vthis); assert(vd == sd->vthis);
@ -191,7 +189,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
LOG_SCOPE LOG_SCOPE
DImValue val(vd->type, DImValue val(vd->type,
DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type))); DtoBitCast(DtoNestedContext(loc, sd), DtoType(vd->type)));
DtoAssign(loc, &field, &val, EXP::blit); DtoAssign(loc, field, &val, EXP::blit);
} }
// Make sure to zero out padding bytes counted as being part of the type // Make sure to zero out padding bytes counted as being part of the type
@ -419,7 +417,7 @@ public:
Type *dtype = e->type->toBasetype(); Type *dtype = e->type->toBasetype();
llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e); llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e);
LLConstant *arrptr = DtoGEP(gvar, 0u, 0u); LLConstant *arrptr = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
if (dtype->ty == TY::Tarray) { if (dtype->ty == TY::Tarray) {
LLConstant *clen = LLConstant *clen =
@ -850,7 +848,7 @@ public:
uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType); uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType);
if (e->offset % elemSize == 0) { if (e->offset % elemSize == 0) {
// We can turn this into a "nice" GEP. // We can turn this into a "nice" GEP.
offsetValue = DtoGEP1(baseValue, e->offset / elemSize); offsetValue = DtoGEP1(DtoType(base->type), baseValue, e->offset / elemSize);
} }
} }
@ -858,7 +856,8 @@ public:
// Offset isn't a multiple of base type size, just cast to i8* and // Offset isn't a multiple of base type size, just cast to i8* and
// apply the byte offset. // apply the byte offset.
offsetValue = offsetValue =
DtoGEP1(DtoBitCast(baseValue, getVoidPtrType()), e->offset); DtoGEP1(LLType::getInt8Ty(gIR->context()),
DtoBitCast(baseValue, getVoidPtrType()), e->offset);
} }
} }
@ -986,7 +985,7 @@ public:
llvm_unreachable("Unknown DotVarExp type for VarDeclaration."); llvm_unreachable("Unknown DotVarExp type for VarDeclaration.");
} }
LLValue *ptr = DtoIndexAggregate(aggrPtr, ad, vd); auto ptr = DtoLVal(DtoIndexAggregate(aggrPtr, ad, vd));
// special case for bit fields (no real lvalues) // special case for bit fields (no real lvalues)
if (auto bf = vd->isBitFieldDeclaration()) { if (auto bf = vd->isBitFieldDeclaration()) {
@ -1093,17 +1092,19 @@ public:
LLValue *arrptr = nullptr; LLValue *arrptr = nullptr;
if (e1type->ty == TY::Tpointer) { if (e1type->ty == TY::Tpointer) {
arrptr = DtoGEP1(DtoRVal(l), DtoRVal(r)); arrptr = DtoGEP1(DtoMemType(e1type->nextOf()), DtoRVal(l), DtoRVal(r));
} else if (e1type->ty == TY::Tsarray) { } else if (e1type->ty == TY::Tsarray) {
if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) { if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) {
DtoIndexBoundsCheck(e->loc, l, r); DtoIndexBoundsCheck(e->loc, l, r);
} }
arrptr = DtoGEP(DtoLVal(l), DtoConstUint(0), DtoRVal(r)); LLType *elt = DtoMemType(e1type->nextOf());
LLType *arrty = llvm::ArrayType::get(elt, e1type->isTypeSArray()->dim->isIntegerExp()->getInteger());
arrptr = DtoGEP(arrty, DtoLVal(l), DtoConstUint(0), DtoRVal(r));
} else if (e1type->ty == TY::Tarray) { } else if (e1type->ty == TY::Tarray) {
if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) { if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) {
DtoIndexBoundsCheck(e->loc, l, r); DtoIndexBoundsCheck(e->loc, l, r);
} }
arrptr = DtoGEP1(DtoArrayPtr(l), DtoRVal(r)); arrptr = DtoGEP1(DtoMemType(l->type->nextOf()), DtoArrayPtr(l), DtoRVal(r));
} else if (e1type->ty == TY::Taarray) { } else if (e1type->ty == TY::Taarray) {
result = DtoAAIndex(e->loc, e->type, l, r, e->modifiable); result = DtoAAIndex(e->loc, e->type, l, r, e->modifiable);
return; return;
@ -1192,7 +1193,7 @@ public:
} }
// offset by lower // offset by lower
eptr = DtoGEP1(getBasePointer(), vlo, "lowerbound"); eptr = DtoGEP1(DtoMemType(etype->nextOf()), getBasePointer(), vlo, "lowerbound");
// adjust length // adjust length
elen = p->ir->CreateSub(vup, vlo); elen = p->ir->CreateSub(vup, vlo);
@ -1415,7 +1416,7 @@ public:
LLValue *const lval = DtoLVal(dv); LLValue *const lval = DtoLVal(dv);
toElem(e->e2); toElem(e->e2);
LLValue *val = DtoLoad(lval); LLValue *val = DtoLoad(DtoType(dv->type), lval);
LLValue *post = nullptr; LLValue *post = nullptr;
Type *e1type = e->e1->type->toBasetype(); Type *e1type = e->e1->type->toBasetype();
@ -1434,7 +1435,7 @@ public:
assert(e->e2->op == EXP::int64); assert(e->e2->op == EXP::int64);
LLConstant *offset = LLConstant *offset =
e->op == EXP::plusPlus ? DtoConstUint(1) : DtoConstInt(-1); e->op == EXP::plusPlus ? DtoConstUint(1) : DtoConstInt(-1);
post = DtoGEP1(val, offset, "", p->scopebb()); post = DtoGEP1(DtoType(dv->type->nextOf()), val, offset, "", p->scopebb());
} else if (e1type->iscomplex()) { } else if (e1type->iscomplex()) {
assert(e2type->iscomplex()); assert(e2type->iscomplex());
LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0); LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0);
@ -1445,7 +1446,7 @@ public:
} else if (e->op == EXP::minusMinus) { } else if (e->op == EXP::minusMinus) {
re = llvm::BinaryOperator::CreateFSub(re, one, "", p->scopebb()); re = llvm::BinaryOperator::CreateFSub(re, one, "", p->scopebb());
} }
DtoComplexSet(lval, re, im); DtoComplexSet(DtoType(dv->type), lval, re, im);
} else if (e1type->isfloating()) { } else if (e1type->isfloating()) {
assert(e2type->isfloating()); assert(e2type->isfloating());
LLValue *one = DtoConstFP(e1type, ldouble(1.0)); LLValue *one = DtoConstFP(e1type, ldouble(1.0));
@ -1611,7 +1612,7 @@ public:
} else if (auto ve = e->e1->isVarExp()) { } else if (auto ve = e->e1->isVarExp()) {
if (auto vd = ve->var->isVarDeclaration()) { if (auto vd = ve->var->isVarDeclaration()) {
if (vd->onstack()) { if (vd->onstack()) {
DtoFinalizeScopeClass(e->loc, DtoRVal(dval), vd->onstackWithDtor()); DtoFinalizeScopeClass(e->loc, dval, vd->onstackWithDtor());
onstack = true; onstack = true;
} }
} }
@ -1628,8 +1629,8 @@ public:
// dyn array // dyn array
else if (et->ty == TY::Tarray) { else if (et->ty == TY::Tarray) {
DtoDeleteArray(e->loc, dval); DtoDeleteArray(e->loc, dval);
if (dval->isLVal()) { if (DLValue *ldval = dval->isLVal()) {
DtoSetArrayToNull(DtoLVal(dval)); DtoSetArrayToNull(ldval);
} }
} }
// unknown/invalid // unknown/invalid
@ -2266,13 +2267,13 @@ public:
e->loc, arrayType, e->loc, arrayType,
new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false); new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false);
initializeArrayLiteral( initializeArrayLiteral(
p, e, DtoBitCast(dynSlice->getPtr(), getPtrToType(llStoType))); p, e, DtoBitCast(dynSlice->getPtr(), getPtrToType(llStoType)), llStoType);
result = dynSlice; result = dynSlice;
} }
} else { } else {
llvm::Value *storage = llvm::Value *storage =
DtoRawAlloca(llStoType, DtoAlignment(e->type), "arrayliteral"); DtoRawAlloca(llStoType, DtoAlignment(e->type), "arrayliteral");
initializeArrayLiteral(p, e, storage); initializeArrayLiteral(p, e, storage, llStoType);
if (arrayType->ty == TY::Tsarray) { if (arrayType->ty == TY::Tsarray) {
result = new DLValue(e->type, storage); result = new DLValue(e->type, storage);
} else if (arrayType->ty == TY::Tpointer) { } else if (arrayType->ty == TY::Tpointer) {
@ -2453,7 +2454,7 @@ public:
LLConstant *globalstore = new LLGlobalVariable( LLConstant *globalstore = new LLGlobalVariable(
gIR->module, initval->getType(), false, gIR->module, initval->getType(), false,
LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage"); LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
LLConstant *slice = DtoGEP(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 = DtoAggrPaint(slice, funcTy->getParamType(1));
@ -2461,7 +2462,7 @@ public:
globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false, globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false,
LLGlobalValue::InternalLinkage, LLGlobalValue::InternalLinkage,
initval, ".aaValuesStorage"); initval, ".aaValuesStorage");
slice = DtoGEP(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 = DtoAggrPaint(slice, funcTy->getParamType(2));
@ -2469,7 +2470,7 @@ public:
valuesArray, "aa"); valuesArray, "aa");
if (basetype->ty != TY::Taarray) { if (basetype->ty != TY::Taarray) {
LLValue *tmp = DtoAlloca(e->type, "aaliteral"); LLValue *tmp = DtoAlloca(e->type, "aaliteral");
DtoStore(aa, DtoGEP(tmp, 0u, 0)); DtoStore(aa, DtoGEP(DtoType(e->type), tmp, 0u, 0));
result = new DLValue(e->type, tmp); result = new DLValue(e->type, tmp);
} else { } else {
result = new DImValue(e->type, aa); result = new DImValue(e->type, aa);
@ -2508,8 +2509,9 @@ public:
DValue *toGEP(UnaExp *exp, unsigned index) { DValue *toGEP(UnaExp *exp, unsigned index) {
// (&a.foo).funcptr is a case where toElem(e1) is genuinely not an l-value. // (&a.foo).funcptr is a case where toElem(e1) is genuinely not an l-value.
LLValue *val = makeLValue(exp->loc, toElem(exp->e1)); DValue * dv = toElem(exp->e1);
LLValue *v = DtoGEP(val, 0, index); LLValue *val = makeLValue(exp->loc, dv);
LLValue *v = DtoGEP(DtoType(dv->type), val, 0, index);
return new DLValue(exp->type, DtoBitCast(v, DtoPtrToType(exp->type))); return new DLValue(exp->type, DtoBitCast(v, DtoPtrToType(exp->type)));
} }
@ -2565,12 +2567,12 @@ public:
for (auto exp : *e->exps) { for (auto exp : *e->exps) {
types.push_back(DtoMemType(exp->type)); types.push_back(DtoMemType(exp->type));
} }
LLValue *val = llvm::StructType *st = llvm::StructType::get(gIR->context(), types);
DtoRawAlloca(LLStructType::get(gIR->context(), types), 0, ".tuple"); LLValue *val = DtoRawAlloca(st, 0, ".tuple");
for (size_t i = 0; i < e->exps->length; i++) { for (size_t i = 0; i < e->exps->length; i++) {
Expression *el = (*e->exps)[i]; Expression *el = (*e->exps)[i];
DValue *ep = toElem(el); DValue *ep = toElem(el);
LLValue *gep = DtoGEP(val, 0, i); LLValue *gep = DtoGEP(st, val, 0, i);
if (DtoIsInMemoryOnly(el->type)) { if (DtoIsInMemoryOnly(el->type)) {
DtoMemCpy(gep, DtoLVal(ep)); DtoMemCpy(gep, DtoLVal(ep));
} else if (el->type->ty != TY::Tvoid) { } else if (el->type->ty != TY::Tvoid) {
@ -2599,6 +2601,7 @@ public:
return DtoRVal(DtoCast(e->loc, element, elementType)); return DtoRVal(DtoCast(e->loc, element, elementType));
}; };
LLType *dstType = DtoType(e->type);
Type *tsrc = e->e1->type->toBasetype(); Type *tsrc = e->e1->type->toBasetype();
if (auto lit = e->e1->isArrayLiteralExp()) { if (auto lit = e->e1->isArrayLiteralExp()) {
// Optimization for array literals: check for a fully static literal and // Optimization for array literals: check for a fully static literal and
@ -2626,7 +2629,7 @@ public:
DtoStore(vectorConstant, dstMem); DtoStore(vectorConstant, dstMem);
} else { } else {
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
DtoStore(llElements[i], DtoGEP(dstMem, 0, i)); DtoStore(llElements[i], DtoGEP(dstType, dstMem, 0, i));
} }
} }
} else if (tsrc->ty == TY::Tarray || tsrc->ty == TY::Tsarray) { } else if (tsrc->ty == TY::Tarray || tsrc->ty == TY::Tsarray) {
@ -2643,16 +2646,18 @@ public:
Logger::println("dynamic array expression, assume matching length"); Logger::println("dynamic array expression, assume matching length");
} }
LLValue *arrayPtr = DtoArrayPtr(toElem(e->e1)); DValue *e1 = toElem(e->e1);
LLValue *arrayPtr = DtoArrayPtr(e1);
Type *srcElementType = tsrc->nextOf(); Type *srcElementType = tsrc->nextOf();
if (DtoMemType(elementType) == DtoMemType(srcElementType)) { if (DtoMemType(elementType) == DtoMemType(srcElementType)) {
DtoMemCpy(dstMem, arrayPtr); DtoMemCpy(dstMem, arrayPtr);
} else { } else {
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
DLValue srcElement(srcElementType, DtoGEP1(arrayPtr, i)); LLValue *gep = DtoGEP1(DtoMemType(e1->type->nextOf()), arrayPtr, i);
DLValue srcElement(srcElementType, gep);
LLValue *llVal = getCastElement(&srcElement); LLValue *llVal = getCastElement(&srcElement);
DtoStore(llVal, DtoGEP(dstMem, 0, i)); DtoStore(llVal, DtoGEP(dstType, dstMem, 0, i));
} }
} }
} else { } else {
@ -2673,7 +2678,7 @@ public:
DtoStore(vectorConstant, dstMem); DtoStore(vectorConstant, dstMem);
} else { } else {
for (unsigned int i = 0; i < N; ++i) { for (unsigned int i = 0; i < N; ++i) {
DtoStore(llElement, DtoGEP(dstMem, 0, i)); DtoStore(llElement, DtoGEP(dstType, dstMem, 0, i));
} }
} }
} }
@ -2719,22 +2724,25 @@ public:
Type *t = ex->type->toBasetype(); Type *t = ex->type->toBasetype();
assert(t->ty == TY::Tclass); assert(t->ty == TY::Tclass);
ClassDeclaration *sym = static_cast<TypeClass *>(t)->sym;
IrClass *irc = getIrAggr(sym, true);
LLValue *val = DtoRVal(ex); LLValue *val = DtoRVal(ex);
// Get and load vtbl pointer. // Get and load vtbl pointer.
llvm::Value *vtbl = DtoLoad(DtoGEP(val, 0u, 0)); llvm::GlobalVariable* vtblsym = irc->getVtblSymbol();
llvm::Value *vtbl = DtoLoad(vtblsym->getType(), DtoGEP(irc->getLLStructType(), val, 0u, 0));
// TypeInfo ptr is first vtbl entry. // TypeInfo ptr is first vtbl entry.
llvm::Value *typinf = DtoGEP(vtbl, 0u, 0); llvm::Value *typinf = DtoGEP(vtblsym->getValueType(), vtbl, 0u, 0);
Type *resultType; Type *resultType;
if (static_cast<TypeClass *>(t)->sym->isInterfaceDeclaration()) { if (sym->isInterfaceDeclaration()) {
// For interfaces, the first entry in the vtbl is actually a pointer // For interfaces, the first entry in the vtbl is actually a pointer
// to an Interface instance, which has the type info as its first // to an Interface instance, which has the type info as its first
// member, so we have to add an extra layer of indirection. // member, so we have to add an extra layer of indirection.
resultType = getInterfaceTypeInfoType(); resultType = getInterfaceTypeInfoType();
typinf = DtoLoad( LLType *pres = DtoType(resultType->pointerTo());
DtoBitCast(typinf, DtoType(resultType->pointerTo()->pointerTo()))); typinf = DtoLoad(pres, DtoBitCast(typinf, pres->getPointerTo()));
} else { } else {
resultType = getClassInfoType(); resultType = getClassInfoType();
typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo())); typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo()));
@ -2867,7 +2875,7 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
else if (auto al = rhs->isArrayLiteralExp()) { else if (auto al = rhs->isArrayLiteralExp()) {
if (lhs->type->toBasetype()->ty == TY::Tsarray) { if (lhs->type->toBasetype()->ty == TY::Tsarray) {
Logger::println("success, in-place-constructing array literal"); Logger::println("success, in-place-constructing array literal");
initializeArrayLiteral(gIR, al, DtoLVal(lhs)); initializeArrayLiteral(gIR, al, DtoLVal(lhs), DtoMemType(lhs->type));
return true; return true;
} }
} }

View file

@ -345,47 +345,42 @@ LLIntegerType *DtoSize_t() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
LLType *getPointeeType(LLValue *pointer) {
return pointer->getType()->getPointerElementType();
}
////////////////////////////////////////////////////////////////////////////////
namespace { namespace {
llvm::GetElementPtrInst *DtoGEP(LLValue *ptr, llvm::ArrayRef<LLValue *> indices, llvm::GetElementPtrInst *DtoGEP(LLType * type,LLValue *ptr,
llvm::ArrayRef<LLValue *> indices,
const char *name, llvm::BasicBlock *bb) { const char *name, llvm::BasicBlock *bb) {
auto gep = llvm::GetElementPtrInst::Create(getPointeeType(ptr), ptr, indices, auto gep = llvm::GetElementPtrInst::Create(type, ptr, indices,
name, bb ? bb : gIR->scopebb()); name, bb ? bb : gIR->scopebb());
gep->setIsInBounds(true); gep->setIsInBounds(true);
return gep; return gep;
} }
} }
LLValue *DtoGEP1(LLValue *ptr, LLValue *i0, const char *name, LLValue *DtoGEP1(LLType * ptrty, LLValue *ptr, LLValue *i0, const char *name,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
return DtoGEP(ptr, i0, name, bb); return DtoGEP(ptrty, ptr, i0, name, bb);
} }
LLValue *DtoGEP(LLValue *ptr, LLValue *i0, LLValue *i1, const char *name, LLValue *DtoGEP(LLType * ptrty, LLValue *ptr, LLValue *i0, LLValue *i1, const char *name,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
LLValue *indices[] = {i0, i1}; LLValue *indices[] = {i0, i1};
return DtoGEP(ptr, indices, name, bb); return DtoGEP(ptrty, ptr, indices, name, bb);
} }
LLValue *DtoGEP1(LLValue *ptr, unsigned i0, const char *name, LLValue *DtoGEP1(LLType * ptrty, LLValue *ptr, unsigned i0, const char *name,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
return DtoGEP(ptr, DtoConstUint(i0), name, bb); return DtoGEP(ptrty, ptr, DtoConstUint(i0), name, bb);
} }
LLValue *DtoGEP(LLValue *ptr, unsigned i0, unsigned i1, const char *name, LLValue *DtoGEP(LLType * ptrty, LLValue *ptr, unsigned i0, unsigned i1, const char *name,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)};
return DtoGEP(ptr, indices, name, bb); return DtoGEP(ptrty, ptr, indices, name, bb);
} }
LLConstant *DtoGEP(LLConstant *ptr, unsigned i0, unsigned i1) { LLConstant *DtoGEP(LLType * ptrty, LLConstant *ptr, unsigned i0, unsigned i1) {
LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)};
return llvm::ConstantExpr::getGetElementPtr(getPointeeType(ptr), ptr, indices, return llvm::ConstantExpr::getGetElementPtr(ptrty, ptr, indices,
/* InBounds = */ true); /* InBounds = */ true);
} }
@ -491,7 +486,7 @@ LLConstant *DtoConstFP(Type *t, const real_t value) {
LLConstant *DtoConstCString(const char *str) { LLConstant *DtoConstCString(const char *str) {
llvm::StringRef s(str ? str : ""); llvm::StringRef s(str ? str : "");
LLGlobalVariable *gvar = gIR->getCachedStringLiteral(s); LLGlobalVariable *gvar = gIR->getCachedStringLiteral(s);
return DtoGEP(gvar, 0u, 0u); return DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
} }
LLConstant *DtoConstString(const char *str) { LLConstant *DtoConstString(const char *str) {
@ -503,27 +498,31 @@ LLConstant *DtoConstString(const char *str) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
namespace { namespace {
llvm::LoadInst *DtoLoadImpl(LLValue *src, const char *name) { llvm::LoadInst *DtoLoadImpl(LLType *type, LLValue *src, const char *name) {
return gIR->ir->CreateLoad(getPointeeType(src), src, name); return gIR->ir->CreateLoad(type, src, name);
} }
} }
LLValue *DtoLoad(LLValue *src, const char *name) { LLValue *DtoLoad(LLType* type, LLValue *src, const char *name) {
return DtoLoadImpl(src, name); return DtoLoadImpl(type, src, name);
}
LLValue *DtoLoad(DLValue *src, const char *name) {
return DtoLoadImpl(DtoType(src->type), DtoLVal(src), name);
} }
// Like DtoLoad, but the pointer is guaranteed to be aligned appropriately for // Like DtoLoad, but the pointer is guaranteed to be aligned appropriately for
// the type. // the type.
LLValue *DtoAlignedLoad(LLValue *src, const char *name) { LLValue *DtoAlignedLoad(LLType *type, LLValue *src, const char *name) {
llvm::LoadInst *ld = DtoLoadImpl(src, name); llvm::LoadInst *ld = DtoLoadImpl(type, src, name);
if (auto alignment = getABITypeAlign(ld->getType())) { if (auto alignment = getABITypeAlign(ld->getType())) {
ld->setAlignment(LLAlign(alignment)); ld->setAlignment(LLAlign(alignment));
} }
return ld; return ld;
} }
LLValue *DtoVolatileLoad(LLValue *src, const char *name) { LLValue *DtoVolatileLoad(LLType *type, LLValue *src, const char *name) {
llvm::LoadInst *ld = DtoLoadImpl(src, name); llvm::LoadInst *ld = DtoLoadImpl(type, src, name);
ld->setVolatile(true); ld->setVolatile(true);
return ld; return ld;
} }
@ -568,15 +567,36 @@ LLType *stripAddrSpaces(LLType *t)
if(gIR->dcomputetarget == nullptr) if(gIR->dcomputetarget == nullptr)
return t; return t;
llvm::PointerType *pt = isaPointer(t);
if (!pt)
return t;
#if LDC_LLVM_VER >= 1600
return getVoidPtrType();
#elif LDC_LLVM_VER >= 1400
if (pt->isOpaque())
return getVoidPtrType();
else {
int indirections = 0;
while (t->isPointerTy()) {
indirections++;
t = t->getPointerElementType();
}
while (indirections-- != 0)
t = t->getPointerTo(0);
}
return t;
#else
int indirections = 0; int indirections = 0;
while (t->isPointerTy()) { while (t->isPointerTy()) {
indirections++; indirections++;
t = t->getPointerElementType(); t = t->getPointerElementType();
} }
while (indirections-- != 0) while (indirections-- != 0)
t = t->getPointerTo(0); t = t->getPointerTo(0);
return t; return t;
#endif
} }
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name) { LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name) {

View file

@ -82,20 +82,17 @@ void setVisibility(Dsymbol *sym, llvm::GlobalObject *obj);
LLIntegerType *DtoSize_t(); LLIntegerType *DtoSize_t();
LLStructType *DtoModuleReferenceType(); LLStructType *DtoModuleReferenceType();
// Returns the pointee type of the specified pointer value.
LLType *getPointeeType(LLValue *pointer);
// getelementptr helpers // getelementptr helpers
LLValue *DtoGEP1(LLValue *ptr, LLValue *i0, const char *name = "", LLValue *DtoGEP1(LLType * ptrty,LLValue *ptr, LLValue *i0, const char *name = "",
llvm::BasicBlock *bb = nullptr); llvm::BasicBlock *bb = nullptr);
LLValue *DtoGEP(LLValue *ptr, LLValue *i0, LLValue *i1, const char *name = "", LLValue *DtoGEP(LLType * ptrty,LLValue *ptr, LLValue *i0, LLValue *i1, const char *name = "",
llvm::BasicBlock *bb = nullptr); llvm::BasicBlock *bb = nullptr);
LLValue *DtoGEP1(LLValue *ptr, unsigned i0, const char *name = "", LLValue *DtoGEP1(LLType * ptrty, LLValue *ptr, unsigned i0, const char *name = "",
llvm::BasicBlock *bb = nullptr); llvm::BasicBlock *bb = nullptr);
LLValue *DtoGEP(LLValue *ptr, unsigned i0, unsigned i1, const char *name = "", LLValue *DtoGEP(LLType * ptrty, LLValue *ptr, unsigned i0, unsigned i1, const char *name = "",
llvm::BasicBlock *bb = nullptr); llvm::BasicBlock *bb = nullptr);
LLConstant *DtoGEP(LLConstant *ptr, unsigned i0, unsigned i1); LLConstant *DtoGEP(LLType * ptrty, LLConstant *ptr, unsigned i0, unsigned i1);
// to constant helpers // to constant helpers
LLConstantInt *DtoConstSize_t(uint64_t); LLConstantInt *DtoConstSize_t(uint64_t);
@ -109,9 +106,11 @@ LLConstant *DtoConstString(const char *);
LLConstant *DtoConstBool(bool); LLConstant *DtoConstBool(bool);
// llvm wrappers // llvm wrappers
LLValue *DtoLoad(LLValue *src, const char *name = ""); class DLValue;
LLValue *DtoVolatileLoad(LLValue *src, const char *name = ""); LLValue *DtoLoad(DLValue *src, const char *name = "");
LLValue *DtoAlignedLoad(LLValue *src, const char *name = ""); LLValue *DtoLoad(LLType *, LLValue *src, const char *name = "");
LLValue *DtoVolatileLoad(LLType *, LLValue *src, const char *name = "");
LLValue *DtoAlignedLoad(LLType *type, LLValue *src, const char *name = "");
void DtoStore(LLValue *src, LLValue *dst); void DtoStore(LLValue *src, LLValue *dst);
void DtoVolatileStore(LLValue *src, LLValue *dst); void DtoVolatileStore(LLValue *src, LLValue *dst);
void DtoStoreZextI8(LLValue *src, LLValue *dst); void DtoStoreZextI8(LLValue *src, LLValue *dst);

View file

@ -83,7 +83,7 @@ void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
const auto enterCatchFn = getRuntimeFunction( const auto enterCatchFn = getRuntimeFunction(
c->loc, irs.module, c->loc, irs.module,
isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch"); isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch");
const auto ptr = DtoLoad(ehPtrSlot); const auto ptr = DtoLoad(getVoidPtrType(), ehPtrSlot);
const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr); const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr);
// For catches that use the Throwable object, create storage for it. // For catches that use the Throwable object, create storage for it.
@ -255,7 +255,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
if (cpyObj) { if (cpyObj) {
// assign the caught exception to the location in the closure // assign the caught exception to the location in the closure
auto val = irs.ir->CreateLoad(getPointeeType(exnObj), exnObj); auto val = irs.ir->CreateLoad(DtoType(var->type), exnObj);
irs.ir->CreateStore(val, cpyObj); irs.ir->CreateStore(val, cpyObj);
exnObj = cpyObj; exnObj = cpyObj;
} }
@ -778,7 +778,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
irs.ir->SetInsertPoint(resumeUnwindBlock); irs.ir->SetInsertPoint(resumeUnwindBlock);
llvm::Function *resumeFn = getUnwindResumeFunction(Loc(), irs.module); llvm::Function *resumeFn = getUnwindResumeFunction(Loc(), irs.module);
irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot())); irs.ir->CreateCall(resumeFn, DtoLoad(getVoidPtrType(), getOrCreateEhPtrSlot()));
irs.ir->CreateUnreachable(); irs.ir->CreateUnreachable();
irs.ir->SetInsertPoint(oldBB); irs.ir->SetInsertPoint(oldBB);

View file

@ -93,6 +93,11 @@ void emitTypeInfoMetadata(LLGlobalVariable *typeinfoGlobal, Type *forType) {
auto val = llvm::UndefValue::get(DtoType(forType)); auto val = llvm::UndefValue::get(DtoType(forType));
meta->addOperand(llvm::MDNode::get(gIR->context(), meta->addOperand(llvm::MDNode::get(gIR->context(),
llvm::ConstantAsMetadata::get(val))); llvm::ConstantAsMetadata::get(val)));
if (TypeArray *ta = t->isTypeDArray()) {
auto val2 = llvm::UndefValue::get(DtoMemType(ta->nextOf()));
meta->addOperand(llvm::MDNode::get(gIR->context(),
llvm::ConstantAsMetadata::get(val2)));
}
} }
} }
} }
@ -435,7 +440,9 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
assert(isBuiltin && "existing global expected to be the init symbol of a " assert(isBuiltin && "existing global expected to be the init symbol of a "
"built-in TypeInfo"); "built-in TypeInfo");
} else { } else {
LLType *type = DtoType(decl->type)->getPointerElementType(); DtoType(decl->type);
TypeClass *tclass = decl->type->isTypeClass();
LLType *type = getIrType(tclass)->isClass()->getMemoryLLType();
// We need to keep the symbol mutable as the type is not declared as // We need to keep the symbol mutable as the type is not declared as
// immutable on the D side, and e.g. synchronized() can be used on the // immutable on the D side, and e.g. synchronized() can be used on the
// implicit monitor. // implicit monitor.

View file

@ -61,6 +61,9 @@ public:
llvm::Constant *getInitSymbol(bool define = false); llvm::Constant *getInitSymbol(bool define = false);
/// Builds the __initZ initializer constant lazily. /// Builds the __initZ initializer constant lazily.
llvm::Constant *getDefaultInit(); llvm::Constant *getDefaultInit();
/// Return the LLVM type of this Aggregate (w/o the reference for classes)
llvm::StructType *getLLStructType();
/// Whether to suppress the TypeInfo definition for the aggregate via /// Whether to suppress the TypeInfo definition for the aggregate via
/// `-betterC`, no `object.TypeInfo`, or `pragma(LDC_no_typeinfo)`. /// `-betterC`, no `object.TypeInfo`, or `pragma(LDC_no_typeinfo)`.
@ -99,8 +102,6 @@ protected:
private: private:
llvm::StructType *llStructType = nullptr; llvm::StructType *llStructType = nullptr;
llvm::StructType *getLLStructType();
/// Recursively adds all the initializers for the given aggregate and, in /// Recursively adds all the initializers for the given aggregate and, in
/// case of a class type, all its base classes. /// case of a class type, all its base classes.
void addFieldInitializers(llvm::SmallVectorImpl<llvm::Constant *> &constants, void addFieldInitializers(llvm::SmallVectorImpl<llvm::Constant *> &constants,

View file

@ -110,8 +110,7 @@ LLGlobalVariable *IrClass::getClassInfoSymbol(bool define) {
emitTypeInfoMetadata(typeInfo, aggrdecl->type); emitTypeInfoMetadata(typeInfo, aggrdecl->type);
// Gather information // Gather information
LLType *type = DtoType(aggrdecl->type); LLType *bodyType = getLLStructType();
LLType *bodyType = type->getPointerElementType();
bool hasDestructor = (aggrdecl->dtor != nullptr); bool hasDestructor = (aggrdecl->dtor != nullptr);
// Construct the fields // Construct the fields
llvm::Metadata *mdVals[CD_NumFields]; llvm::Metadata *mdVals[CD_NumFields];
@ -512,7 +511,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol(); llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol();
llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr( llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr(
getPointeeType(interfaceInfosZ), interfaceInfosZ, idxs, true); interfaceInfosZ->getValueType(), interfaceInfosZ, idxs, true);
constants.push_back(DtoBitCast(c, voidPtrTy)); constants.push_back(DtoBitCast(c, voidPtrTy));
} else { } else {
@ -626,7 +625,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
LLValue *&thisArg = args[thisArgIndex]; LLValue *&thisArg = args[thisArgIndex];
LLType *targetThisType = thisArg->getType(); LLType *targetThisType = thisArg->getType();
thisArg = DtoBitCast(thisArg, getVoidPtrType()); thisArg = DtoBitCast(thisArg, getVoidPtrType());
thisArg = DtoGEP1(thisArg, DtoConstInt(-thunkOffset)); thisArg = DtoGEP1(LLType::getInt8Ty(gIR->context()), thisArg, DtoConstInt(-thunkOffset));
thisArg = DtoBitCast(thisArg, targetThisType); thisArg = DtoBitCast(thisArg, targetThisType);
// all calls that might be subject to inlining into a caller with debug // all calls that might be subject to inlining into a caller with debug
@ -762,7 +761,7 @@ LLConstant *IrClass::getClassInfoInterfaces() {
LLConstant *idxs[2] = {DtoConstSize_t(0), LLConstant *idxs[2] = {DtoConstSize_t(0),
DtoConstSize_t(n - cd->vtblInterfaces->length)}; DtoConstSize_t(n - cd->vtblInterfaces->length)};
LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr(getPointeeType(ciarr), LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr(ciarr->getValueType(),
ciarr, idxs, true); ciarr, idxs, true);
// return as a slice // return as a slice

View file

@ -273,18 +273,17 @@ IrTypeAggr::IrTypeAggr(AggregateDeclaration *ad)
LLStructType::create(gIR->context(), ad->toPrettyChars())), LLStructType::create(gIR->context(), ad->toPrettyChars())),
aggr(ad) {} aggr(ad) {}
void IrTypeAggr::getMemberLocation(VarDeclaration *var, unsigned &fieldIndex, unsigned IrTypeAggr::getMemberLocation(VarDeclaration *var, bool& isFieldIdx) const {
unsigned &byteOffset) const {
// Note: The interface is a bit more general than what we actually return. // Note: The interface is a bit more general than what we actually return.
// Specifically, the frontend offset information we use for overlapping // Specifically, the frontend offset information we use for overlapping
// fields is always based at the object start. // fields is always based at the object start.
auto it = varGEPIndices.find(var); auto it = varGEPIndices.find(var);
if (it != varGEPIndices.end()) { if (it != varGEPIndices.end()) {
fieldIndex = it->second; isFieldIdx = true;
byteOffset = 0; return it->second;
} else { } else {
fieldIndex = 0; isFieldIdx = false;
byteOffset = var->offset; return var->offset;
} }
} }

View file

@ -72,8 +72,7 @@ public:
/// Returns the index of the field in the LLVM struct type that corresponds /// Returns the index of the field in the LLVM struct type that corresponds
/// to the given member variable, plus the offset to the actual field start /// to the given member variable, plus the offset to the actual field start
/// due to overlapping (union) fields, if any. /// due to overlapping (union) fields, if any.
void getMemberLocation(VarDeclaration *var, unsigned &fieldIndex, unsigned getMemberLocation(VarDeclaration *var, bool& isFieldIdx) const;
unsigned &byteOffset) const;
protected: protected:
/// ///

View file

@ -189,53 +189,52 @@ void generateBind(const Context &context, DynamicCompilerContext &jitContext,
assert(bindPtr != nullptr); assert(bindPtr != nullptr);
assert(bindFuncs.end() == bindFuncs.find(bindPtr)); assert(bindFuncs.end() == bindFuncs.find(bindPtr));
auto funcToInline = getIrFunc(originalFunc); auto funcToInline = getIrFunc(originalFunc);
if (funcToInline != nullptr) { if (funcToInline == nullptr) {
auto exampleIrFunc = getIrFunc(exampleFunc); fatal(context, "Bind: function body not available");
assert(exampleIrFunc != nullptr);
auto errhandler = [&](const std::string &str) { fatal(context, str); };
auto overrideHandler = [&](llvm::Type &type, const void *data,
size_t size) -> llvm::Constant * {
if (type.isPointerTy()) {
auto getBindFunc = [&]() {
auto handle = *static_cast<void *const *>(data);
return handle != nullptr && jitContext.hasBindFunction(handle)
? handle
: nullptr;
};
auto elemType = type.getPointerElementType();
if (elemType->isFunctionTy()) {
(void)size;
assert(size == sizeof(void *));
auto val = *reinterpret_cast<void *const *>(data);
if (val != nullptr) {
auto ret = getIrFunc(val);
if (ret != nullptr && ret->getType() != &type) {
return llvm::ConstantExpr::getBitCast(ret, &type);
}
return ret;
}
} else if (auto handle = getBindFunc()) {
auto it = bindFuncs.find(handle);
assert(bindFuncs.end() != it);
auto bindIrFunc = it->second;
auto funcPtrType = bindIrFunc->getType();
auto globalVar1 = new llvm::GlobalVariable(
module, funcPtrType, true, llvm::GlobalValue::PrivateLinkage,
bindIrFunc, ".jit_bind_handle");
return llvm::ConstantExpr::getBitCast(globalVar1, &type);
}
}
return nullptr;
};
auto func =
bindParamsToFunc(module, *funcToInline, *exampleIrFunc, params,
errhandler, BindOverride(overrideHandler));
moduleInfo.addBindHandle(func->getName(), bindPtr);
bindFuncs.insert({bindPtr, func});
} else {
fatal(context, "Bind: function body not available");
} }
auto exampleIrFunc = getIrFunc(exampleFunc);
assert(exampleIrFunc != nullptr);
auto errhandler = [&](const std::string &str) { fatal(context, str); };
auto overrideHandler = [&](llvm::Type &type, const void *data,
size_t size) -> llvm::Constant * {
if (type.isPointerTy()) {
auto getBindFunc = [&]() {
auto handle = *static_cast<void *const *>(data);
return handle != nullptr && jitContext.hasBindFunction(handle)
? handle
: nullptr;
};
auto elemType = type.getPointerElementType();
if (elemType->isFunctionTy()) {
(void)size;
assert(size == sizeof(void *));
auto val = *reinterpret_cast<void *const *>(data);
if (val != nullptr) {
auto ret = getIrFunc(val);
if (ret != nullptr && ret->getType() != &type) {
return llvm::ConstantExpr::getBitCast(ret, &type);
}
return ret;
}
} else if (auto handle = getBindFunc()) {
auto it = bindFuncs.find(handle);
assert(bindFuncs.end() != it);
auto bindIrFunc = it->second;
auto funcPtrType = bindIrFunc->getType();
auto globalVar1 = new llvm::GlobalVariable(
module, funcPtrType, true, llvm::GlobalValue::PrivateLinkage,
bindIrFunc, ".jit_bind_handle");
return llvm::ConstantExpr::getBitCast(globalVar1, &type);
}
}
return nullptr;
};
auto func =
bindParamsToFunc(module, *funcToInline, *exampleIrFunc, params,
errhandler, BindOverride(overrideHandler));
moduleInfo.addBindHandle(func->getName(), bindPtr);
bindFuncs.insert({bindPtr, func});
}; };
for (auto &&bind : jitContext.getBindInstances()) { for (auto &&bind : jitContext.getBindInstances()) {
auto bindPtr = bind.first; auto bindPtr = bind.first;