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

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

View file

@ -36,6 +36,7 @@ find_package(LLVM 9.0 REQUIRED
selectiondag support tablegen target transformutils vectorize
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}")

View file

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

View file

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

View file

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

View file

@ -52,26 +52,6 @@ LLValue *DtoSlice(Expression *e) {
////////////////////////////////////////////////////////////////////////////////
static LLValue *DtoSlicePtr(Expression *e) {
DValue *dval = toElem(e);
Loc loc;
LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context()));
Type *vt = dval->type->toBasetype();
if (vt->ty == TY::Tarray) {
return makeLValue(loc, dval);
}
bool isStaticArray = vt->ty == TY::Tsarray;
LLValue *val = isStaticArray ? DtoLVal(dval) : makeLValue(loc, dval);
LLValue *array = DtoRawAlloca(type, 0, ".array");
LLValue *len = isStaticArray ? DtoArrayLen(dval) : DtoConstSize_t(1);
DtoStore(len, DtoGEP(array, 0u, 0));
DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEP(array, 0, 1));
return array;
}
////////////////////////////////////////////////////////////////////////////////
LLStructType *DtoArrayType(Type *arrayTy) {
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);

View file

@ -53,11 +53,12 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale);
/// Initializes a chunk of memory with the contents of an array literal.
///
/// 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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -355,12 +355,12 @@ void replaceDynamicThreadLocals(llvm::Module &oldModule,
}
}
llvm::Constant *getArrayPtr(llvm::Constant *array) {
llvm::Constant *getArrayPtr(llvm::Type *type, llvm::Constant *array) {
assert(nullptr != array);
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)));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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