mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 15:40:55 +03:00
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:
commit
78fdc135e4
44 changed files with 666 additions and 543 deletions
|
@ -36,6 +36,7 @@ find_package(LLVM 9.0 REQUIRED
|
|||
selectiondag support tablegen target transformutils vectorize
|
||||
windowsmanifest ${EXTRA_LLVM_MODULES})
|
||||
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
|
||||
string(REGEX MATCH "[^;]*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
|
||||
string(REGEX REPLACE "[^;]*LLVMTableGen[^;]*;?" "" LLVM_LIBRARIES "${LLVM_LIBRARIES}")
|
||||
|
|
|
@ -135,11 +135,11 @@ struct BaseBitcastABIRewrite : ABIRewrite {
|
|||
if (!dv->isLVal()) {
|
||||
LLValue *dump = DtoAllocaDump(dv, asType, alignment,
|
||||
".BaseBitcastABIRewrite_arg_storage");
|
||||
return DtoLoad(dump, name);
|
||||
return DtoLoad(asType, dump, name);
|
||||
}
|
||||
|
||||
LLValue *address = DtoLVal(dv);
|
||||
LLType *pointeeType = address->getType()->getPointerElementType();
|
||||
LLType *pointeeType = DtoType(dv->type);
|
||||
|
||||
if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType) ||
|
||||
alignment > DtoAlignment(dv->type)) {
|
||||
|
@ -148,11 +148,11 @@ struct BaseBitcastABIRewrite : ABIRewrite {
|
|||
asType, alignment, ".BaseBitcastABIRewrite_padded_arg_storage");
|
||||
DtoMemCpy(paddedDump, address,
|
||||
DtoConstSize_t(getTypeAllocSize(pointeeType)));
|
||||
return DtoLoad(paddedDump, name);
|
||||
return DtoLoad(asType, paddedDump, name);
|
||||
}
|
||||
|
||||
address = DtoBitCast(address, getPtrToType(asType));
|
||||
return DtoLoad(address, name);
|
||||
return DtoLoad(asType, address, name);
|
||||
}
|
||||
|
||||
LLValue *getLVal(Type *dty, LLValue *v) override {
|
||||
|
|
|
@ -267,7 +267,13 @@ struct X86TargetABI : TargetABI {
|
|||
// Keep alignment for LLVM 13+, to prevent invalid `movaps` etc.,
|
||||
// but limit to 4 (required according to runnable/ldc_cabi1.d).
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ bool isHFVA(Type *t, int maxNumElements, Type **rewriteType);
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
128
gen/arrays.cpp
128
gen/arrays.cpp
|
@ -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) {
|
||||
assert(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");
|
||||
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
|
||||
gIR->ir->SetInsertPoint(condbb);
|
||||
|
||||
LLType *sz = DtoSize_t();
|
||||
// create the condition
|
||||
LLValue *cond_val =
|
||||
gIR->ir->CreateICmpNE(DtoLoad(itr), length, "arrayinit.condition");
|
||||
gIR->ir->CreateICmpNE(DtoLoad(sz, itr), length, "arrayinit.condition");
|
||||
|
||||
// conditional branch
|
||||
assert(!gIR->scopereturned());
|
||||
|
@ -154,10 +135,10 @@ static void DtoArrayInit(const Loc &loc, LLValue *ptr, LLValue *length,
|
|||
// rewrite scope
|
||||
gIR->ir->SetInsertPoint(bodybb);
|
||||
|
||||
LLValue *itr_val = DtoLoad(itr);
|
||||
LLValue *itr_val = DtoLoad(sz,itr);
|
||||
// assign array element value
|
||||
DLValue arrayelem(elementValue->type->toBasetype(),
|
||||
DtoGEP1(ptr, itr_val, "arrayinit.arrayelem"));
|
||||
Type *elemty = elementValue->type->toBasetype();
|
||||
DLValue arrayelem(elemty, DtoGEP1(i1ToI8(DtoType(elemty)), ptr, itr_val, "arrayinit.arrayelem"));
|
||||
DtoAssign(loc, &arrayelem, elementValue, EXP::blit);
|
||||
|
||||
// increment iterator
|
||||
|
@ -235,7 +216,7 @@ void DtoArrayAssign(const Loc &loc, DValue *lhs, DValue *rhs, EXP op,
|
|||
if (t->ty == TY::Tarray && !lhs->isSlice()) {
|
||||
assert(t2->ty == TY::Tarray || t2->ty == TY::Tsarray);
|
||||
if (rhs->isNull()) {
|
||||
DtoSetArrayToNull(DtoLVal(lhs));
|
||||
DtoSetArrayToNull(lhs);
|
||||
} else {
|
||||
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) {
|
||||
IF_LOG Logger::println("SetArray");
|
||||
LLValue *arr = DtoLVal(array);
|
||||
assert(isaStruct(arr->getType()->getContainedType(0)));
|
||||
DtoStore(dim, DtoGEP(arr, 0u, 0));
|
||||
DtoStore(ptr, DtoGEP(arr, 0, 1));
|
||||
LLType *s = isaStruct(arr->getType()->getContainedType(0));
|
||||
assert(s);
|
||||
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));
|
||||
}
|
||||
|
||||
LLConstant *gep = DtoGEP(gvar, 0u, 0u);
|
||||
LLConstant *gep = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
|
||||
gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty));
|
||||
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
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)));
|
||||
|
||||
// try to construct it in-place
|
||||
|
@ -754,19 +737,19 @@ DSliceValue *DtoNewMulDimDynArray(const Loc &loc, Type *arrayType,
|
|||
LLArrayType *type = LLArrayType::get(DtoSize_t(), ndims);
|
||||
array = DtoRawAlloca(type, 0, ".dimarray");
|
||||
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());
|
||||
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())),
|
||||
DtoGEP(darray, 0, 1, ".ptr"));
|
||||
DtoGEP(dtype, darray, 0, 1, ".ptr"));
|
||||
|
||||
// call allocator
|
||||
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';
|
||||
|
||||
|
@ -825,9 +808,10 @@ void DtoCatAssignElement(const Loc &loc, DValue *array, Expression *exp) {
|
|||
// Assign to the new last element.
|
||||
LLValue *newLength = DtoArrayLen(array);
|
||||
LLValue *ptr = DtoArrayPtr(array);
|
||||
LLType *ptrty = i1ToI8(DtoType(array->type->nextOf()));
|
||||
LLValue *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);
|
||||
DtoAssign(loc, &lastElem, expVal, EXP::blit);
|
||||
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,
|
||||
Expression *exp2) {
|
||||
IF_LOG Logger::println("DtoCatAssignArray");
|
||||
|
@ -867,7 +879,8 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
|
|||
// Create array of slices
|
||||
typedef llvm::SmallVector<llvm::Value *, 16> ArgVector;
|
||||
ArgVector arrs;
|
||||
arrs.push_back(DtoSlicePtr(exp2));
|
||||
DValue * dval = toElem(exp2);
|
||||
arrs.push_back(DtoSlicePtr(dval));
|
||||
do {
|
||||
arrs.push_back(DtoSlicePtr(ce->e2));
|
||||
ce = static_cast<CatExp *>(ce->e1);
|
||||
|
@ -877,24 +890,24 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
|
|||
// Create static array from slices
|
||||
LLPointerType *ptrarraytype = isaPointer(arrs[0]);
|
||||
assert(ptrarraytype && "Expected pointer type");
|
||||
LLStructType *arraytype = isaStruct(ptrarraytype->getPointerElementType());
|
||||
LLStructType *arraytype = DtoSlicePtrType(dval);
|
||||
assert(arraytype && "Expected struct type");
|
||||
LLArrayType *type = LLArrayType::get(arraytype, arrs.size());
|
||||
LLValue *array = DtoRawAlloca(type, 0, ".slicearray");
|
||||
unsigned int i = 0;
|
||||
for (ArgVector::reverse_iterator I = arrs.rbegin(), E = arrs.rend(); I != E;
|
||||
++I) {
|
||||
LLValue *v = DtoLoad(DtoBitCast(*I, ptrarraytype));
|
||||
DtoStore(v, DtoGEP(array, 0, i++, ".slice"));
|
||||
LLValue *v = DtoLoad(arraytype, DtoBitCast(*I, ptrarraytype));
|
||||
DtoStore(v, DtoGEP(type, array, 0, i++, ".slice"));
|
||||
}
|
||||
|
||||
LLStructType *type2 = DtoArrayType(arraytype);
|
||||
LLValue *array2 = DtoRawAlloca(type2, 0, ".array");
|
||||
DtoStore(DtoConstSize_t(arrs.size()), DtoGEP(array2, 0u, 0, ".len"));
|
||||
DtoStore(DtoBitCast(array, ptrarraytype), DtoGEP(array2, 0, 1, ".ptr"));
|
||||
LLValue *val =
|
||||
DtoLoad(DtoBitCast(array2, getPtrToType(DtoArrayType(DtoArrayType(
|
||||
LLType::getInt8Ty(gIR->context()))))));
|
||||
DtoStore(DtoConstSize_t(arrs.size()), DtoGEP(type2, array2, 0u, 0, ".len"));
|
||||
DtoStore(DtoBitCast(array, ptrarraytype), DtoGEP(type2, array2, 0, 1, ".ptr"));
|
||||
LLType *bytearrarr = DtoArrayType(DtoArrayType(LLType::getInt8Ty(gIR->context())));
|
||||
LLType *pbytearrarr = getPtrToType(bytearrarr);
|
||||
LLValue *val = DtoLoad(bytearrarr, DtoBitCast(array2, pbytearrarr));
|
||||
|
||||
// TypeInfo ti
|
||||
args.push_back(DtoTypeInfoOf(loc, arrayType));
|
||||
|
@ -905,14 +918,14 @@ DSliceValue *DtoCatArrays(const Loc &loc, Type *arrayType, Expression *exp1,
|
|||
|
||||
// TypeInfo ti
|
||||
args.push_back(DtoTypeInfoOf(loc, arrayType));
|
||||
// byte[] x
|
||||
LLValue *val = DtoLoad(DtoSlicePtr(exp1));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1));
|
||||
args.push_back(val);
|
||||
// byte[] y
|
||||
val = DtoLoad(DtoSlicePtr(exp2));
|
||||
val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2));
|
||||
args.push_back(val);
|
||||
|
||||
auto loadArray = [fn](Expression* e, int paramTypeIdx) {
|
||||
DValue * dval = toElem(e);
|
||||
LLValue *val = DtoLoad(DtoSlicePtrType(dval), DtoSlicePtr(e));
|
||||
return DtoAggrPaint(val, fn->getFunctionType()->getParamType(paramTypeIdx));
|
||||
};
|
||||
args.push_back(loadArray(exp1,1));
|
||||
args.push_back(loadArray(exp2,2));
|
||||
}
|
||||
|
||||
auto newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray");
|
||||
|
@ -1168,7 +1181,8 @@ LLValue *DtoArrayLen(DValue *v) {
|
|||
return DtoConstSize_t(0);
|
||||
}
|
||||
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();
|
||||
assert(slice);
|
||||
|
@ -1198,7 +1212,7 @@ LLValue *DtoArrayPtr(DValue *v) {
|
|||
if (v->isNull()) {
|
||||
ptr = getNullPtr(wantedLLPtrType);
|
||||
} 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 {
|
||||
auto slice = v->isSlice();
|
||||
assert(slice);
|
||||
|
|
|
@ -53,11 +53,12 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale);
|
|||
/// Initializes a chunk of memory with the contents of an array literal.
|
||||
///
|
||||
/// 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,
|
||||
bool canSkipPostblit);
|
||||
void DtoSetArrayToNull(LLValue *v);
|
||||
void DtoSetArrayToNull(DValue *v);
|
||||
|
||||
DSliceValue *DtoNewDynArray(const Loc &loc, Type *arrayType, DValue *dim,
|
||||
bool defaultInit = true);
|
||||
|
|
|
@ -200,6 +200,7 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
|
|||
|
||||
LLSmallVector<LLValue *, 8> outputLVals;
|
||||
LLSmallVector<LLType *, 8> outputTypes;
|
||||
LLSmallVector<LLType *, 8> indirectTypes;
|
||||
LLSmallVector<LLValue *, 8> operands;
|
||||
if (stmt->args) {
|
||||
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);
|
||||
if (isIndirect) {
|
||||
operands.push_back(lval);
|
||||
indirectTypes.push_back(DtoType(e->type));
|
||||
} else {
|
||||
outputLVals.push_back(lval);
|
||||
outputTypes.push_back(lval->getType()->getPointerElementType());
|
||||
outputTypes.push_back(DtoType(e->type));
|
||||
}
|
||||
} else {
|
||||
if (isIndirect && !e->isLvalue()) {
|
||||
|
@ -227,6 +229,8 @@ void GccAsmStatement_toIR(GccAsmStatement *stmt, IRState *irs) {
|
|||
|
||||
LLValue *inputVal = isIndirect ? DtoLVal(e) : DtoRVal(e);
|
||||
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);
|
||||
|
||||
LLValue *rval =
|
||||
DtoInlineAsmExpr(stmt->loc, insn, constraints, operands, returnType);
|
||||
DtoInlineAsmExpr(stmt->loc, insn, constraints, operands,
|
||||
indirectTypes, returnType);
|
||||
|
||||
if (N == 1) {
|
||||
DtoStore(rval, outputLVals[0]);
|
||||
|
|
130
gen/asmstmt.cpp
130
gen/asmstmt.cpp
|
@ -182,9 +182,10 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
static std::string memory_name = "memory";
|
||||
|
||||
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<LLValue *> output_values;
|
||||
std::vector<std::string> output_constraints;
|
||||
std::vector<std::string> clobbers;
|
||||
|
||||
|
@ -264,11 +265,11 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
|
||||
if (is_input) {
|
||||
arg_map[i] = --input_idx;
|
||||
input_values.push_back(arg_val);
|
||||
asmStmt->in.ops.push_back(arg_val);
|
||||
input_constraints.push_back(cns);
|
||||
} else {
|
||||
arg_map[i] = n_outputs++;
|
||||
output_values.push_back(arg_val);
|
||||
asmStmt->out.ops.push_back(arg_val);
|
||||
output_constraints.push_back(cns);
|
||||
}
|
||||
}
|
||||
|
@ -346,8 +347,6 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
}
|
||||
|
||||
// rewrite GCC-style constraints to LLVM-style constraints
|
||||
std::string llvmOutConstraints;
|
||||
std::string llvmInConstraints;
|
||||
int n = 0;
|
||||
for (auto &oc : output_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
|
||||
// numbering.
|
||||
input_constraints.push_back(ss.str());
|
||||
input_values.push_back(output_values[n]);
|
||||
asmStmt->in.ops.push_back(asmStmt->out.ops[n]);
|
||||
}
|
||||
llvmOutConstraints += oc;
|
||||
llvmOutConstraints += ",";
|
||||
asmStmt->out.c += oc;
|
||||
asmStmt->out.c += ",";
|
||||
n++;
|
||||
}
|
||||
asmblock->outputcount += n;
|
||||
|
||||
for (const auto &ic : input_constraints) {
|
||||
llvmInConstraints += ic;
|
||||
llvmInConstraints += ",";
|
||||
asmStmt->in.c += ic;
|
||||
asmStmt->in.c += ",";
|
||||
}
|
||||
|
||||
std::string clobstr;
|
||||
|
@ -391,7 +390,7 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
Logger::println("Output values:");
|
||||
LOG_SCOPE
|
||||
size_t i = 0;
|
||||
for (auto ov : output_values) {
|
||||
for (auto ov : asmStmt->out.ops) {
|
||||
Logger::cout() << "Out " << i++ << " = " << *ov << '\n';
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +398,7 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
Logger::println("Input values:");
|
||||
LOG_SCOPE
|
||||
size_t i = 0;
|
||||
for (auto iv : input_values) {
|
||||
for (auto iv : asmStmt->in.ops) {
|
||||
Logger::cout() << "In " << i++ << " = " << *iv << '\n';
|
||||
}
|
||||
}
|
||||
|
@ -410,50 +409,20 @@ void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
|
|||
replace_func_name(irs, code->insnTemplate);
|
||||
|
||||
// push asm statement
|
||||
auto asmStmt = new IRAsmStmt;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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",
|
||||
"5", "6", "7", "8", "9"};
|
||||
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(">>");
|
||||
std::string argnum;
|
||||
std::string needle;
|
||||
|
@ -579,8 +548,8 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
code << "movl $<<in" << n_goto << ">>, $<<out0>>\n";
|
||||
// FIXME: Store the value -> label mapping somewhere, so it can be
|
||||
// referenced later
|
||||
outSetterStmt->in.push_back(DtoConstUint(n_goto));
|
||||
outSetterStmt->in_c += "i,";
|
||||
outSetterStmt->in.ops.push_back(DtoConstUint(n_goto));
|
||||
outSetterStmt->in.c += "i,";
|
||||
code << asmGotoEnd;
|
||||
|
||||
++n_goto;
|
||||
|
@ -593,8 +562,8 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
// create storage for and initialize the temporary
|
||||
jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target");
|
||||
// setup variable for output from asm
|
||||
outSetterStmt->out_c = "=*m,";
|
||||
outSetterStmt->out.push_back(jump_target);
|
||||
outSetterStmt->out.c = "=*m,";
|
||||
outSetterStmt->out.ops.push_back(jump_target);
|
||||
|
||||
asmblock->s.push_back(outSetterStmt);
|
||||
} else {
|
||||
|
@ -616,12 +585,11 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
}
|
||||
|
||||
// build asm block
|
||||
std::vector<LLValue *> outargs;
|
||||
std::vector<LLValue *> inargs;
|
||||
std::vector<LLType *> outtypes;
|
||||
std::vector<LLType *> intypes;
|
||||
std::string out_c;
|
||||
std::string in_c;
|
||||
struct ArgBlock {
|
||||
std::vector<LLValue *> args;
|
||||
std::vector<LLType *> types;
|
||||
std::string c;
|
||||
} in, out;
|
||||
std::string clobbers;
|
||||
std::string code;
|
||||
size_t asmIdx = asmblock->retn;
|
||||
|
@ -631,15 +599,15 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
for (size_t i = 0; i < n; ++i) {
|
||||
IRAsmStmt *a = asmblock->s[i];
|
||||
assert(a);
|
||||
size_t onn = a->out.size();
|
||||
size_t onn = a->out.ops.size();
|
||||
for (size_t j = 0; j < onn; ++j) {
|
||||
outargs.push_back(a->out[j]);
|
||||
outtypes.push_back(a->out[j]->getType());
|
||||
out.args.push_back(a->out.ops[j]);
|
||||
out.types.push_back(a->out.ops[j]->getType());
|
||||
}
|
||||
if (!a->out_c.empty()) {
|
||||
out_c += a->out_c;
|
||||
if (!a->out.c.empty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -647,15 +615,15 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
for (size_t i = 0; i < n; ++i) {
|
||||
IRAsmStmt *a = asmblock->s[i];
|
||||
assert(a);
|
||||
size_t inn = a->in.size();
|
||||
size_t inn = a->in.ops.size();
|
||||
for (size_t j = 0; j < inn; ++j) {
|
||||
inargs.push_back(a->in[j]);
|
||||
intypes.push_back(a->in[j]->getType());
|
||||
in.args.push_back(a->in.ops[j]);
|
||||
in.types.push_back(a->in.ops[j]->getType());
|
||||
}
|
||||
if (!a->in_c.empty()) {
|
||||
in_c += a->in_c;
|
||||
if (!a->in.c.empty()) {
|
||||
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;
|
||||
if (!code.empty()) {
|
||||
code += "\n\t";
|
||||
|
@ -665,21 +633,21 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
asmblock->s.clear();
|
||||
|
||||
// append inputs
|
||||
out_c += in_c;
|
||||
out.c += in.c;
|
||||
|
||||
// append clobbers
|
||||
for (const auto &c : asmblock->clobs) {
|
||||
out_c += c;
|
||||
out.c += c;
|
||||
}
|
||||
|
||||
// remove excessive comma
|
||||
if (!out_c.empty()) {
|
||||
out_c.resize(out_c.size() - 1);
|
||||
if (!out.c.empty()) {
|
||||
out.c.resize(out.c.size() - 1);
|
||||
}
|
||||
|
||||
IF_LOG {
|
||||
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
|
||||
|
@ -692,14 +660,14 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
|
||||
// build argument types
|
||||
std::vector<LLType *> types;
|
||||
types.insert(types.end(), outtypes.begin(), outtypes.end());
|
||||
types.insert(types.end(), intypes.begin(), intypes.end());
|
||||
types.insert(types.end(), out.types.begin(), out.types.end());
|
||||
types.insert(types.end(), in.types.begin(), in.types.end());
|
||||
llvm::FunctionType *fty = llvm::FunctionType::get(retty, types, false);
|
||||
IF_LOG Logger::cout() << "function type = " << *fty << '\n';
|
||||
|
||||
std::vector<LLValue *> args;
|
||||
args.insert(args.end(), outargs.begin(), outargs.end());
|
||||
args.insert(args.end(), inargs.begin(), inargs.end());
|
||||
args.insert(args.end(), out.args.begin(), out.args.end());
|
||||
args.insert(args.end(), in.args.begin(), in.args.end());
|
||||
|
||||
IF_LOG {
|
||||
Logger::cout() << "Arguments:" << '\n';
|
||||
|
@ -717,9 +685,9 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
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()) {
|
||||
call->setName("asm");
|
||||
}
|
||||
|
@ -732,7 +700,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
if (block->retfixup) {
|
||||
block->asmBlock->abiret = (*block->retfixup)(p->ir, call);
|
||||
} else if (p->asmBlock->retemu) {
|
||||
block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret);
|
||||
block->asmBlock->abiret = DtoLoad(block->retty, block->asmBlock->abiret);
|
||||
} else {
|
||||
block->asmBlock->abiret = call;
|
||||
}
|
||||
|
@ -747,7 +715,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
|||
// make new blocks
|
||||
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());
|
||||
|
||||
// add all cases
|
||||
|
|
|
@ -89,12 +89,14 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset,
|
|||
// pointer elements. We try to undo this before resorting to
|
||||
// temporarily bitcasting the pointer to i8.
|
||||
|
||||
LLType * llBaseTy = nullptr;
|
||||
LLValue *llBase = nullptr;
|
||||
LLValue *llOffset = nullptr;
|
||||
LLValue *llResult = nullptr;
|
||||
|
||||
if (offset->isConst()) {
|
||||
llBase = DtoRVal(base);
|
||||
llBaseTy = DtoMemType(base->type->nextOf());
|
||||
dinteger_t byteOffset = offset->toInteger();
|
||||
if (byteOffset == 0) {
|
||||
llResult = llBase;
|
||||
|
@ -107,15 +109,18 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset,
|
|||
auto rvals =
|
||||
evalSides(base, noStrideInc ? noStrideInc : offset, loadLhsAfterRhs);
|
||||
llBase = DtoRVal(rvals.lhs);
|
||||
llBaseTy = DtoMemType(rvals.lhs->type->nextOf());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if (!llResult) {
|
||||
if (negateOffset)
|
||||
llOffset = gIR->ir->CreateNeg(llOffset);
|
||||
llResult = DtoGEP1(llBase, llOffset);
|
||||
llResult = DtoGEP1(llBaseTy, llBase, llOffset);
|
||||
}
|
||||
|
||||
return new DImValue(resultType, DtoBitCast(llResult, DtoType(resultType)));
|
||||
|
|
|
@ -157,6 +157,7 @@ class MultiSetter {
|
|||
public:
|
||||
// end with a nullptr
|
||||
MultiSetter(bool invert, CHECKENABLE *p, ...);
|
||||
MultiSetter() = default;
|
||||
|
||||
void operator=(bool val);
|
||||
};
|
||||
|
|
|
@ -105,7 +105,7 @@ DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
|
|||
LOG_SCOPE;
|
||||
unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
|
||||
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';
|
||||
DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
|
||||
}
|
||||
|
@ -141,9 +141,10 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
|
|||
DtoResolveClass(tc->sym);
|
||||
|
||||
IrClass *irClass = getIrAggr(tc->sym);
|
||||
llvm::StructType *st = irClass->getLLStructType();
|
||||
|
||||
// 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 =
|
||||
DtoBitCast(irClass->getVtblSymbol(), tmp->getType()->getContainedType(0));
|
||||
DtoStore(val, tmp);
|
||||
|
@ -151,7 +152,7 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
|
|||
// For D classes, set the monitor field to null.
|
||||
const bool isCPPclass = tc->sym->isCPPclass() ? true : false;
|
||||
if (!isCPPclass) {
|
||||
tmp = DtoGEP(dst, 0, 1, "monitor");
|
||||
tmp = DtoGEP(st, dst, 0, 1, "monitor");
|
||||
val = LLConstant::getNullValue(tmp->getType()->getContainedType(0));
|
||||
DtoStore(val, tmp);
|
||||
}
|
||||
|
@ -164,12 +165,12 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
|
|||
return;
|
||||
}
|
||||
|
||||
LLValue *dstarr = DtoGEP(dst, 0, firstDataIdx);
|
||||
LLValue *dstarr = DtoGEP(st, dst, 0, firstDataIdx);
|
||||
|
||||
// init symbols might not have valid types
|
||||
LLValue *initsym = irClass->getInitSymbol();
|
||||
initsym = DtoBitCast(initsym, DtoType(tc));
|
||||
LLValue *srcarr = DtoGEP(initsym, 0, firstDataIdx);
|
||||
LLValue *srcarr = DtoGEP(st, initsym, 0, firstDataIdx);
|
||||
|
||||
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) {
|
||||
DtoFinalizeClass(loc, inst);
|
||||
return;
|
||||
|
@ -198,7 +200,9 @@ void DtoFinalizeScopeClass(const Loc &loc, LLValue *inst, bool hasDtor) {
|
|||
llvm::BasicBlock *ifbb = gIR->insertBB("if");
|
||||
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 =
|
||||
gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor,
|
||||
getNullValue(monitor->getType()), ".hasMonitor");
|
||||
|
@ -280,7 +284,7 @@ DValue *DtoCastClass(const Loc &loc, DValue *val, Type *_to) {
|
|||
if (offset != 0) {
|
||||
assert(offset > 0);
|
||||
v = DtoBitCast(v, getVoidPtrType());
|
||||
v = DtoGEP1(v, DtoConstUint(offset));
|
||||
v = DtoGEP1(LLType::getInt8Ty(gIR->context()), v, DtoConstUint(offset));
|
||||
}
|
||||
IF_LOG {
|
||||
Logger::cout() << "V = " << *v << std::endl;
|
||||
|
@ -405,7 +409,8 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
|
|||
// sanity checks
|
||||
assert(fdecl->isVirtual());
|
||||
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
|
||||
assert(fdecl->vtblIndex > 0 ||
|
||||
(fdecl->vtblIndex == 0 &&
|
||||
|
@ -415,17 +420,20 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
|
|||
LLValue *vthis = DtoRVal(inst);
|
||||
IF_LOG Logger::cout() << "vthis: " << *vthis << '\n';
|
||||
|
||||
IrClass * irc = getIrAggr(tc->sym, true);
|
||||
LLValue *funcval = vthis;
|
||||
// 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
|
||||
funcval = DtoLoad(funcval);
|
||||
funcval = DtoLoad(vtblsym->getType(), funcval);
|
||||
// index vtbl
|
||||
const std::string name = fdecl->toChars();
|
||||
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
|
||||
funcval = DtoAlignedLoad(funcval);
|
||||
funcval = DtoAlignedLoad(getVoidPtrType(), funcval);
|
||||
|
||||
IF_LOG Logger::cout() << "funcval: " << *funcval << '\n';
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
class ClassDeclaration;
|
||||
class CtorDeclaration;
|
||||
class DValue;
|
||||
class FuncDeclaration;
|
||||
class NewExp;
|
||||
class TypeClass;
|
||||
|
@ -28,7 +29,7 @@ void DtoResolveClass(ClassDeclaration *cd);
|
|||
DValue *DtoNewClass(const Loc &loc, TypeClass *type, NewExp *newexp);
|
||||
void DtoInitClass(TypeClass *tc, llvm::Value *dst);
|
||||
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 *DtoDynamicCastObject(const Loc &loc, DValue *val, Type *to);
|
||||
|
|
|
@ -107,9 +107,9 @@ DValue *DtoComplex(const Loc &loc, Type *to, DValue *val) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoComplexSet(LLValue *c, LLValue *re, LLValue *im) {
|
||||
DtoStore(re, DtoGEP(c, 0u, 0));
|
||||
DtoStore(im, DtoGEP(c, 0, 1));
|
||||
void DtoComplexSet(LLType* ty, LLValue *c, LLValue *re, LLValue *im) {
|
||||
DtoStore(re, DtoGEP(ty, c, 0u, 0));
|
||||
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);
|
||||
if (to->iscomplex()) {
|
||||
if (v->isLVal()) {
|
||||
LLValue *reVal = DtoGEP(DtoLVal(v), 0u, 0, ".re_part");
|
||||
LLValue *imVal = DtoGEP(DtoLVal(v), 0, 1, ".im_part");
|
||||
LLValue *reVal = DtoGEP(DtoType(v->type), DtoLVal(v), 0u, 0, ".re_part");
|
||||
LLValue *imVal = DtoGEP(DtoType(v->type), DtoLVal(v), 0, 1, ".im_part");
|
||||
re = new DLValue(baserety, reVal);
|
||||
im = new DLValue(baseimty, imVal);
|
||||
} else {
|
||||
|
|
|
@ -34,7 +34,7 @@ llvm::Constant *DtoComplexShuffleMask(unsigned a, unsigned b);
|
|||
|
||||
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,
|
||||
DValue *&im);
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
struct DComputePointerRewrite : ABIRewrite {
|
||||
LLValue *put(DValue *v, bool isLValueExp, bool) override {
|
||||
LLValue *address = DtoLVal(v);
|
||||
address = DtoGEP(address, 0u, 0u);
|
||||
return DtoLoad(address, ".DComputePointerRewrite_arg");
|
||||
address = DtoGEP(DtoType(v->type), address, 0u, 0u);
|
||||
return DtoLoad(type(v->type), address, ".DComputePointerRewrite_arg");
|
||||
}
|
||||
|
||||
LLValue *getLVal(Type *dty, LLValue *v) override {
|
||||
LLValue *mem = DtoAlloca(dty, ".DComputePointerRewrite_param_storage");
|
||||
DtoStore(v, DtoGEP(mem, 0u, 0u));
|
||||
DtoStore(v, DtoGEP(DtoType(dty), mem, 0u, 0u));
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
|
|
@ -545,10 +545,9 @@ DIType DIBuilder::CreateCompositeType(Type *t) {
|
|||
|
||||
// Use the actual type associated with the declaration, ignoring any
|
||||
// const/wrappers.
|
||||
LLType *T = DtoType(ad->type);
|
||||
if (t->ty == TY::Tclass)
|
||||
T = T->getPointerElementType();
|
||||
DtoType(ad->type);
|
||||
IrAggr *irAggr = getIrAggr(ad, true);
|
||||
LLType *T = irAggr->getLLStructType();
|
||||
|
||||
if (irAggr->diCompositeType) {
|
||||
return irAggr->diCompositeType;
|
||||
|
|
|
@ -131,7 +131,7 @@ DRValue *DLValue::getRVal() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
LLValue *rval = DtoLoad(val);
|
||||
LLValue *rval = DtoLoad(val->getType()->getPointerElementType(), val);
|
||||
|
||||
const auto ty = type->toBasetype()->ty;
|
||||
if (ty == TY::Tbool) {
|
||||
|
@ -161,10 +161,12 @@ DSpecialRefValue::DSpecialRefValue(Type *t, LLValue *v) : DLValue(v, t) {
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -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);
|
||||
llvm::ConstantInt *zero = llvm::ConstantInt::get(
|
||||
llvm::Type::getInt32Ty(array->getContext()), 0, false);
|
||||
llvm::Constant *idxs[] = {zero, zero};
|
||||
return llvm::ConstantExpr::getGetElementPtr(getPointeeType(array), array,
|
||||
return llvm::ConstantExpr::getGetElementPtr(type, array,
|
||||
idxs, true);
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ getArrayAndSize(llvm::Module &module, llvm::Type *elemType,
|
|||
module, arrayType, true, llvm::GlobalValue::PrivateLinkage,
|
||||
llvm::ConstantArray::get(arrayType, elements), ".str");
|
||||
return std::make_pair(
|
||||
getArrayPtr(arrVar),
|
||||
getArrayPtr(arrVar->getValueType() ,arrVar),
|
||||
llvm::ConstantInt::get(module.getContext(), APInt(32, elements.size())));
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,7 @@ void createStaticI8Array(llvm::Module &mod, llvm::GlobalVariable *var,
|
|||
dataLen),
|
||||
true, llvm::GlobalValue::InternalLinkage,
|
||||
llvm::ConstantDataArray::get(mod.getContext(), arr), ".str");
|
||||
var->setInitializer(getArrayPtr(gvar));
|
||||
var->setInitializer(getArrayPtr(gvar->getValueType(), gvar));
|
||||
if (nullptr != varLen) {
|
||||
varLen->setInitializer(
|
||||
llvm::ConstantInt::get(mod.getContext(), APInt(32, dataLen)));
|
||||
|
|
|
@ -1291,7 +1291,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
|||
LLType *targetThisType = thismem->getType();
|
||||
thismem = DtoBitCast(thismem, getVoidPtrType());
|
||||
auto off = DtoConstInt(-fd->interfaceVirtual->offset);
|
||||
thismem = DtoGEP1(thismem, off);
|
||||
thismem = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), thismem, off);
|
||||
thismem = DtoBitCast(thismem, targetThisType);
|
||||
}
|
||||
thismem = DtoAllocaDump(thismem, 0, "this");
|
||||
|
|
|
@ -264,7 +264,8 @@ void IRState::addLinkerDependentLib(llvm::StringRef libraryName) {
|
|||
|
||||
llvm::CallInst *
|
||||
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);
|
||||
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
|
||||
// constraint/argument index mapping
|
||||
ptrdiff_t i = call->getType()->isVoidTy() ? 0 : -1;
|
||||
size_t indirectIdx = 0, indirectLen = indirectTypes.size();
|
||||
|
||||
for (const auto &constraintInfo : ia->ParseConstraints()) {
|
||||
if (constraintInfo.isIndirect) {
|
||||
call->addParamAttr(i, llvm::Attribute::get(context(),
|
||||
llvm::Type *indirectType = indirectLen != 0 ?
|
||||
indirectTypes[indirectIdx] :
|
||||
args[i]->getType()->getPointerElementType();
|
||||
|
||||
call->addParamAttr(i, llvm::Attribute::get(
|
||||
context(),
|
||||
llvm::Attribute::ElementType,
|
||||
getPointeeType(args[i])));
|
||||
indirectType));
|
||||
++indirectIdx;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -77,10 +77,11 @@ struct IRAsmStmt {
|
|||
IRAsmStmt() : isBranchToLabel(nullptr) {}
|
||||
|
||||
std::string code;
|
||||
std::string out_c;
|
||||
std::string in_c;
|
||||
std::vector<LLValue *> out;
|
||||
std::vector<LLValue *> in;
|
||||
struct Operands {
|
||||
std::string c; // contraint
|
||||
std::vector<LLValue *> ops;
|
||||
};
|
||||
Operands out, in;
|
||||
|
||||
// if this is nonzero, it contains the target label
|
||||
LabelDsymbol *isBranchToLabel;
|
||||
|
@ -267,7 +268,8 @@ public:
|
|||
void addLinkerDependentLib(llvm::StringRef libraryName);
|
||||
|
||||
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);
|
||||
const Loc &getInlineAsmSrcLoc(unsigned srcLocCookie) const;
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment,
|
|||
LLType *asMemType = i1ToI8(voidToI8(asType));
|
||||
LLValue *copy = DtoRawAlloca(asMemType, alignment, name);
|
||||
const auto minSize =
|
||||
std::min(getTypeAllocSize(lval->getType()->getPointerElementType()),
|
||||
std::min(getTypeAllocSize(DtoType(val->type)),
|
||||
getTypeAllocSize(asMemType));
|
||||
const auto minAlignment =
|
||||
std::min(DtoAlignment(val->type), static_cast<unsigned>(alignment));
|
||||
|
@ -1865,7 +1865,7 @@ FuncDeclaration *getParentFunc(Dsymbol *sym) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||
DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||
VarDeclaration *vd) {
|
||||
IF_LOG Logger::println("Indexing aggregate field %s:", vd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
@ -1876,45 +1876,51 @@ LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
|||
DtoResolveDsymbol(ad);
|
||||
|
||||
// Look up field to index or offset to apply.
|
||||
unsigned fieldIndex;
|
||||
unsigned byteOffset;
|
||||
auto irTypeAggr = getIrType(ad->type)->isAggr();
|
||||
assert(irTypeAggr);
|
||||
irTypeAggr->getMemberLocation(vd, fieldIndex, byteOffset);
|
||||
bool isFieldIdx;
|
||||
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
|
||||
|
||||
LLValue *ptr = src;
|
||||
if (byteOffset) {
|
||||
assert(fieldIndex == 0);
|
||||
if (!isFieldIdx) {
|
||||
// Cast to void* to apply byte-wise offset from object start.
|
||||
ptr = DtoBitCast(ptr, getVoidPtrType());
|
||||
ptr = DtoGEP1(ptr, byteOffset);
|
||||
ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, off);
|
||||
} else {
|
||||
if (ad->structsize == 0) { // can happen for extern(C) structs
|
||||
assert(fieldIndex == 0);
|
||||
assert(off == 0);
|
||||
} else {
|
||||
// Cast the pointer we got to the canonical struct type the indices are
|
||||
// based on.
|
||||
LLType *st = DtoType(ad->type);
|
||||
if (ad->isStructDeclaration()) {
|
||||
st = getPtrToType(st);
|
||||
LLType *st = nullptr;
|
||||
LLType *pst = nullptr;
|
||||
if (ad->isClassDeclaration()) {
|
||||
st = getIrAggr(ad)->getLLStructType();
|
||||
pst = DtoType(ad->type);
|
||||
}
|
||||
ptr = DtoBitCast(ptr, st);
|
||||
ptr = DtoGEP(ptr, 0, fieldIndex);
|
||||
else {
|
||||
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';
|
||||
return ptr;
|
||||
return new DLValue(vd->type, ptr);
|
||||
}
|
||||
|
||||
unsigned getFieldGEPIndex(AggregateDeclaration *ad, VarDeclaration *vd) {
|
||||
unsigned fieldIndex;
|
||||
unsigned byteOffset;
|
||||
auto irTypeAggr = getIrType(ad->type)->isAggr();
|
||||
assert(irTypeAggr);
|
||||
irTypeAggr->getMemberLocation(vd, fieldIndex, byteOffset);
|
||||
assert(byteOffset == 0 && "Cannot address field by a simple GEP.");
|
||||
return fieldIndex;
|
||||
bool isFieldIdx;
|
||||
unsigned off = irTypeAggr->getMemberLocation(vd, isFieldIdx);
|
||||
assert(isFieldIdx && "Cannot address field by a simple GEP.");
|
||||
return off;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (val->getType() != expectedType) {
|
||||
#if LDC_LLVM_VER < 1500
|
||||
// The type of globals is determined by their initializer, and the front-end
|
||||
// may inject implicit casts for class references and static arrays.
|
||||
assert(vd->isDataseg() || (vd->storage_class & STCextern) ||
|
||||
|
@ -1943,6 +1950,7 @@ DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
|
|||
// work as well.
|
||||
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(pointeeType) &&
|
||||
"LValue type mismatch, encountered type too small.");
|
||||
#endif
|
||||
val = DtoBitCast(val, expectedType);
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ void findDefaultTarget();
|
|||
/// 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.
|
||||
LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||
DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
|
||||
VarDeclaration *vd);
|
||||
|
||||
/// 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::StringRef constraints,
|
||||
llvm::ArrayRef<llvm::Value *> operands,
|
||||
llvm::ArrayRef<llvm::Type *> indirectTypes,
|
||||
llvm::Type *returnType);
|
||||
|
||||
/// 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);
|
||||
|
||||
///
|
||||
LLValue *DtoCallableValue(DValue *fn);
|
||||
|
||||
///
|
||||
LLFunctionType *DtoExtractFunctionType(LLType *type);
|
||||
|
||||
/// 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
|
||||
/// DValue (if any). If the call does not correspond to a "magic" intrinsic,
|
||||
|
|
|
@ -85,9 +85,10 @@ llvm::Function *buildForwarderFunction(
|
|||
|
||||
// ... incrementing the gate variables.
|
||||
for (auto gate : gates) {
|
||||
assert(getIrGlobal(gate));
|
||||
const auto val = getIrGlobal(gate)->value;
|
||||
const auto rval = builder.CreateLoad(getPointeeType(val), val, "vgate");
|
||||
const auto glob = getIrGlobal(gate);
|
||||
assert(glob);
|
||||
const auto val = glob->value;
|
||||
const auto rval = builder.CreateLoad(glob->getType(), val, "vgate");
|
||||
const auto res = builder.CreateAdd(rval, DtoConstUint(1), "vgate");
|
||||
builder.CreateStore(res, val);
|
||||
}
|
||||
|
|
|
@ -268,7 +268,8 @@ void addCoverageAnalysis(Module *m) {
|
|||
init, "_d_cover_data");
|
||||
|
||||
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,
|
||||
|
|
|
@ -271,19 +271,19 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
|
|||
if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass ||
|
||||
rt->ty == TY::Taarray) {
|
||||
if (rt->size() == 8) {
|
||||
as->out_c = "=A,";
|
||||
as->out.c = "=A,";
|
||||
} else {
|
||||
as->out_c = "={ax},";
|
||||
as->out.c = "={ax},";
|
||||
}
|
||||
} else if (rt->isfloating()) {
|
||||
if (rt->iscomplex()) {
|
||||
if (fdecl->_linkage == LINK::d) {
|
||||
// extern(D) always returns on the FPU stack
|
||||
as->out_c = "={st},={st(1)},";
|
||||
as->out.c = "={st},={st(1)},";
|
||||
asmblock->retn = 2;
|
||||
} else if (rt->ty == TY::Tcomplex32) {
|
||||
// non-extern(D) cfloat is returned as i64
|
||||
as->out_c = "=A,";
|
||||
as->out.c = "=A,";
|
||||
asmblock->retty = LLType::getInt64Ty(gIR->context());
|
||||
} else {
|
||||
// non-extern(D) cdouble and creal are returned via sret
|
||||
|
@ -293,10 +293,10 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
as->out_c = "={st},";
|
||||
as->out.c = "={st},";
|
||||
}
|
||||
} else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) {
|
||||
as->out_c = "={ax},={dx},";
|
||||
as->out.c = "={ax},={dx},";
|
||||
asmblock->retn = 2;
|
||||
#if 0
|
||||
// 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
|
||||
|
||||
// generate asm
|
||||
as->out_c = "=*m,=*m,";
|
||||
as->out.c = "=*m,=*m,";
|
||||
LLValue* tmp = DtoRawAlloca(llretTy, 0, ".tmp_asm_ret");
|
||||
as->out.push_back( tmp );
|
||||
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) {
|
||||
if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass ||
|
||||
rt->ty == TY::Taarray) {
|
||||
as->out_c = "={ax},";
|
||||
as->out.c = "={ax},";
|
||||
} else if (rt->isfloating()) {
|
||||
const bool isWin64 = triple.isOSWindows();
|
||||
|
||||
if (rt == Type::tcomplex80 && !isWin64) {
|
||||
// On x87 stack, re=st, im=st(1)
|
||||
as->out_c = "={st},={st(1)},";
|
||||
as->out.c = "={st},={st(1)},";
|
||||
asmblock->retn = 2;
|
||||
} else if ((rt == Type::tfloat80 || rt == Type::timaginary80) &&
|
||||
!triple.isWindowsMSVCEnvironment()) {
|
||||
// On x87 stack
|
||||
as->out_c = "={st},";
|
||||
as->out.c = "={st},";
|
||||
} else if (rt == Type::tcomplex32) {
|
||||
if (isWin64) {
|
||||
// cfloat on Win64 -> %rax
|
||||
as->out_c = "={ax},";
|
||||
as->out.c = "={ax},";
|
||||
asmblock->retty = LLType::getInt64Ty(gIR->context());
|
||||
} else {
|
||||
// cfloat on Posix -> %xmm0 (extract two floats)
|
||||
as->out_c = "={xmm0},";
|
||||
as->out.c = "={xmm0},";
|
||||
asmblock->retty = LLType::getDoubleTy(gIR->context());
|
||||
}
|
||||
} else if (rt->iscomplex()) {
|
||||
|
@ -365,15 +365,15 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc,
|
|||
return;
|
||||
} else {
|
||||
// cdouble on Posix -> re=%xmm0, im=%xmm1
|
||||
as->out_c = "={xmm0},={xmm1},";
|
||||
as->out.c = "={xmm0},={xmm1},";
|
||||
asmblock->retn = 2;
|
||||
}
|
||||
} else {
|
||||
// Plain float/double/ifloat/idouble
|
||||
as->out_c = "={xmm0},";
|
||||
as->out.c = "={xmm0},";
|
||||
}
|
||||
} else if (rt->ty == TY::Tarray || rt->ty == TY::Tdelegate) {
|
||||
as->out_c = "={ax},={dx},";
|
||||
as->out.c = "={ax},={dx},";
|
||||
asmblock->retn = 2;
|
||||
} else {
|
||||
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,
|
||||
constraintsStr.length};
|
||||
|
||||
auto constraintInfo = llvm::InlineAsm::ParseConstraints(constraints);
|
||||
// build runtime arguments
|
||||
const size_t n = arguments->length - 2;
|
||||
LLSmallVector<LLValue *, 8> operands;
|
||||
LLSmallVector<LLType *, 8> indirectTypes;
|
||||
operands.reserve(n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
operands.push_back(DtoRVal((*arguments)[2 + i]));
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 =
|
||||
DtoInlineAsmExpr(loc, code, constraints, operands, irReturnType);
|
||||
DtoInlineAsmExpr(loc, code, constraints, operands, indirectTypes, irReturnType);
|
||||
|
||||
// work around missing tuple support for users of the return value
|
||||
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::StringRef constraints,
|
||||
llvm::ArrayRef<llvm::Value *> operands,
|
||||
llvm::ArrayRef<llvm::Type *> indirectTypes,
|
||||
llvm::Type *returnType) {
|
||||
IF_LOG Logger::println("DtoInlineAsmExpr @ %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
@ -471,7 +504,13 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
|
|||
llvm::FunctionType::get(returnType, operandTypes, false);
|
||||
|
||||
// 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");
|
||||
fatal();
|
||||
}
|
||||
|
@ -480,7 +519,7 @@ llvm::CallInst *DtoInlineAsmExpr(const Loc &loc, llvm::StringRef code,
|
|||
bool sideeffect = true;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,22 @@ bool isNRVOVar(VarDeclaration *vd) {
|
|||
bool captureByRef(VarDeclaration *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
|
||||
|
||||
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()) {
|
||||
Logger::println(
|
||||
"Current function is member of nested class, loading vthis");
|
||||
LLValue *val =
|
||||
ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg;
|
||||
LLValue *val = loadThisPtr(ad, *irfunc);
|
||||
|
||||
for (; ad; ad = ad->toParent2()->isAggregateDeclaration()) {
|
||||
assert(ad->vthis);
|
||||
val = DtoLoad(DtoGEP(val, 0, getVthisIdx(ad), ".vthis"));
|
||||
val = indexVThis(ad, val);
|
||||
}
|
||||
ctx = val;
|
||||
skipDIDeclaration = true;
|
||||
|
@ -118,10 +134,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
// Extract variable from nested context
|
||||
|
||||
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'; }
|
||||
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);
|
||||
// register all ops (offsetting, dereferencing) required to get there in the
|
||||
// following list.
|
||||
|
@ -131,14 +147,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
LLSmallVector<int64_t, 4> dwarfAddrOps;
|
||||
#endif
|
||||
|
||||
const auto offsetToNthField = [&val, &dwarfAddrOps](unsigned fieldIndex,
|
||||
const auto offsetToNthField = [&val, &dwarfAddrOps, &currFrame](unsigned fieldIndex,
|
||||
const char *name = "") {
|
||||
gIR->DBuilder.OpOffset(dwarfAddrOps, val, fieldIndex);
|
||||
val = DtoGEP(val, 0, fieldIndex, name);
|
||||
};
|
||||
const auto dereference = [&val, &dwarfAddrOps](const char *name = "") {
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
val = DtoAlignedLoad(val, name);
|
||||
val = DtoGEP(currFrame, val, 0, fieldIndex, name);
|
||||
};
|
||||
|
||||
const auto vardepth = irLocal->nestedDepth;
|
||||
|
@ -160,7 +172,10 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
IF_LOG Logger::println("Lower depth");
|
||||
offsetToNthField(vardepth);
|
||||
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';
|
||||
}
|
||||
|
||||
|
@ -173,7 +188,7 @@ DValue *DtoNestedVariable(const Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
// Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass
|
||||
// storage of pointer (reference lvalue).
|
||||
} else if (byref || captureByRef(vd)) {
|
||||
val = DtoAlignedLoad(val);
|
||||
val = DtoAlignedLoad(irLocal->value->getType(), val);
|
||||
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable()
|
||||
// => don't dereference, use reference lvalue as address
|
||||
if (!vd->isReference())
|
||||
|
@ -211,7 +226,8 @@ void DtoResolveNestedContext(const Loc &loc, AggregateDeclaration *decl,
|
|||
DtoResolveDsymbol(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);
|
||||
}
|
||||
}
|
||||
|
@ -262,13 +278,13 @@ LLValue *DtoNestedContext(const Loc &loc, Dsymbol *sym) {
|
|||
} else if (irFunc.thisArg) {
|
||||
// or just have a this argument
|
||||
AggregateDeclaration *ad = irFunc.decl->isMember2();
|
||||
val = ad->isClassDeclaration() ? DtoLoad(irFunc.thisArg) : irFunc.thisArg;
|
||||
val = loadThisPtr(ad, irFunc);
|
||||
if (!ad->vthis) {
|
||||
// This is just a plain 'outer' reference of a class nested in a
|
||||
// function (but without any variables in the nested context).
|
||||
return val;
|
||||
}
|
||||
val = DtoLoad(DtoGEP(val, 0, getVthisIdx(ad), ".vthis"));
|
||||
val = indexVThis(ad, val);
|
||||
} else {
|
||||
if (sym->isFuncDeclaration()) {
|
||||
// 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(
|
||||
"Calling sibling function or directly nested function");
|
||||
} else {
|
||||
val = DtoBitCast(val,
|
||||
LLPointerType::getUnqual(getIrFunc(ctxfd)->frameType));
|
||||
val = DtoGEP(val, 0, neededDepth);
|
||||
val = DtoAlignedLoad(
|
||||
llvm::StructType *type = getIrFunc(ctxfd)->frameType;
|
||||
val = DtoBitCast(val, LLPointerType::getUnqual(type));
|
||||
val = DtoGEP(type, val, 0, neededDepth);
|
||||
val = DtoAlignedLoad(type->getElementType(neededDepth),
|
||||
val, (std::string(".frame.") + frameToPass->toChars()).c_str());
|
||||
}
|
||||
}
|
||||
|
@ -476,10 +492,9 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
|||
AggregateDeclaration *ad = fd->isMember2();
|
||||
assert(ad);
|
||||
assert(ad->vthis);
|
||||
LLValue *thisptr =
|
||||
ad->isClassDeclaration() ? DtoLoad(irFunc.thisArg) : irFunc.thisArg;
|
||||
LLValue *thisptr = loadThisPtr(ad, irFunc);
|
||||
IF_LOG Logger::println("Indexing to 'this'");
|
||||
src = DtoLoad(DtoGEP(thisptr, 0, getVthisIdx(ad), ".vthis"));
|
||||
src = indexVThis(ad, thisptr);
|
||||
}
|
||||
if (depth > 1) {
|
||||
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
|
||||
// pointers
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -505,7 +520,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
|||
}
|
||||
|
||||
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_LOG Logger::println("nested param: %s", vd->toChars());
|
||||
LOG_SCOPE
|
||||
|
|
|
@ -149,7 +149,7 @@ llvm::CodeGenOpt::Level codeGenOptLevel() {
|
|||
return llvm::CodeGenOpt::Default;
|
||||
}
|
||||
|
||||
static inline void addPass(PassManagerBase &pm, Pass *pass) {
|
||||
static inline void legacyAddPass(PassManagerBase &pm, Pass *pass) {
|
||||
pm.add(pass);
|
||||
|
||||
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) {
|
||||
if (builder.OptLevel >= 1) {
|
||||
addPass(pm, createStripExternalsPass());
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
legacyAddPass(pm, createStripExternalsPass());
|
||||
legacyAddPass(pm, createGlobalDCEPass());
|
||||
}
|
||||
}
|
||||
|
||||
static void addSimplifyDRuntimeCallsPass(const PassManagerBuilder &builder,
|
||||
static void legacyAddSimplifyDRuntimeCallsPass(const PassManagerBuilder &builder,
|
||||
PassManagerBase &pm) {
|
||||
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) {
|
||||
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) {
|
||||
PM.add(createAddressSanitizerFunctionPass());
|
||||
PM.add(createModuleAddressSanitizerLegacyPassPass());
|
||||
}
|
||||
|
||||
static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
|
||||
static void legacyAddMemorySanitizerPass(const PassManagerBuilder &Builder,
|
||||
PassManagerBase &PM) {
|
||||
int trackOrigins = fSanitizeMemoryTrackOrigins;
|
||||
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) {
|
||||
PM.add(createThreadSanitizerLegacyPassPass());
|
||||
}
|
||||
|
||||
static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
|
||||
static void legacyAddSanitizerCoveragePass(const PassManagerBuilder &Builder,
|
||||
legacy::PassManagerBase &PM) {
|
||||
#if LDC_LLVM_VER >= 1000
|
||||
PM.add(createModuleSanitizerCoverageLegacyPassPass(
|
||||
|
@ -223,7 +223,7 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
|
|||
}
|
||||
|
||||
// Adds PGO instrumentation generation and use passes.
|
||||
static void addPGOPasses(PassManagerBuilder &builder,
|
||||
static void legacyAddPGOPasses(PassManagerBuilder &builder,
|
||||
legacy::PassManagerBase &mpm, unsigned optLevel) {
|
||||
if (opts::isInstrumentingForASTBasedPGO()) {
|
||||
InstrProfOptions options;
|
||||
|
@ -252,7 +252,7 @@ static void addPGOPasses(PassManagerBuilder &builder,
|
|||
* The selection mirrors Clang behavior and is based on LLVM's
|
||||
* PassManagerBuilder.
|
||||
*/
|
||||
static void addOptimizationPasses(legacy::PassManagerBase &mpm,
|
||||
static void legacyAddOptimizationPasses(legacy::PassManagerBase &mpm,
|
||||
legacy::FunctionPassManager &fpm,
|
||||
unsigned optLevel, unsigned sizeLevel) {
|
||||
if (!noVerify) {
|
||||
|
@ -291,49 +291,49 @@ static void addOptimizationPasses(legacy::PassManagerBase &mpm,
|
|||
|
||||
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
||||
addAddressSanitizerPasses);
|
||||
legacyAddAddressSanitizerPasses);
|
||||
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
addAddressSanitizerPasses);
|
||||
legacyAddAddressSanitizerPasses);
|
||||
}
|
||||
|
||||
if (opts::isSanitizerEnabled(opts::MemorySanitizer)) {
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
||||
addMemorySanitizerPass);
|
||||
legacyAddMemorySanitizerPass);
|
||||
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
addMemorySanitizerPass);
|
||||
legacyAddMemorySanitizerPass);
|
||||
}
|
||||
|
||||
if (opts::isSanitizerEnabled(opts::ThreadSanitizer)) {
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
||||
addThreadSanitizerPass);
|
||||
legacyAddThreadSanitizerPass);
|
||||
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
addThreadSanitizerPass);
|
||||
legacyAddThreadSanitizerPass);
|
||||
}
|
||||
|
||||
if (opts::isSanitizerEnabled(opts::CoverageSanitizer)) {
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
||||
addSanitizerCoveragePass);
|
||||
legacyAddSanitizerCoveragePass);
|
||||
builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
addSanitizerCoveragePass);
|
||||
legacyAddSanitizerCoveragePass);
|
||||
}
|
||||
|
||||
if (!disableLangSpecificPasses) {
|
||||
if (!disableSimplifyDruntimeCalls) {
|
||||
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd,
|
||||
addSimplifyDRuntimeCallsPass);
|
||||
legacyAddSimplifyDRuntimeCallsPass);
|
||||
}
|
||||
|
||||
if (!disableGCToStack) {
|
||||
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd,
|
||||
addGarbageCollect2StackPass);
|
||||
legacyAddGarbageCollect2StackPass);
|
||||
}
|
||||
}
|
||||
|
||||
// EP_OptimizerLast does not exist in LLVM 3.0, add it manually below.
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
||||
addStripExternalsPass);
|
||||
legacyAddStripExternalsPass);
|
||||
|
||||
addPGOPasses(builder, mpm, optLevel);
|
||||
legacyAddPGOPasses(builder, mpm, optLevel);
|
||||
|
||||
builder.populateFunctionPassManager(fpm);
|
||||
builder.populateModulePassManager(mpm);
|
||||
|
@ -389,7 +389,7 @@ bool ldc_optimize_module(llvm::Module *M) {
|
|||
mpm.add(createStripSymbolsPass(true));
|
||||
}
|
||||
|
||||
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
||||
legacyAddOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
||||
|
||||
if (global.params.dllimport != DLLImport::none) {
|
||||
mpm.add(createDLLImportRelocationPass());
|
||||
|
|
|
@ -188,18 +188,23 @@ private:
|
|||
IRBuilder<> b(&ctor->back());
|
||||
|
||||
Value *address = currentGlobal;
|
||||
Type * t = currentGlobal->getValueType();
|
||||
for (auto i : currentGepPath) {
|
||||
auto t = address->getType()->getPointerElementType();
|
||||
if (i <= 0xFFFFFFFFu) {
|
||||
address = b.CreateConstInBoundsGEP2_32(t, address, 0,
|
||||
static_cast<unsigned>(i));
|
||||
} else {
|
||||
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;
|
||||
auto t = address->getType()->getPointerElementType();
|
||||
if (auto gep = isGEP(skipOverCast(originalInitializer))) {
|
||||
Constant *newOperand =
|
||||
createConstPointerCast(importedVar, gep->getOperand(0)->getType());
|
||||
|
|
|
@ -60,7 +60,7 @@ struct Analysis {
|
|||
CallGraph *CG;
|
||||
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 {
|
||||
public:
|
||||
unsigned TypeInfoArgNr;
|
||||
|
||||
public:
|
||||
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
|
||||
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
|
||||
|
||||
bool analyze(LLCallBasePtr CB, const Analysis &A) override {
|
||||
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
|
||||
Ty = A.getTypeFor(TypeInfo);
|
||||
Ty = A.getTypeFor(TypeInfo, 0);
|
||||
if (!Ty) {
|
||||
return false;
|
||||
}
|
||||
|
@ -190,14 +190,8 @@ public:
|
|||
}
|
||||
|
||||
arrSize = CB->getArgOperand(ArrSizeArgNr);
|
||||
|
||||
// Extract the element type from the array type.
|
||||
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();
|
||||
|
||||
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
|
||||
Ty = A.getTypeFor(TypeInfo, 1);
|
||||
// If the user explicitly disabled the limits, don't even check
|
||||
// whether the element count fits in 32 bits. This could cause
|
||||
// miscompilations for humongous arrays, but as the value "range"
|
||||
|
@ -551,7 +545,7 @@ bool GarbageCollect2Stack::run(Function &F, DominatorTree &DT, CallGraphWrapperP
|
|||
return Changed;
|
||||
}
|
||||
|
||||
llvm::Type *Analysis::getTypeFor(Value *typeinfo) const {
|
||||
llvm::Type *Analysis::getTypeFor(Value *typeinfo, unsigned OperandNo) const {
|
||||
GlobalVariable *ti_global =
|
||||
dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts());
|
||||
if (!ti_global) {
|
||||
|
@ -561,11 +555,11 @@ llvm::Type *Analysis::getTypeFor(Value *typeinfo) const {
|
|||
const auto metaname = getMetadataName(TD_PREFIX, ti_global);
|
||||
|
||||
NamedMDNode *meta = M.getNamedMetadata(metaname);
|
||||
if (!meta || meta->getNumOperands() != 1) {
|
||||
if (!meta || (meta->getNumOperands() != 1 && meta->getNumOperands() != 2) ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MDNode *node = meta->getOperand(0);
|
||||
MDNode *node = meta->getOperand(OperandNo);
|
||||
return llvm::cast<llvm::ConstantAsMetadata>(node->getOperand(0))->getType();
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ public:
|
|||
if (returnValue->getType() != funcType->getReturnType() &&
|
||||
DtoIsInMemoryOnly(rt) && isaPointer(returnValue)) {
|
||||
Logger::println("Loading value for return");
|
||||
returnValue = DtoLoad(returnValue);
|
||||
returnValue = DtoLoad(funcType->getReturnType(), returnValue);
|
||||
}
|
||||
|
||||
// can happen for classes
|
||||
|
@ -313,7 +313,8 @@ public:
|
|||
irs->DBuilder.EmitStopPoint(fd->endloc);
|
||||
}
|
||||
|
||||
irs->ir->CreateRet(useRetValSlot ? DtoLoad(funcGen.retValSlot)
|
||||
irs->ir->CreateRet(
|
||||
useRetValSlot ? DtoLoad(funcType->getReturnType(), funcGen.retValSlot)
|
||||
: returnValue);
|
||||
} else {
|
||||
irs->ir->CreateRetVoid();
|
||||
|
@ -1345,7 +1346,7 @@ public:
|
|||
irs->ir->SetInsertPoint(condbb);
|
||||
|
||||
LLValue *done = nullptr;
|
||||
LLValue *load = DtoLoad(keyvar);
|
||||
LLValue *load = DtoLoad(keytype, keyvar);
|
||||
if (stmt->op == TOK::foreach_) {
|
||||
done = irs->ir->CreateICmpULT(load, niters);
|
||||
} else if (stmt->op == TOK::foreach_reverse_) {
|
||||
|
@ -1365,8 +1366,8 @@ public:
|
|||
PGO.emitCounterIncrement(stmt);
|
||||
|
||||
// get value for this iteration
|
||||
LLValue *loadedKey = DtoLoad(keyvar);
|
||||
LLValue *gep = DtoGEP1(val, loadedKey);
|
||||
LLValue *loadedKey = DtoLoad(keytype, keyvar);
|
||||
LLValue *gep = DtoGEP1(DtoMemType(aggrval->type->nextOf()), val, loadedKey);
|
||||
|
||||
if (!stmt->value->isRef() && !stmt->value->isOut()) {
|
||||
// Copy value to local variable, and use it as the value variable.
|
||||
|
@ -1393,7 +1394,7 @@ public:
|
|||
// next
|
||||
irs->ir->SetInsertPoint(nextbb);
|
||||
if (stmt->op == TOK::foreach_) {
|
||||
LLValue *load = DtoLoad(keyvar);
|
||||
LLValue *load = DtoLoad(keytype, keyvar);
|
||||
load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false));
|
||||
DtoStore(load, keyvar);
|
||||
}
|
||||
|
@ -1428,7 +1429,7 @@ public:
|
|||
// handle key
|
||||
assert(stmt->key->type->isintegral());
|
||||
LLValue *keyval = DtoRawVarDeclaration(stmt->key);
|
||||
|
||||
LLType *keytype = DtoType(stmt->key->type);
|
||||
// store initial value in key
|
||||
if (stmt->op == TOK::foreach_) {
|
||||
DtoStore(lower, keyval);
|
||||
|
@ -1449,7 +1450,7 @@ public:
|
|||
irs->ir->SetInsertPoint(condbb);
|
||||
|
||||
// first we test that lwr < upr
|
||||
lower = DtoLoad(keyval);
|
||||
lower = DtoLoad(keytype, keyval);
|
||||
assert(lower->getType() == upper->getType());
|
||||
llvm::ICmpInst::Predicate cmpop;
|
||||
if (isLLVMUnsigned(stmt->key->type)) {
|
||||
|
@ -1475,7 +1476,7 @@ public:
|
|||
|
||||
// reverse foreach decrements here
|
||||
if (stmt->op == TOK::foreach_reverse_) {
|
||||
LLValue *v = DtoLoad(keyval);
|
||||
LLValue *v = DtoLoad(keytype, keyval);
|
||||
LLValue *one = LLConstantInt::get(v->getType(), 1, false);
|
||||
v = irs->ir->CreateSub(v, one);
|
||||
DtoStore(v, keyval);
|
||||
|
@ -1498,7 +1499,7 @@ public:
|
|||
|
||||
// forward foreach increments here
|
||||
if (stmt->op == TOK::foreach_) {
|
||||
LLValue *v = DtoLoad(keyval);
|
||||
LLValue *v = DtoLoad(keytype, keyval);
|
||||
LLValue *one = LLConstantInt::get(v->getType(), 1, false);
|
||||
v = irs->ir->CreateAdd(v, one);
|
||||
DtoStore(v, keyval);
|
||||
|
|
|
@ -145,7 +145,7 @@ LLValue *DtoUnpaddedStruct(Type *dty, LLValue *v) {
|
|||
LLValue *newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty));
|
||||
|
||||
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;
|
||||
if (fields[i]->type->ty == TY::Tstruct) {
|
||||
// Nested structs are the only members that can contain padding
|
||||
|
@ -153,7 +153,7 @@ LLValue *DtoUnpaddedStruct(Type *dty, LLValue *v) {
|
|||
} else {
|
||||
assert(!fields[i]->isBitFieldDeclaration());
|
||||
fieldptr = DtoBitCast(fieldptr, DtoPtrToType(fields[i]->type));
|
||||
fieldval = DtoLoad(fieldptr);
|
||||
fieldval = DtoLoad(DtoType(fields[i]->type), fieldptr);
|
||||
}
|
||||
newval = DtoInsertValue(newval, fieldval, i);
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ void DtoPaddedStruct(Type *dty, LLValue *v, LLValue *lval) {
|
|||
VarDeclarations &fields = sty->sym->fields;
|
||||
|
||||
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);
|
||||
if (fields[i]->type->ty == TY::Tstruct) {
|
||||
// Nested structs are the only members that can contain padding
|
||||
|
|
117
gen/tocall.cpp
117
gen/tocall.cpp
|
@ -24,6 +24,7 @@
|
|||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/nested.h"
|
||||
#include "gen/mangling.h"
|
||||
#include "gen/pragma.h"
|
||||
#include "gen/tollvm.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,
|
||||
IrFuncTy &irFty, LLFunctionType *calleeType,
|
||||
Expressions &argexps,
|
||||
|
@ -212,7 +178,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
|
|||
((!isVararg && !isaPointer(paramType)) ||
|
||||
(isVararg && !irArg->byref && !irArg->isByVal()))) {
|
||||
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
|
||||
|
@ -286,7 +252,7 @@ static LLValue *getTypeinfoArrayArgumentForDVarArg(Expressions *argexps,
|
|||
gIR->module, tiarrty, true, llvm::GlobalValue::InternalLinkage, tiinits,
|
||||
"._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,
|
||||
DValue *&result) {
|
||||
// va_start instruction
|
||||
|
@ -422,9 +401,10 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
if (pointeeType->isIntegerTy()) {
|
||||
val = DtoRVal(dval);
|
||||
} else if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
|
||||
LLType *atype = getAtomicType(pointeeType);
|
||||
ptr = DtoBitCast(ptr, intPtrType);
|
||||
auto lval = makeLValue(exp1->loc, dval);
|
||||
val = DtoLoad(DtoBitCast(lval, intPtrType));
|
||||
val = DtoLoad(atype, DtoBitCast(lval, intPtrType));
|
||||
} else {
|
||||
e->error(
|
||||
"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();
|
||||
|
||||
LLValue *ptr = DtoRVal(exp);
|
||||
LLType *pointeeType = getPointeeType(ptr);
|
||||
LLType *pointeeType = DtoType(e->type);
|
||||
LLType *loadedType = pointeeType;
|
||||
Type *retType = exp->type->nextOf();
|
||||
|
||||
if (!pointeeType->isIntegerTy()) {
|
||||
if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
|
||||
ptr = DtoBitCast(ptr, intPtrType);
|
||||
loadedType = getAtomicType(pointeeType);
|
||||
} else {
|
||||
e->error("atomic load only supports types of size 1/2/4/8/16 bytes, "
|
||||
"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);
|
||||
if (auto alignment = getTypeAllocSize(loadedType)) {
|
||||
load->setAlignment(LLAlign(alignment));
|
||||
|
@ -511,11 +492,12 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
cmp = DtoRVal(dcmp);
|
||||
val = DtoRVal(dval);
|
||||
} else if (auto intPtrType = getPtrToAtomicType(pointeeType)) {
|
||||
LLType *atype = getAtomicType(pointeeType);
|
||||
ptr = DtoBitCast(ptr, intPtrType);
|
||||
auto cmpLVal = makeLValue(exp2->loc, dcmp);
|
||||
cmp = DtoLoad(DtoBitCast(cmpLVal, intPtrType));
|
||||
cmp = DtoLoad(atype, DtoBitCast(cmpLVal, intPtrType));
|
||||
auto lval = makeLValue(exp3->loc, dval);
|
||||
val = DtoLoad(DtoBitCast(lval, intPtrType));
|
||||
val = DtoLoad(atype, DtoBitCast(lval, intPtrType));
|
||||
} else {
|
||||
e->error(
|
||||
"`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
|
||||
// because of i1)
|
||||
auto mem = DtoAlloca(e->type);
|
||||
llvm::Type* memty = DtoType(e->type);
|
||||
DtoStore(p->ir->CreateExtractValue(ret, 0),
|
||||
DtoBitCast(DtoGEP(mem, 0u, 0), ptr->getType()));
|
||||
DtoStoreZextI8(p->ir->CreateExtractValue(ret, 1), DtoGEP(mem, 0, 1));
|
||||
DtoBitCast(DtoGEP(memty, mem, 0u, 0), ptr->getType()));
|
||||
DtoStoreZextI8(p->ir->CreateExtractValue(ret, 1), DtoGEP(memty, mem, 0, 1));
|
||||
|
||||
result = new DLValue(e->type, mem);
|
||||
return true;
|
||||
|
@ -600,7 +583,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
assert(bitmask == 31 || bitmask == 63);
|
||||
// auto q = cast(size_t*)ptr + (bitnum >> (64bit ? 6 : 5));
|
||||
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);
|
||||
LLValue *mask =
|
||||
|
@ -609,7 +592,7 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
|||
|
||||
// auto result = (*q & mask) ? -1 : 0;
|
||||
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");
|
||||
ret = p->ir->CreateICmpNE(ret, DtoConstSize_t(0), "bitop.tmp");
|
||||
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];
|
||||
LLValue *ptr = DtoRVal(exp1);
|
||||
result = new DImValue(e->type, DtoVolatileLoad(ptr));
|
||||
result = new DImValue(e->type, DtoVolatileLoad(DtoType(e->type), ptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -769,7 +752,7 @@ private:
|
|||
// class pointer
|
||||
Type *thistype = gIR->func()->decl->vthis->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));
|
||||
}
|
||||
}
|
||||
|
@ -784,7 +767,7 @@ private:
|
|||
// ... or a delegate context arg
|
||||
LLValue *ctxarg;
|
||||
if (fnval->isLVal()) {
|
||||
ctxarg = DtoLoad(DtoGEP(DtoLVal(fnval), 0u, 0), ".ptr");
|
||||
ctxarg = DtoLoad(getVoidPtrType(), DtoGEP(DtoType(fnval->type), DtoLVal(fnval), 0u, 0), ".ptr");
|
||||
} else {
|
||||
ctxarg = gIR->ir->CreateExtractValue(DtoRVal(fnval), 0, ".ptr");
|
||||
}
|
||||
|
@ -816,7 +799,8 @@ private:
|
|||
const auto selector = dfnval->func->objc.selector;
|
||||
assert(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 !
|
||||
DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
|
||||
Expressions *arguments, LLValue *sretPointer) {
|
||||
|
@ -860,10 +864,15 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
|
|||
}
|
||||
|
||||
// get callee llvm value
|
||||
LLValue *callable = DtoCallableValue(fnval);
|
||||
LLFunctionType *const callableTy =
|
||||
DtoExtractFunctionType(callable->getType());
|
||||
assert(callableTy);
|
||||
LLValue *callable = DtoCallableValue(irFty.funcType, fnval);
|
||||
LLFunctionType *callableTy = irFty.funcType;
|
||||
if (dfnval && dfnval->func->isCsymbol()) {
|
||||
// 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';
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ public:
|
|||
}
|
||||
|
||||
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) {
|
||||
result = DtoBitCast(arrptr, DtoType(t));
|
||||
|
@ -196,7 +196,7 @@ public:
|
|||
if (t1b->ty == TY::Tpointer && e->e2->type->isintegral()) {
|
||||
llvm::Constant *ptr = toConstElem(e->e1, p);
|
||||
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));
|
||||
return;
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ public:
|
|||
dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger());
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -284,14 +284,15 @@ public:
|
|||
static_cast<VarExp *>(e->e1)->var->isVarDeclaration();
|
||||
assert(vd);
|
||||
DtoResolveVariable(vd);
|
||||
IrGlobal *irg = getIrGlobal(vd);
|
||||
LLConstant *value =
|
||||
isIrGlobalCreated(vd) ? isaConstant(getIrGlobal(vd)->value) : nullptr;
|
||||
isIrGlobalCreated(vd) ? isaConstant(irg->value) : nullptr;
|
||||
if (!value) {
|
||||
goto Lerr;
|
||||
}
|
||||
Type *type = vd->type->toBasetype();
|
||||
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));
|
||||
} else if (tb->ty == TY::Tclass && e->e1->type->ty == TY::Tclass &&
|
||||
|
@ -309,7 +310,7 @@ public:
|
|||
assert(i_index != ~0UL);
|
||||
|
||||
// offset pointer
|
||||
instance = DtoGEP(instance, 0, i_index);
|
||||
instance = DtoGEP(DtoType(e->e1->type), instance, 0, i_index);
|
||||
}
|
||||
result = DtoBitCast(instance, DtoType(tb));
|
||||
} else {
|
||||
|
@ -350,7 +351,7 @@ public:
|
|||
if (elemSize && e->offset % elemSize == 0) {
|
||||
// We can turn this into a "nice" GEP.
|
||||
result = llvm::ConstantExpr::getGetElementPtr(
|
||||
getPointeeType(base), base, DtoConstSize_t(e->offset / elemSize));
|
||||
DtoType(e->var->type), base, DtoConstSize_t(e->offset / elemSize));
|
||||
} else {
|
||||
// Offset isn't a multiple of base type size, just cast to i8* and
|
||||
// apply the byte offset.
|
||||
|
@ -400,7 +401,7 @@ public:
|
|||
LLConstant *val = isaConstant(getIrGlobal(vd)->value);
|
||||
val = DtoBitCast(val, DtoType(vd->type->pointerTo()));
|
||||
LLConstant *gep = llvm::ConstantExpr::getGetElementPtr(
|
||||
getPointeeType(val), val, idxs, true);
|
||||
DtoType(vd->type), val, idxs, true);
|
||||
|
||||
// bitcast to requested type
|
||||
assert(e->type->toBasetype()->ty == TY::Tpointer);
|
||||
|
@ -527,7 +528,7 @@ public:
|
|||
|
||||
// build a constant dynamic array reference with the .ptr field pointing
|
||||
// into store
|
||||
LLConstant *globalstorePtr = DtoGEP(store, 0u, 0u);
|
||||
LLConstant *globalstorePtr = DtoGEP(arrtype, store, 0u, 0u);
|
||||
result = DtoConstSlice(DtoConstSize_t(e->elements->length), globalstorePtr);
|
||||
}
|
||||
|
||||
|
@ -634,13 +635,13 @@ public:
|
|||
if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) {
|
||||
assert(it->isBaseOf(origClass, NULL));
|
||||
|
||||
IrTypeClass *itc = getIrType(origClass->type)->isClass();
|
||||
// find interface impl
|
||||
size_t i_index =
|
||||
getIrType(origClass->type)->isClass()->getInterfaceIndex(it);
|
||||
size_t i_index = itc->getInterfaceIndex(it);
|
||||
assert(i_index != ~0UL);
|
||||
|
||||
// offset pointer
|
||||
result = DtoGEP(result, 0, i_index);
|
||||
result = DtoGEP(itc->getMemoryLLType(), result, 0, i_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
96
gen/toir.cpp
96
gen/toir.cpp
|
@ -65,7 +65,7 @@ bool walkPostorder(Expression *e, StoppableVisitor *v);
|
|||
|
||||
static LLValue *write_zeroes(LLValue *mem, unsigned start, unsigned end) {
|
||||
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));
|
||||
return mem;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
|||
LOG_SCOPE
|
||||
|
||||
// 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
|
||||
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);
|
||||
LOG_SCOPE
|
||||
|
||||
// get a pointer to this field
|
||||
const auto ptr = DtoIndexAggregate(mem, sd, vd);
|
||||
DLValue field(vd->type, DtoBitCast(ptr, DtoPtrToType(vd->type)));
|
||||
const auto field = DtoIndexAggregate(mem, sd, vd);
|
||||
|
||||
// initialize the field
|
||||
if (expr) {
|
||||
IF_LOG Logger::println("expr = %s", expr->toChars());
|
||||
// try to construct it in-place
|
||||
if (!toInPlaceConstruction(&field, expr)) {
|
||||
DtoAssign(loc, &field, toElem(expr), EXP::blit);
|
||||
if (!toInPlaceConstruction(field, expr)) {
|
||||
DtoAssign(loc, field, toElem(expr), EXP::blit);
|
||||
if (expr->isLvalue())
|
||||
callPostblit(loc, expr, DtoLVal(&field));
|
||||
callPostblit(loc, expr, DtoLVal(field));
|
||||
}
|
||||
} else {
|
||||
assert(vd == sd->vthis);
|
||||
|
@ -191,7 +189,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
|||
LOG_SCOPE
|
||||
DImValue val(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
|
||||
|
@ -419,7 +417,7 @@ public:
|
|||
Type *dtype = e->type->toBasetype();
|
||||
|
||||
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) {
|
||||
LLConstant *clen =
|
||||
|
@ -850,7 +848,7 @@ public:
|
|||
uint64_t elemSize = gDataLayout->getTypeAllocSize(elemType);
|
||||
if (e->offset % elemSize == 0) {
|
||||
// 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
|
||||
// apply the byte offset.
|
||||
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.");
|
||||
}
|
||||
|
||||
LLValue *ptr = DtoIndexAggregate(aggrPtr, ad, vd);
|
||||
auto ptr = DtoLVal(DtoIndexAggregate(aggrPtr, ad, vd));
|
||||
|
||||
// special case for bit fields (no real lvalues)
|
||||
if (auto bf = vd->isBitFieldDeclaration()) {
|
||||
|
@ -1093,17 +1092,19 @@ public:
|
|||
|
||||
LLValue *arrptr = nullptr;
|
||||
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) {
|
||||
if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) {
|
||||
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) {
|
||||
if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) {
|
||||
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) {
|
||||
result = DtoAAIndex(e->loc, e->type, l, r, e->modifiable);
|
||||
return;
|
||||
|
@ -1192,7 +1193,7 @@ public:
|
|||
}
|
||||
|
||||
// offset by lower
|
||||
eptr = DtoGEP1(getBasePointer(), vlo, "lowerbound");
|
||||
eptr = DtoGEP1(DtoMemType(etype->nextOf()), getBasePointer(), vlo, "lowerbound");
|
||||
|
||||
// adjust length
|
||||
elen = p->ir->CreateSub(vup, vlo);
|
||||
|
@ -1415,7 +1416,7 @@ public:
|
|||
LLValue *const lval = DtoLVal(dv);
|
||||
toElem(e->e2);
|
||||
|
||||
LLValue *val = DtoLoad(lval);
|
||||
LLValue *val = DtoLoad(DtoType(dv->type), lval);
|
||||
LLValue *post = nullptr;
|
||||
|
||||
Type *e1type = e->e1->type->toBasetype();
|
||||
|
@ -1434,7 +1435,7 @@ public:
|
|||
assert(e->e2->op == EXP::int64);
|
||||
LLConstant *offset =
|
||||
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()) {
|
||||
assert(e2type->iscomplex());
|
||||
LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0);
|
||||
|
@ -1445,7 +1446,7 @@ public:
|
|||
} else if (e->op == EXP::minusMinus) {
|
||||
re = llvm::BinaryOperator::CreateFSub(re, one, "", p->scopebb());
|
||||
}
|
||||
DtoComplexSet(lval, re, im);
|
||||
DtoComplexSet(DtoType(dv->type), lval, re, im);
|
||||
} else if (e1type->isfloating()) {
|
||||
assert(e2type->isfloating());
|
||||
LLValue *one = DtoConstFP(e1type, ldouble(1.0));
|
||||
|
@ -1611,7 +1612,7 @@ public:
|
|||
} else if (auto ve = e->e1->isVarExp()) {
|
||||
if (auto vd = ve->var->isVarDeclaration()) {
|
||||
if (vd->onstack()) {
|
||||
DtoFinalizeScopeClass(e->loc, DtoRVal(dval), vd->onstackWithDtor());
|
||||
DtoFinalizeScopeClass(e->loc, dval, vd->onstackWithDtor());
|
||||
onstack = true;
|
||||
}
|
||||
}
|
||||
|
@ -1628,8 +1629,8 @@ public:
|
|||
// dyn array
|
||||
else if (et->ty == TY::Tarray) {
|
||||
DtoDeleteArray(e->loc, dval);
|
||||
if (dval->isLVal()) {
|
||||
DtoSetArrayToNull(DtoLVal(dval));
|
||||
if (DLValue *ldval = dval->isLVal()) {
|
||||
DtoSetArrayToNull(ldval);
|
||||
}
|
||||
}
|
||||
// unknown/invalid
|
||||
|
@ -2266,13 +2267,13 @@ public:
|
|||
e->loc, arrayType,
|
||||
new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false);
|
||||
initializeArrayLiteral(
|
||||
p, e, DtoBitCast(dynSlice->getPtr(), getPtrToType(llStoType)));
|
||||
p, e, DtoBitCast(dynSlice->getPtr(), getPtrToType(llStoType)), llStoType);
|
||||
result = dynSlice;
|
||||
}
|
||||
} else {
|
||||
llvm::Value *storage =
|
||||
DtoRawAlloca(llStoType, DtoAlignment(e->type), "arrayliteral");
|
||||
initializeArrayLiteral(p, e, storage);
|
||||
initializeArrayLiteral(p, e, storage, llStoType);
|
||||
if (arrayType->ty == TY::Tsarray) {
|
||||
result = new DLValue(e->type, storage);
|
||||
} else if (arrayType->ty == TY::Tpointer) {
|
||||
|
@ -2453,7 +2454,7 @@ public:
|
|||
LLConstant *globalstore = new LLGlobalVariable(
|
||||
gIR->module, initval->getType(), false,
|
||||
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);
|
||||
LLValue *keysArray = DtoAggrPaint(slice, funcTy->getParamType(1));
|
||||
|
||||
|
@ -2461,7 +2462,7 @@ public:
|
|||
globalstore = new LLGlobalVariable(gIR->module, initval->getType(), false,
|
||||
LLGlobalValue::InternalLinkage,
|
||||
initval, ".aaValuesStorage");
|
||||
slice = DtoGEP(globalstore, 0u, 0u);
|
||||
slice = DtoGEP(initval->getType(), globalstore, 0u, 0u);
|
||||
slice = DtoConstSlice(DtoConstSize_t(e->keys->length), slice);
|
||||
LLValue *valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
|
||||
|
||||
|
@ -2469,7 +2470,7 @@ public:
|
|||
valuesArray, "aa");
|
||||
if (basetype->ty != TY::Taarray) {
|
||||
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);
|
||||
} else {
|
||||
result = new DImValue(e->type, aa);
|
||||
|
@ -2508,8 +2509,9 @@ public:
|
|||
|
||||
DValue *toGEP(UnaExp *exp, unsigned index) {
|
||||
// (&a.foo).funcptr is a case where toElem(e1) is genuinely not an l-value.
|
||||
LLValue *val = makeLValue(exp->loc, toElem(exp->e1));
|
||||
LLValue *v = DtoGEP(val, 0, index);
|
||||
DValue * dv = toElem(exp->e1);
|
||||
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)));
|
||||
}
|
||||
|
||||
|
@ -2565,12 +2567,12 @@ public:
|
|||
for (auto exp : *e->exps) {
|
||||
types.push_back(DtoMemType(exp->type));
|
||||
}
|
||||
LLValue *val =
|
||||
DtoRawAlloca(LLStructType::get(gIR->context(), types), 0, ".tuple");
|
||||
llvm::StructType *st = llvm::StructType::get(gIR->context(), types);
|
||||
LLValue *val = DtoRawAlloca(st, 0, ".tuple");
|
||||
for (size_t i = 0; i < e->exps->length; i++) {
|
||||
Expression *el = (*e->exps)[i];
|
||||
DValue *ep = toElem(el);
|
||||
LLValue *gep = DtoGEP(val, 0, i);
|
||||
LLValue *gep = DtoGEP(st, val, 0, i);
|
||||
if (DtoIsInMemoryOnly(el->type)) {
|
||||
DtoMemCpy(gep, DtoLVal(ep));
|
||||
} else if (el->type->ty != TY::Tvoid) {
|
||||
|
@ -2599,6 +2601,7 @@ public:
|
|||
return DtoRVal(DtoCast(e->loc, element, elementType));
|
||||
};
|
||||
|
||||
LLType *dstType = DtoType(e->type);
|
||||
Type *tsrc = e->e1->type->toBasetype();
|
||||
if (auto lit = e->e1->isArrayLiteralExp()) {
|
||||
// Optimization for array literals: check for a fully static literal and
|
||||
|
@ -2626,7 +2629,7 @@ public:
|
|||
DtoStore(vectorConstant, dstMem);
|
||||
} else {
|
||||
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) {
|
||||
|
@ -2643,16 +2646,18 @@ public:
|
|||
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();
|
||||
|
||||
if (DtoMemType(elementType) == DtoMemType(srcElementType)) {
|
||||
DtoMemCpy(dstMem, arrayPtr);
|
||||
} else {
|
||||
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);
|
||||
DtoStore(llVal, DtoGEP(dstMem, 0, i));
|
||||
DtoStore(llVal, DtoGEP(dstType, dstMem, 0, i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2673,7 +2678,7 @@ public:
|
|||
DtoStore(vectorConstant, dstMem);
|
||||
} else {
|
||||
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();
|
||||
assert(t->ty == TY::Tclass);
|
||||
|
||||
ClassDeclaration *sym = static_cast<TypeClass *>(t)->sym;
|
||||
IrClass *irc = getIrAggr(sym, true);
|
||||
LLValue *val = DtoRVal(ex);
|
||||
|
||||
// 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.
|
||||
llvm::Value *typinf = DtoGEP(vtbl, 0u, 0);
|
||||
llvm::Value *typinf = DtoGEP(vtblsym->getValueType(), vtbl, 0u, 0);
|
||||
|
||||
Type *resultType;
|
||||
if (static_cast<TypeClass *>(t)->sym->isInterfaceDeclaration()) {
|
||||
if (sym->isInterfaceDeclaration()) {
|
||||
// For interfaces, the first entry in the vtbl is actually a pointer
|
||||
// to an Interface instance, which has the type info as its first
|
||||
// member, so we have to add an extra layer of indirection.
|
||||
resultType = getInterfaceTypeInfoType();
|
||||
typinf = DtoLoad(
|
||||
DtoBitCast(typinf, DtoType(resultType->pointerTo()->pointerTo())));
|
||||
LLType *pres = DtoType(resultType->pointerTo());
|
||||
typinf = DtoLoad(pres, DtoBitCast(typinf, pres->getPointerTo()));
|
||||
} else {
|
||||
resultType = getClassInfoType();
|
||||
typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo()));
|
||||
|
@ -2867,7 +2875,7 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
|
|||
else if (auto al = rhs->isArrayLiteralExp()) {
|
||||
if (lhs->type->toBasetype()->ty == TY::Tsarray) {
|
||||
Logger::println("success, in-place-constructing array literal");
|
||||
initializeArrayLiteral(gIR, al, DtoLVal(lhs));
|
||||
initializeArrayLiteral(gIR, al, DtoLVal(lhs), DtoMemType(lhs->type));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,47 +345,42 @@ LLIntegerType *DtoSize_t() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLType *getPointeeType(LLValue *pointer) {
|
||||
return pointer->getType()->getPointerElementType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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) {
|
||||
auto gep = llvm::GetElementPtrInst::Create(getPointeeType(ptr), ptr, indices,
|
||||
auto gep = llvm::GetElementPtrInst::Create(type, ptr, indices,
|
||||
name, bb ? bb : gIR->scopebb());
|
||||
gep->setIsInBounds(true);
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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)};
|
||||
return llvm::ConstantExpr::getGetElementPtr(getPointeeType(ptr), ptr, indices,
|
||||
return llvm::ConstantExpr::getGetElementPtr(ptrty, ptr, indices,
|
||||
/* InBounds = */ true);
|
||||
}
|
||||
|
||||
|
@ -491,7 +486,7 @@ LLConstant *DtoConstFP(Type *t, const real_t value) {
|
|||
LLConstant *DtoConstCString(const char *str) {
|
||||
llvm::StringRef s(str ? str : "");
|
||||
LLGlobalVariable *gvar = gIR->getCachedStringLiteral(s);
|
||||
return DtoGEP(gvar, 0u, 0u);
|
||||
return DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
|
||||
}
|
||||
|
||||
LLConstant *DtoConstString(const char *str) {
|
||||
|
@ -503,27 +498,31 @@ LLConstant *DtoConstString(const char *str) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
llvm::LoadInst *DtoLoadImpl(LLValue *src, const char *name) {
|
||||
return gIR->ir->CreateLoad(getPointeeType(src), src, name);
|
||||
llvm::LoadInst *DtoLoadImpl(LLType *type, LLValue *src, const char *name) {
|
||||
return gIR->ir->CreateLoad(type, src, name);
|
||||
}
|
||||
}
|
||||
|
||||
LLValue *DtoLoad(LLValue *src, const char *name) {
|
||||
return DtoLoadImpl(src, name);
|
||||
LLValue *DtoLoad(LLType* type, LLValue *src, const char *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
|
||||
// the type.
|
||||
LLValue *DtoAlignedLoad(LLValue *src, const char *name) {
|
||||
llvm::LoadInst *ld = DtoLoadImpl(src, name);
|
||||
LLValue *DtoAlignedLoad(LLType *type, LLValue *src, const char *name) {
|
||||
llvm::LoadInst *ld = DtoLoadImpl(type, src, name);
|
||||
if (auto alignment = getABITypeAlign(ld->getType())) {
|
||||
ld->setAlignment(LLAlign(alignment));
|
||||
}
|
||||
return ld;
|
||||
}
|
||||
|
||||
LLValue *DtoVolatileLoad(LLValue *src, const char *name) {
|
||||
llvm::LoadInst *ld = DtoLoadImpl(src, name);
|
||||
LLValue *DtoVolatileLoad(LLType *type, LLValue *src, const char *name) {
|
||||
llvm::LoadInst *ld = DtoLoadImpl(type, src, name);
|
||||
ld->setVolatile(true);
|
||||
return ld;
|
||||
}
|
||||
|
@ -568,6 +567,26 @@ LLType *stripAddrSpaces(LLType *t)
|
|||
if(gIR->dcomputetarget == nullptr)
|
||||
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;
|
||||
while (t->isPointerTy()) {
|
||||
indirections++;
|
||||
|
@ -577,6 +596,7 @@ LLType *stripAddrSpaces(LLType *t)
|
|||
t = t->getPointerTo(0);
|
||||
|
||||
return t;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name) {
|
||||
|
|
21
gen/tollvm.h
21
gen/tollvm.h
|
@ -82,20 +82,17 @@ void setVisibility(Dsymbol *sym, llvm::GlobalObject *obj);
|
|||
LLIntegerType *DtoSize_t();
|
||||
LLStructType *DtoModuleReferenceType();
|
||||
|
||||
// Returns the pointee type of the specified pointer value.
|
||||
LLType *getPointeeType(LLValue *pointer);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
LLValue *DtoGEP1(LLValue *ptr, unsigned i0, const char *name = "",
|
||||
LLValue *DtoGEP1(LLType * ptrty, LLValue *ptr, unsigned i0, const char *name = "",
|
||||
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);
|
||||
LLConstant *DtoGEP(LLConstant *ptr, unsigned i0, unsigned i1);
|
||||
LLConstant *DtoGEP(LLType * ptrty, LLConstant *ptr, unsigned i0, unsigned i1);
|
||||
|
||||
// to constant helpers
|
||||
LLConstantInt *DtoConstSize_t(uint64_t);
|
||||
|
@ -109,9 +106,11 @@ LLConstant *DtoConstString(const char *);
|
|||
LLConstant *DtoConstBool(bool);
|
||||
|
||||
// llvm wrappers
|
||||
LLValue *DtoLoad(LLValue *src, const char *name = "");
|
||||
LLValue *DtoVolatileLoad(LLValue *src, const char *name = "");
|
||||
LLValue *DtoAlignedLoad(LLValue *src, const char *name = "");
|
||||
class DLValue;
|
||||
LLValue *DtoLoad(DLValue *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 DtoVolatileStore(LLValue *src, LLValue *dst);
|
||||
void DtoStoreZextI8(LLValue *src, LLValue *dst);
|
||||
|
|
|
@ -83,7 +83,7 @@ void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
|
|||
const auto enterCatchFn = getRuntimeFunction(
|
||||
c->loc, irs.module,
|
||||
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);
|
||||
|
||||
// For catches that use the Throwable object, create storage for it.
|
||||
|
@ -255,7 +255,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
|
|||
|
||||
if (cpyObj) {
|
||||
// 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);
|
||||
exnObj = cpyObj;
|
||||
}
|
||||
|
@ -778,7 +778,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
|
|||
irs.ir->SetInsertPoint(resumeUnwindBlock);
|
||||
|
||||
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->SetInsertPoint(oldBB);
|
||||
|
|
|
@ -93,6 +93,11 @@ void emitTypeInfoMetadata(LLGlobalVariable *typeinfoGlobal, Type *forType) {
|
|||
auto val = llvm::UndefValue::get(DtoType(forType));
|
||||
meta->addOperand(llvm::MDNode::get(gIR->context(),
|
||||
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 "
|
||||
"built-in TypeInfo");
|
||||
} 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
|
||||
// immutable on the D side, and e.g. synchronized() can be used on the
|
||||
// implicit monitor.
|
||||
|
|
|
@ -61,6 +61,9 @@ public:
|
|||
llvm::Constant *getInitSymbol(bool define = false);
|
||||
/// Builds the __initZ initializer constant lazily.
|
||||
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
|
||||
/// `-betterC`, no `object.TypeInfo`, or `pragma(LDC_no_typeinfo)`.
|
||||
|
@ -99,8 +102,6 @@ protected:
|
|||
private:
|
||||
llvm::StructType *llStructType = nullptr;
|
||||
|
||||
llvm::StructType *getLLStructType();
|
||||
|
||||
/// Recursively adds all the initializers for the given aggregate and, in
|
||||
/// case of a class type, all its base classes.
|
||||
void addFieldInitializers(llvm::SmallVectorImpl<llvm::Constant *> &constants,
|
||||
|
|
|
@ -110,8 +110,7 @@ LLGlobalVariable *IrClass::getClassInfoSymbol(bool define) {
|
|||
emitTypeInfoMetadata(typeInfo, aggrdecl->type);
|
||||
|
||||
// Gather information
|
||||
LLType *type = DtoType(aggrdecl->type);
|
||||
LLType *bodyType = type->getPointerElementType();
|
||||
LLType *bodyType = getLLStructType();
|
||||
bool hasDestructor = (aggrdecl->dtor != nullptr);
|
||||
// Construct the fields
|
||||
llvm::Metadata *mdVals[CD_NumFields];
|
||||
|
@ -512,7 +511,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
|
|||
|
||||
llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol();
|
||||
llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr(
|
||||
getPointeeType(interfaceInfosZ), interfaceInfosZ, idxs, true);
|
||||
interfaceInfosZ->getValueType(), interfaceInfosZ, idxs, true);
|
||||
|
||||
constants.push_back(DtoBitCast(c, voidPtrTy));
|
||||
} else {
|
||||
|
@ -626,7 +625,7 @@ LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
|
|||
LLValue *&thisArg = args[thisArgIndex];
|
||||
LLType *targetThisType = thisArg->getType();
|
||||
thisArg = DtoBitCast(thisArg, getVoidPtrType());
|
||||
thisArg = DtoGEP1(thisArg, DtoConstInt(-thunkOffset));
|
||||
thisArg = DtoGEP1(LLType::getInt8Ty(gIR->context()), thisArg, DtoConstInt(-thunkOffset));
|
||||
thisArg = DtoBitCast(thisArg, targetThisType);
|
||||
|
||||
// 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),
|
||||
DtoConstSize_t(n - cd->vtblInterfaces->length)};
|
||||
|
||||
LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr(getPointeeType(ciarr),
|
||||
LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr(ciarr->getValueType(),
|
||||
ciarr, idxs, true);
|
||||
|
||||
// return as a slice
|
||||
|
|
|
@ -273,18 +273,17 @@ IrTypeAggr::IrTypeAggr(AggregateDeclaration *ad)
|
|||
LLStructType::create(gIR->context(), ad->toPrettyChars())),
|
||||
aggr(ad) {}
|
||||
|
||||
void IrTypeAggr::getMemberLocation(VarDeclaration *var, unsigned &fieldIndex,
|
||||
unsigned &byteOffset) const {
|
||||
unsigned IrTypeAggr::getMemberLocation(VarDeclaration *var, bool& isFieldIdx) const {
|
||||
// Note: The interface is a bit more general than what we actually return.
|
||||
// Specifically, the frontend offset information we use for overlapping
|
||||
// fields is always based at the object start.
|
||||
auto it = varGEPIndices.find(var);
|
||||
if (it != varGEPIndices.end()) {
|
||||
fieldIndex = it->second;
|
||||
byteOffset = 0;
|
||||
isFieldIdx = true;
|
||||
return it->second;
|
||||
} else {
|
||||
fieldIndex = 0;
|
||||
byteOffset = var->offset;
|
||||
isFieldIdx = false;
|
||||
return var->offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,8 +72,7 @@ public:
|
|||
/// 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
|
||||
/// due to overlapping (union) fields, if any.
|
||||
void getMemberLocation(VarDeclaration *var, unsigned &fieldIndex,
|
||||
unsigned &byteOffset) const;
|
||||
unsigned getMemberLocation(VarDeclaration *var, bool& isFieldIdx) const;
|
||||
|
||||
protected:
|
||||
///
|
||||
|
|
|
@ -189,7 +189,9 @@ void generateBind(const Context &context, DynamicCompilerContext &jitContext,
|
|||
assert(bindPtr != nullptr);
|
||||
assert(bindFuncs.end() == bindFuncs.find(bindPtr));
|
||||
auto funcToInline = getIrFunc(originalFunc);
|
||||
if (funcToInline != nullptr) {
|
||||
if (funcToInline == nullptr) {
|
||||
fatal(context, "Bind: function body not available");
|
||||
}
|
||||
auto exampleIrFunc = getIrFunc(exampleFunc);
|
||||
assert(exampleIrFunc != nullptr);
|
||||
auto errhandler = [&](const std::string &str) { fatal(context, str); };
|
||||
|
@ -233,9 +235,6 @@ void generateBind(const Context &context, DynamicCompilerContext &jitContext,
|
|||
errhandler, BindOverride(overrideHandler));
|
||||
moduleInfo.addBindHandle(func->getName(), bindPtr);
|
||||
bindFuncs.insert({bindPtr, func});
|
||||
} else {
|
||||
fatal(context, "Bind: function body not available");
|
||||
}
|
||||
};
|
||||
for (auto &&bind : jitContext.getBindInstances()) {
|
||||
auto bindPtr = bind.first;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue