Skip to content

Commit

Permalink
[next step: ensure no more DImValues for function ptrs and delegates]
Browse files Browse the repository at this point in the history
  • Loading branch information
kinke committed Sep 29, 2024
1 parent 6b7c533 commit 79d56f7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 25 deletions.
32 changes: 18 additions & 14 deletions gen/dvalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ DRValue::DRValue(Type *t, LLValue *v) : DValue(t, v) {
////////////////////////////////////////////////////////////////////////////////

DImValue::DImValue(Type *t, llvm::Value *v) : DRValue(t, v) {
// TODO: get rid of Tfunction exception
#ifndef NDEBUG
const auto tb = t->toBasetype();
#endif
assert(tb->ty != TY::Tarray && "use DSliceValue for dynamic arrays");
assert(!tb->isFunction_Delegate_PtrToFunction() &&
"use DFuncValue for function pointers and delegates");

// v may be an addrspace qualified pointer so strip it before doing a pointer
// equality check.
assert(t->toBasetype()->ty == TY::Tfunction ||
stripAddrSpaces(v->getType()) == DtoType(t));
assert(t->toBasetype()->ty != TY::Tarray &&
"use DSliceValue for dynamic arrays");
assert(stripAddrSpaces(v->getType()) == DtoType(t));
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -119,12 +122,7 @@ DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *funcPtr,
LLValue *vt, LLValue *vtable)
: DRValue(t, createFuncRValue(t, funcPtr, vt)), func(fd), funcPtr(funcPtr),
vthis(vt), vtable(vtable) {
#ifndef NDEBUG
const auto tb = t->toBasetype();
#endif
assert(tb->ty == TY::Tfunction || tb->ty == TY::Tdelegate ||
(tb->ty == TY::Tpointer &&
tb->nextOf()->toBasetype()->ty == TY::Tfunction));
assert(t->toBasetype()->isFunction_Delegate_PtrToFunction());
}

DFuncValue::DFuncValue(FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt,
Expand All @@ -150,8 +148,8 @@ DRValue *DLValue::getRVal() {

LLValue *rval = DtoLoad(DtoMemType(type), val);

const auto ty = type->toBasetype()->ty;
if (ty == TY::Tbool) {
const auto tb = type->toBasetype();
if (tb->ty == TY::Tbool) {
assert(rval->getType() == llvm::Type::getInt8Ty(gIR->context()));

if (isOptimizationEnabled()) {
Expand All @@ -164,8 +162,14 @@ DRValue *DLValue::getRVal() {

// truncate to i1
rval = gIR->ir->CreateTrunc(rval, llvm::Type::getInt1Ty(gIR->context()));
} else if (ty == TY::Tarray) {
} else if (tb->ty == TY::Tarray) {
return new DSliceValue(type, rval);
} else if (tb->isPtrToFunction()) {
return new DFuncValue(type, nullptr, rval);
} else if (tb->ty == TY::Tdelegate) {
const auto contextPtr = DtoExtractValue(rval, 0, ".ptr");
const auto funcPtr = DtoExtractValue(rval, 1, ".funcptr");
return new DFuncValue(type, nullptr, funcPtr, contextPtr);
}

return new DImValue(type, rval);
Expand Down
4 changes: 3 additions & 1 deletion gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,9 @@ DValue *DtoCastPtr(const Loc &loc, DValue *val, Type *to) {
fatal();
}

return new DImValue(to, rval);
return totype->isPtrToFunction()
? static_cast<DValue *>(new DFuncValue(to, nullptr, rval))
: static_cast<DValue *>(new DImValue(to, rval));
}

DValue *DtoCastFloat(const Loc &loc, DValue *val, Type *to) {
Expand Down
18 changes: 13 additions & 5 deletions gen/tocall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,8 +712,9 @@ class ImplicitArgumentsBuilder {

size_t index = args.size();

if (dfnval && (dfnval->func->ident == Id::ensure ||
dfnval->func->ident == Id::require)) {
if (dfnval && dfnval->func &&
(dfnval->func->ident == Id::ensure ||
dfnval->func->ident == Id::require)) {
// can be the this "context" argument for a contract invocation
// (pass a pointer to the aggregate `this` pointer, which can naturally be
// used as the contract's parent context in case the contract features
Expand Down Expand Up @@ -747,7 +748,7 @@ class ImplicitArgumentsBuilder {
args.push_back(ctxarg);
} else if (nestedcall) {
// ... or a nested function context arg
if (dfnval) {
if (dfnval && dfnval->func) {
LLValue *contextptr = DtoNestedContext(loc, dfnval->func);
args.push_back(contextptr);
} else {
Expand All @@ -767,6 +768,7 @@ class ImplicitArgumentsBuilder {

if (irFty.arg_objcSelector) {
assert(dfnval);
assert(dfnval->func);
const auto selector = dfnval->func->objc.selector;
assert(selector);
LLGlobalVariable *selptr = gIR->objc.getMethVarRef(*selector);
Expand Down Expand Up @@ -836,7 +838,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
// get callee llvm value
LLValue *callable = DtoCallableValue(fnval);
LLFunctionType *callableTy = irFty.funcType;
if (dfnval && dfnval->func->isCsymbol()) {
if (dfnval && dfnval->func && 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())
Expand Down Expand Up @@ -1017,7 +1019,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,
attrlist =
llvm::Intrinsic::getAttributes(gIR->context(), cf->getIntrinsicID());
}
} else if (dfnval) {
} else if (dfnval && dfnval->func) {
call->setCallingConv(getCallingConvention(dfnval->func));
} else {
call->setCallingConv(gABI->callingConv(tf, iab.hasContext));
Expand All @@ -1044,6 +1046,12 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval,

if (rbase->ty == TY::Tarray) {
return new DSliceValue(resulttype, retllval);
} else if (rbase->isPtrToFunction()) {
return new DFuncValue(resulttype, nullptr, retllval);
} else if (rbase->ty == TY::Tdelegate) {
const auto contextPtr = DtoExtractValue(retllval, 0, ".ptr");
const auto funcPtr = DtoExtractValue(retllval, 1, ".funcptr");
return new DFuncValue(resulttype, nullptr, funcPtr, contextPtr);
}

return new DImValue(resulttype, retllval);
Expand Down
27 changes: 22 additions & 5 deletions gen/toir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,20 @@ class ToElemVisitor : public Visitor {

llvm::Value *offsetValue = nullptr;

const auto tb = e->type->toBasetype();
assert(tb->ty != TY::Tdelegate);
assert(tb->ty != TY::Tfunction);

if (e->offset == 0) {
offsetValue = baseValue;

if (tb->isPtrToFunction())
if (auto dfn = base->isFunc()) {
result = e->type == dfn->type
? dfn
: new DFuncValue(e->type, dfn->func, dfn->funcPtr);
return;
}
} else {
LLType *elemType = DtoType(base->type);
if (elemType->isSized()) {
Expand Down Expand Up @@ -912,9 +924,14 @@ class ToElemVisitor : public Visitor {
}
}

if (tb->isPtrToFunction()) {
result = new DFuncValue(e->type, nullptr, offsetValue);
return;
}

// Casts are also "optimized into" SymOffExp by the frontend.
LLValue *llVal = (e->type->toBasetype()->isintegral()
? p->ir->CreatePtrToInt(offsetValue, DtoType(e->type))
LLValue *llVal =
(tb->isintegral() ? p->ir->CreatePtrToInt(offsetValue, DtoType(e->type))
: DtoBitCast(offsetValue, DtoType(e->type)));
result = new DImValue(e->type, llVal);
}
Expand Down Expand Up @@ -993,7 +1010,7 @@ class ToElemVisitor : public Visitor {
: new DFuncValue(e->type, dfv->func, dfv->funcPtr, dfv->vthis);
} else {
// FIXME: should not reach this
result = new DImValue(e->type, DtoRVal(dv));
result = new DFuncValue(e->type, nullptr, DtoRVal(dv));
}
return;
}
Expand Down Expand Up @@ -2928,8 +2945,8 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
Logger::println("is a constructor call, checking lhs of DotVarExp");
if (toInPlaceConstruction(lhs, dve->e1)) {
Logger::println("success, calling ctor on in-place constructed lhs");
auto fnval = new DFuncValue(fd, DtoCallee(fd), DtoLVal(lhs));
DtoCallFunction(ce->loc, ce->type, fnval, ce->arguments);
auto fnval = DFuncValue(fd, DtoCallee(fd), DtoLVal(lhs));
DtoCallFunction(ce->loc, ce->type, &fnval, ce->arguments);
return true;
}
}
Expand Down

0 comments on commit 79d56f7

Please sign in to comment.