mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-10-15 19:47:01 +02:00
Fixed issue with internal real representation, incorrect for non x86-32 architectures.
Cleaned up CallExp::toElem, moved implementation to tocall.cpp providing a single procedure to call arbitrary D functions fairly easily.
This commit is contained in:
@@ -213,8 +213,14 @@ typedef d_uns32 d_dchar;
|
||||
#include "d-gcc-real.h"
|
||||
#else
|
||||
typedef long double real_t;
|
||||
// this should be enough
|
||||
#if defined(i386) || defined(__i386__) || defined(_WIN32) || defined(__MINGW32__)
|
||||
#define REAL_T_SIZE 12
|
||||
#define REAL_T_PAD 2
|
||||
#else
|
||||
#define REAL_T_SIZE sizeof(real_t)
|
||||
#define REAL_T_PAD 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Modify OutBuffer::writewchar to write the correct size of wchar
|
||||
|
||||
+10
-6
@@ -791,20 +791,22 @@ DValue* DtoNewClass(TypeClass* tc, NewExp* newexp)
|
||||
LLValue* mem;
|
||||
if (newexp->onstack)
|
||||
{
|
||||
mem = new llvm::AllocaInst(DtoType(tc)->getContainedType(0), "newclass_alloca", gIR->topallocapoint());
|
||||
mem = new llvm::AllocaInst(DtoType(tc)->getContainedType(0), ".newclass_alloca", gIR->topallocapoint());
|
||||
}
|
||||
// custom allocator
|
||||
else if (newexp->allocator)
|
||||
{
|
||||
DValue* res = DtoCallDFunc(newexp->allocator, newexp->newargs);
|
||||
mem = DtoBitCast(res->getRVal(), DtoType(tc), "newclass_custom");
|
||||
DtoForceDeclareDsymbol(newexp->allocator);
|
||||
DFuncValue dfn(newexp->allocator, newexp->allocator->ir.irFunc->func);
|
||||
DValue* res = DtoCallFunction(NULL, &dfn, newexp->newargs);
|
||||
mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom");
|
||||
}
|
||||
// default allocator
|
||||
else
|
||||
{
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_newclass");
|
||||
mem = gIR->CreateCallOrInvoke(fn, tc->sym->ir.irStruct->classInfo, "newclass_gc_alloc")->get();
|
||||
mem = DtoBitCast(mem, DtoType(tc), "newclass_gc");
|
||||
mem = gIR->CreateCallOrInvoke(fn, tc->sym->ir.irStruct->classInfo, ".newclass_gc_alloc")->get();
|
||||
mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc");
|
||||
}
|
||||
|
||||
// init
|
||||
@@ -848,7 +850,9 @@ DValue* DtoNewClass(TypeClass* tc, NewExp* newexp)
|
||||
if (newexp->member)
|
||||
{
|
||||
assert(newexp->arguments != NULL);
|
||||
return DtoCallDFunc(newexp->member, newexp->arguments, tc, mem);
|
||||
DtoForceDeclareDsymbol(newexp->member);
|
||||
DFuncValue dfn(newexp->member, newexp->member->ir.irFunc->func, mem);
|
||||
return DtoCallFunction(tc, &dfn, newexp->arguments);
|
||||
}
|
||||
|
||||
// return default constructed class
|
||||
|
||||
+25
-10
@@ -91,17 +91,32 @@ DValue* DtoBinRem(DValue* lhs, DValue* rhs);
|
||||
// target stuff
|
||||
void findDefaultTarget();
|
||||
|
||||
/**
|
||||
* Calls a D function (with D calling conv).
|
||||
* @param fdecl The FuncDeclaration to call
|
||||
* @param arguments The Array of ExpressionS to pass as arguments.
|
||||
* @param type Optionally the TypeClass of the 'this' arguement.
|
||||
* @param thismem Optionally the LLValue for the 'this' argument.
|
||||
* @return The function call's return value.
|
||||
*/
|
||||
DValue* DtoCallDFunc(FuncDeclaration* fdecl, Array* arguments, TypeClass* type=0, LLValue* thismem=0);
|
||||
|
||||
/// Converts any value to a boolean (llvm i1)
|
||||
LLValue* DtoBoolean(Loc& loc, DValue* dval);
|
||||
|
||||
////////////////////////////////////////////
|
||||
// gen/tocall.cpp stuff below
|
||||
////////////////////////////////////////////
|
||||
|
||||
/// convert DMD calling conv to LLVM
|
||||
unsigned DtoCallingConv(LINK l);
|
||||
|
||||
///
|
||||
TypeFunction* DtoTypeFunction(Type* type);
|
||||
|
||||
///
|
||||
DValue* DtoVaArg(Loc& loc, Type* type, Expression* valistArg);
|
||||
|
||||
///
|
||||
LLValue* DtoCallableValue(DValue* fn);
|
||||
|
||||
///
|
||||
const LLFunctionType* DtoExtractFunctionType(const LLType* type);
|
||||
|
||||
///
|
||||
void DtoBuildDVarArgList(std::vector<LLValue*>& args, llvm::PAListPtr& palist, TypeFunction* tf, Expressions* arguments, size_t argidx);
|
||||
|
||||
///
|
||||
DValue* DtoCallFunction(Type* resulttype, DValue* fnval, Expressions* arguments);
|
||||
|
||||
#endif
|
||||
|
||||
+324
-33
@@ -13,49 +13,340 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* DtoCallDFunc(FuncDeclaration* fdecl, Array* arguments, TypeClass* type, LLValue* thismem)
|
||||
TypeFunction* DtoTypeFunction(Type* type)
|
||||
{
|
||||
Logger::println("Calling function: %s", fdecl->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
TypeFunction* tf = 0;
|
||||
type = type->toBasetype();
|
||||
if (type->ty == Tfunction)
|
||||
{
|
||||
tf = (TypeFunction*)type;
|
||||
}
|
||||
else if (type->ty == Tdelegate)
|
||||
{
|
||||
assert(type->next->ty == Tfunction);
|
||||
tf = (TypeFunction*)type->next;
|
||||
}
|
||||
return tf;
|
||||
}
|
||||
|
||||
assert(fdecl);
|
||||
DtoForceDeclareDsymbol(fdecl);
|
||||
llvm::Function* fn = fdecl->ir.irFunc->func;
|
||||
TypeFunction* tf = (TypeFunction*)DtoDType(fdecl->type);
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned DtoCallingConv(LINK l)
|
||||
{
|
||||
if (l == LINKc || l == LINKcpp)
|
||||
return llvm::CallingConv::C;
|
||||
else if (l == LINKd || l == LINKdefault)
|
||||
return llvm::CallingConv::Fast;
|
||||
else if (l == LINKwindows)
|
||||
return llvm::CallingConv::X86_StdCall;
|
||||
else
|
||||
assert(0 && "Unsupported calling convention");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* DtoVaArg(Loc& loc, Type* type, Expression* valistArg)
|
||||
{
|
||||
DValue* expelem = valistArg->toElem(gIR);
|
||||
const LLType* llt = DtoType(type);
|
||||
if (DtoIsPassedByRef(type))
|
||||
llt = getPtrToType(llt);
|
||||
// issue a warning for broken va_arg instruction.
|
||||
if (global.params.cpu != ARCHx86)
|
||||
warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars());
|
||||
// done
|
||||
return new DImValue(type, gIR->ir->CreateVAArg(expelem->getLVal(), llt, "tmp"));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue* DtoCallableValue(DValue* fn)
|
||||
{
|
||||
Type* type = fn->getType()->toBasetype();
|
||||
if (type->ty == Tfunction)
|
||||
{
|
||||
return fn->getRVal();
|
||||
}
|
||||
else if (type->ty == Tdelegate)
|
||||
{
|
||||
LLValue* dg = fn->getRVal();
|
||||
LLValue* funcptr = DtoGEPi(dg, 0, 1);
|
||||
return DtoLoad(funcptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 && "not a callable type");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const LLFunctionType* DtoExtractFunctionType(const LLType* type)
|
||||
{
|
||||
if (const LLFunctionType* fty = isaFunction(type))
|
||||
return fty;
|
||||
else if (const LLPointerType* pty = isaPointer(type))
|
||||
{
|
||||
if (const LLFunctionType* fty = isaFunction(pty->getElementType()))
|
||||
return fty;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoBuildDVarArgList(std::vector<LLValue*>& args, llvm::PAListPtr& palist, TypeFunction* tf, Expressions* arguments, size_t argidx)
|
||||
{
|
||||
Logger::println("doing d-style variadic arguments");
|
||||
|
||||
std::vector<const LLType*> vtypes;
|
||||
|
||||
// number of non variadic args
|
||||
int begin = tf->parameters->dim;
|
||||
Logger::println("num non vararg params = %d", begin);
|
||||
|
||||
// build struct with argument types (non variadic args)
|
||||
for (int i=begin; i<arguments->dim; i++)
|
||||
{
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
vtypes.push_back(DtoType(argexp->type));
|
||||
size_t sz = getABITypeSize(vtypes.back());
|
||||
if (sz < PTRSIZE)
|
||||
vtypes.back() = DtoSize_t();
|
||||
}
|
||||
const LLStructType* vtype = LLStructType::get(vtypes);
|
||||
Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n';
|
||||
LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",gIR->topallocapoint());
|
||||
|
||||
// store arguments in the struct
|
||||
for (int i=begin,k=0; i<arguments->dim; i++,k++)
|
||||
{
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
if (global.params.llvmAnnotate)
|
||||
DtoAnnotation(argexp->toChars());
|
||||
LLValue* argdst = DtoGEPi(mem,0,k);
|
||||
argdst = DtoBitCast(argdst, getPtrToType(DtoType(argexp->type)));
|
||||
DtoVariadicArgument(argexp, argdst);
|
||||
}
|
||||
|
||||
// build type info array
|
||||
assert(Type::typeinfo->ir.irStruct->constInit);
|
||||
const LLType* typeinfotype = DtoType(Type::typeinfo->type);
|
||||
const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements());
|
||||
|
||||
llvm::GlobalVariable* typeinfomem =
|
||||
new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module);
|
||||
Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
|
||||
|
||||
std::vector<LLConstant*> vtypeinfos;
|
||||
for (int i=begin,k=0; i<arguments->dim; i++,k++)
|
||||
{
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
vtypeinfos.push_back(DtoTypeInfoOf(argexp->type));
|
||||
}
|
||||
|
||||
// apply initializer
|
||||
LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos);
|
||||
typeinfomem->setInitializer(tiinits);
|
||||
|
||||
// put data in d-array
|
||||
std::vector<LLConstant*> pinits;
|
||||
pinits.push_back(DtoConstSize_t(vtype->getNumElements()));
|
||||
pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
|
||||
const LLType* tiarrty = DtoType(Type::typeinfo->type->arrayOf());
|
||||
tiinits = llvm::ConstantStruct::get(pinits);
|
||||
LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty,
|
||||
true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module);
|
||||
|
||||
// specify arguments
|
||||
args.push_back(typeinfoarrayparam);
|
||||
++argidx;
|
||||
args.push_back(gIR->ir->CreateBitCast(mem, getPtrToType(LLType::Int8Ty), "tmp"));
|
||||
++argidx;
|
||||
|
||||
// pass non variadic args
|
||||
for (int i=0; i<begin; i++)
|
||||
{
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
|
||||
args.push_back(argval->getRVal());
|
||||
|
||||
if (fnarg->llvmByVal)
|
||||
palist = palist.addAttr(argidx, llvm::ParamAttr::ByVal);
|
||||
|
||||
++argidx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DValue* DtoCallFunction(Type* resulttype, DValue* fnval, Expressions* arguments)
|
||||
{
|
||||
// the callee D type
|
||||
Type* calleeType = fnval->getType();
|
||||
|
||||
// get func value if any
|
||||
DFuncValue* dfnval = fnval->isFunc();
|
||||
|
||||
// handle special va_copy / va_end intrinsics
|
||||
bool va_intrinsic = (dfnval && dfnval->func && (dfnval->func->llvmInternal == LLVMva_intrinsic));
|
||||
|
||||
// get function type info
|
||||
TypeFunction* tf = DtoTypeFunction(calleeType);
|
||||
assert(tf);
|
||||
|
||||
// misc
|
||||
bool retinptr = tf->llvmRetInPtr;
|
||||
bool usesthis = tf->llvmUsesThis;
|
||||
bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
|
||||
bool nestedcall = (dfnval && dfnval->func && dfnval->func->isNested());
|
||||
bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
|
||||
|
||||
unsigned callconv = DtoCallingConv(tf->linkage);
|
||||
|
||||
// get callee llvm value
|
||||
LLValue* callable = DtoCallableValue(fnval);
|
||||
const LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType());
|
||||
assert(callableTy);
|
||||
|
||||
// get llvm argument iterator, for types
|
||||
LLFunctionType::param_iterator argbegin = callableTy->param_begin();
|
||||
LLFunctionType::param_iterator argiter = argbegin;
|
||||
|
||||
// handle implicit arguments
|
||||
std::vector<LLValue*> args;
|
||||
|
||||
// return in hidden ptr is first
|
||||
if (retinptr)
|
||||
{
|
||||
LLValue* retvar = new llvm::AllocaInst(argiter->get()->getContainedType(0), ".rettmp", gIR->topallocapoint());
|
||||
++argiter;
|
||||
args.push_back(retvar);
|
||||
}
|
||||
|
||||
// then comes the 'this' argument
|
||||
if (dfnval && dfnval->vthis)
|
||||
{
|
||||
LLValue* thisarg = DtoBitCast(dfnval->vthis, argiter->get());
|
||||
++argiter;
|
||||
args.push_back(thisarg);
|
||||
}
|
||||
// or a delegate context arg
|
||||
else if (delegatecall)
|
||||
{
|
||||
LLValue* ctxarg = DtoLoad(DtoGEPi(fnval->getRVal(), 0,0));
|
||||
assert(ctxarg->getType() == argiter->get());
|
||||
++argiter;
|
||||
args.push_back(ctxarg);
|
||||
}
|
||||
// or a nested function context arg
|
||||
else if (nestedcall)
|
||||
{
|
||||
LLValue* contextptr = DtoNestedContext(dfnval->func->toParent2()->isFuncDeclaration());
|
||||
if (!contextptr)
|
||||
contextptr = getNullPtr(getVoidPtrType());
|
||||
else
|
||||
contextptr = DtoBitCast(contextptr, getVoidPtrType());
|
||||
++argiter;
|
||||
args.push_back(contextptr);
|
||||
}
|
||||
|
||||
// handle the rest of the arguments based on param passing style
|
||||
llvm::PAListPtr palist;
|
||||
|
||||
int thisOffset = 0;
|
||||
if (type || thismem)
|
||||
// variadic instrinsics need some custom casts
|
||||
if (va_intrinsic)
|
||||
{
|
||||
assert(type && thismem);
|
||||
thisOffset = 1;
|
||||
}
|
||||
|
||||
std::vector<LLValue*> args;
|
||||
if (thisOffset)
|
||||
args.push_back(thismem);
|
||||
for (size_t i=0; i<arguments->dim; ++i)
|
||||
{
|
||||
Expression* ex = (Expression*)arguments->data[i];
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
DValue* argval = DtoArgument(fnarg, ex);
|
||||
LLValue* a = argval->getRVal();
|
||||
const LLType* aty = fn->getFunctionType()->getParamType(i+thisOffset);
|
||||
if (a->getType() != aty)
|
||||
size_t n = arguments->dim;
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
Logger::cout() << "expected: " << *aty << '\n';
|
||||
Logger::cout() << "got: " << *a->getType() << '\n';
|
||||
a = DtoBitCast(a, aty);
|
||||
Expression* exp = (Expression*)arguments->data[i];
|
||||
DValue* expelem = exp->toElem(gIR);
|
||||
// cast to va_list*
|
||||
LLValue* val = DtoBitCast(expelem->getLVal(), getVoidPtrType());
|
||||
++argiter;
|
||||
args.push_back(val);
|
||||
}
|
||||
args.push_back(a);
|
||||
if (fnarg && fnarg->llvmByVal)
|
||||
palist = palist.addAttr(i+thisOffset+1, llvm::ParamAttr::ByVal); // return,this,args...
|
||||
}
|
||||
|
||||
CallOrInvoke* call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), "tmp");
|
||||
call->setCallingConv(DtoCallingConv(LINKd));
|
||||
// d style varargs needs a few more hidden arguments as well as special passing
|
||||
else if (dvarargs)
|
||||
{
|
||||
DtoBuildDVarArgList(args, palist, tf, arguments, argiter-argbegin+1);
|
||||
}
|
||||
|
||||
// otherwise we're looking at a normal function call
|
||||
else
|
||||
{
|
||||
Logger::println("doing normal arguments");
|
||||
for (int i=0; i<arguments->dim; i++) {
|
||||
int j = argiter-argbegin;
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
|
||||
LLValue* arg = argval->getRVal();
|
||||
if (fnarg && arg->getType() != callableTy->getParamType(j))
|
||||
arg = DtoBitCast(arg, callableTy->getParamType(j));
|
||||
if (fnarg && fnarg->llvmByVal)
|
||||
palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal);
|
||||
++argiter;
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
Logger::println("%d params passed", n);
|
||||
for (int i=0; i<args.size(); ++i) {
|
||||
assert(args[i]);
|
||||
Logger::cout() << "arg["<<i<<"] = " << *args[i] << '\n';
|
||||
}
|
||||
#endif
|
||||
|
||||
// void returns cannot not be named
|
||||
const char* varname = "";
|
||||
if (callableTy->getReturnType() != LLType::VoidTy)
|
||||
varname = "tmp";
|
||||
|
||||
//Logger::cout() << "Calling: " << *funcval << '\n';
|
||||
|
||||
// call the function
|
||||
CallOrInvoke* call = gIR->CreateCallOrInvoke(callable, args.begin(), args.end(), varname);
|
||||
|
||||
// get return value
|
||||
LLValue* retllval = (retinptr) ? args[0] : call->get();
|
||||
|
||||
// if the type of retllval is abstract, refine to concrete
|
||||
if (retllval->getType()->isAbstract())
|
||||
retllval = DtoBitCast(retllval, getPtrToType(DtoType(resulttype)), "retval");
|
||||
|
||||
// set calling convention
|
||||
if (dfnval && dfnval->func)
|
||||
{
|
||||
int li = dfnval->func->llvmInternal;
|
||||
if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic)
|
||||
{
|
||||
call->setCallingConv(callconv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
call->setCallingConv(callconv);
|
||||
}
|
||||
|
||||
// param attrs
|
||||
call->setParamAttrs(palist);
|
||||
|
||||
return new DImValue(type, call->get(), false);
|
||||
return new DImValue(resulttype, retllval, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+15
-326
@@ -851,353 +851,42 @@ DValue* ModAssignExp::toElem(IRState* p)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO: the method below could really use a cleanup/splitup
|
||||
|
||||
DValue* CallExp::toElem(IRState* p)
|
||||
{
|
||||
Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
DValue* fn = e1->toElem(p);
|
||||
// get the callee value
|
||||
DValue* fnval = e1->toElem(p);
|
||||
|
||||
TypeFunction* tf = 0;
|
||||
Type* e1type = DtoDType(e1->type);
|
||||
// get func value if any
|
||||
DFuncValue* dfnval = fnval->isFunc();
|
||||
|
||||
bool delegateCall = false;
|
||||
LINK dlink = LINKd;
|
||||
|
||||
// hidden struct return parameter handling
|
||||
bool retinptr = false;
|
||||
|
||||
// regular functions
|
||||
if (e1type->ty == Tfunction) {
|
||||
tf = (TypeFunction*)e1type;
|
||||
if (tf->llvmRetInPtr) {
|
||||
retinptr = true;
|
||||
}
|
||||
dlink = tf->linkage;
|
||||
}
|
||||
|
||||
// delegates
|
||||
else if (e1type->ty == Tdelegate) {
|
||||
Logger::println("delegateTy = %s\n", e1type->toChars());
|
||||
assert(e1type->next->ty == Tfunction);
|
||||
tf = (TypeFunction*)e1type->next;
|
||||
if (tf->llvmRetInPtr) {
|
||||
retinptr = true;
|
||||
}
|
||||
dlink = tf->linkage;
|
||||
delegateCall = true;
|
||||
}
|
||||
|
||||
// invalid
|
||||
else {
|
||||
assert(tf);
|
||||
}
|
||||
|
||||
// handling of special intrinsics
|
||||
bool va_magic = false;
|
||||
// handle magic intrinsics (mapping to instructions)
|
||||
bool va_intrinsic = false;
|
||||
DFuncValue* dfv = fn->isFunc();
|
||||
if (dfv && dfv->func) {
|
||||
FuncDeclaration* fndecl = dfv->func;
|
||||
// vararg intrinsic
|
||||
if (fndecl->llvmInternal == LLVMva_intrinsic) {
|
||||
va_magic = true;
|
||||
va_intrinsic = true;
|
||||
}
|
||||
if (dfnval && dfnval->func)
|
||||
{
|
||||
FuncDeclaration* fndecl = dfnval->func;
|
||||
// va_start instruction
|
||||
else if (fndecl->llvmInternal == LLVMva_start) {
|
||||
va_magic = true;
|
||||
if (fndecl->llvmInternal == LLVMva_start) {
|
||||
// TODO
|
||||
assert(0 && "va_start not yet implemented");
|
||||
}
|
||||
// va_arg instruction
|
||||
else if (fndecl->llvmInternal == LLVMva_arg) {
|
||||
//Argument* fnarg = Argument::getNth(tf->parameters, 0);
|
||||
Expression* exp = (Expression*)arguments->data[0];
|
||||
DValue* expelem = exp->toElem(p);
|
||||
Type* t = DtoDType(type);
|
||||
const LLType* llt = DtoType(type);
|
||||
if (DtoIsPassedByRef(t))
|
||||
llt = getPtrToType(llt);
|
||||
// TODO
|
||||
// issue a warning for broken va_arg instruction.
|
||||
if (strcmp(global.params.llvmArch, "x86") != 0) {
|
||||
warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars());
|
||||
}
|
||||
// done
|
||||
return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp"));
|
||||
return DtoVaArg(loc, type, (Expression*)arguments->data[0]);
|
||||
}
|
||||
// alloca
|
||||
// C alloca
|
||||
else if (fndecl->llvmInternal == LLVMalloca) {
|
||||
//Argument* fnarg = Argument::getNth(tf->parameters, 0);
|
||||
Expression* exp = (Expression*)arguments->data[0];
|
||||
DValue* expv = exp->toElem(p);
|
||||
if (expv->getType()->toBasetype()->ty != Tint32)
|
||||
expv = DtoCast(loc, expv, Type::tint32);
|
||||
LLValue* alloc = new llvm::AllocaInst(LLType::Int8Ty, expv->getRVal(), "alloca", p->scopebb());
|
||||
// done
|
||||
return new DImValue(type, alloc);
|
||||
return new DImValue(type, gIR->ir->CreateAlloca(LLType::Int8Ty, expv->getRVal(), ".alloca"));
|
||||
}
|
||||
}
|
||||
|
||||
// args
|
||||
size_t n = arguments->dim;
|
||||
DFuncValue* dfn = fn->isFunc();
|
||||
if (dfn && dfn->func && dfn->func->llvmInternal == LLVMva_start)
|
||||
n = 1;
|
||||
if (delegateCall || (dfn && dfn->vthis)) n++;
|
||||
if (retinptr) n++;
|
||||
if (tf->linkage == LINKd && tf->varargs == 1) n+=2;
|
||||
if (dfn && dfn->func && dfn->func->isNested()) n++;
|
||||
|
||||
LLValue* funcval = fn->getRVal();
|
||||
assert(funcval != 0);
|
||||
std::vector<LLValue*> llargs(n, 0);
|
||||
|
||||
const LLFunctionType* llfnty = 0;
|
||||
|
||||
// TODO: review the stuff below, using the llvm type to choose seem like a bad idea. the D type should be used.
|
||||
//
|
||||
// normal function call
|
||||
if (llvm::isa<LLFunctionType>(funcval->getType())) {
|
||||
llfnty = llvm::cast<LLFunctionType>(funcval->getType());
|
||||
}
|
||||
// pointer to something
|
||||
else if (isaPointer(funcval->getType())) {
|
||||
// pointer to function pointer - I think this not really supposed to happen, but does :/
|
||||
// seems like sometimes we get a func* other times a func**
|
||||
if (isaPointer(funcval->getType()->getContainedType(0))) {
|
||||
funcval = DtoLoad(funcval);
|
||||
}
|
||||
// function pointer
|
||||
if (llvm::isa<LLFunctionType>(funcval->getType()->getContainedType(0))) {
|
||||
//Logger::cout() << "function pointer type:\n" << *funcval << '\n';
|
||||
llfnty = llvm::cast<LLFunctionType>(funcval->getType()->getContainedType(0));
|
||||
}
|
||||
// struct pointer - delegate
|
||||
else if (isaStruct(funcval->getType()->getContainedType(0))) {
|
||||
funcval = DtoGEPi(funcval,0,1);
|
||||
funcval = DtoLoad(funcval);
|
||||
const LLType* ty = funcval->getType()->getContainedType(0);
|
||||
llfnty = llvm::cast<LLFunctionType>(ty);
|
||||
}
|
||||
// unknown
|
||||
else {
|
||||
Logger::cout() << "what kind of pointer are we calling? : " << *funcval->getType() << '\n';
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger::cout() << "what are we calling? : " << *funcval << '\n';
|
||||
}
|
||||
assert(llfnty);
|
||||
//Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
|
||||
|
||||
// argument handling
|
||||
LLFunctionType::param_iterator argiter = llfnty->param_begin();
|
||||
int j = 0;
|
||||
|
||||
// attrs
|
||||
llvm::PAListPtr palist;
|
||||
|
||||
// hidden struct return arguments
|
||||
// TODO: use sret param attr
|
||||
if (retinptr) {
|
||||
llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint());
|
||||
++j;
|
||||
++argiter;
|
||||
}
|
||||
|
||||
// this arguments
|
||||
if (dfn && dfn->vthis) {
|
||||
Logger::cout() << "This Call" << '\n';// func val:" << *funcval << '\n';
|
||||
if (dfn->vthis->getType() != argiter->get()) {
|
||||
//Logger::cout() << "value: " << *dfn->vthis << " totype: " << *argiter->get() << '\n';
|
||||
llargs[j] = DtoBitCast(dfn->vthis, argiter->get());
|
||||
}
|
||||
else {
|
||||
llargs[j] = dfn->vthis;
|
||||
}
|
||||
++j;
|
||||
++argiter;
|
||||
}
|
||||
// delegate context arguments
|
||||
else if (delegateCall) {
|
||||
Logger::println("Delegate Call");
|
||||
LLValue* contextptr = DtoGEPi(fn->getRVal(),0,0);
|
||||
llargs[j] = DtoLoad(contextptr);
|
||||
++j;
|
||||
++argiter;
|
||||
}
|
||||
// nested call
|
||||
else if (dfn && dfn->func && dfn->func->isNested()) {
|
||||
Logger::println("Nested Call");
|
||||
LLValue* contextptr = DtoNestedContext(dfn->func->toParent2()->isFuncDeclaration());
|
||||
if (!contextptr)
|
||||
contextptr = llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty));
|
||||
llargs[j] = DtoBitCast(contextptr, getPtrToType(LLType::Int8Ty));
|
||||
++j;
|
||||
++argiter;
|
||||
}
|
||||
|
||||
// va arg function special argument passing
|
||||
if (va_magic)
|
||||
{
|
||||
size_t n = va_intrinsic ? arguments->dim : 1;
|
||||
for (int i=0; i<n; i++,j++)
|
||||
{
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
Expression* exp = (Expression*)arguments->data[i];
|
||||
DValue* expelem = exp->toElem(p);
|
||||
llargs[j] = DtoBitCast(expelem->getLVal(), getPtrToType(LLType::Int8Ty));
|
||||
}
|
||||
}
|
||||
// d variadic function
|
||||
else if (tf->linkage == LINKd && tf->varargs == 1)
|
||||
{
|
||||
Logger::println("doing d-style variadic arguments");
|
||||
|
||||
size_t nimplicit = j;
|
||||
|
||||
std::vector<const LLType*> vtypes;
|
||||
|
||||
// number of non variadic args
|
||||
int begin = tf->parameters->dim;
|
||||
Logger::println("num non vararg params = %d", begin);
|
||||
|
||||
// build struct with argument types
|
||||
for (int i=begin; i<arguments->dim; i++)
|
||||
{
|
||||
Argument* argu = Argument::getNth(tf->parameters, i);
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
vtypes.push_back(DtoType(argexp->type));
|
||||
size_t sz = getABITypeSize(vtypes.back());
|
||||
if (sz < PTRSIZE)
|
||||
vtypes.back() = DtoSize_t();
|
||||
}
|
||||
const LLStructType* vtype = LLStructType::get(vtypes);
|
||||
Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n';
|
||||
LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
|
||||
|
||||
// store arguments in the struct
|
||||
for (int i=begin,k=0; i<arguments->dim; i++,k++)
|
||||
{
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
if (global.params.llvmAnnotate)
|
||||
DtoAnnotation(argexp->toChars());
|
||||
LLValue* argdst = DtoGEPi(mem,0,k);
|
||||
argdst = DtoBitCast(argdst, getPtrToType(DtoType(argexp->type)));
|
||||
DtoVariadicArgument(argexp, argdst);
|
||||
}
|
||||
|
||||
// build type info array
|
||||
assert(Type::typeinfo->ir.irStruct->constInit);
|
||||
const LLType* typeinfotype = DtoType(Type::typeinfo->type);
|
||||
const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements());
|
||||
|
||||
llvm::GlobalVariable* typeinfomem =
|
||||
new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module);
|
||||
Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
|
||||
|
||||
std::vector<LLConstant*> vtypeinfos;
|
||||
for (int i=begin,k=0; i<arguments->dim; i++,k++)
|
||||
{
|
||||
Expression* argexp = (Expression*)arguments->data[i];
|
||||
vtypeinfos.push_back(DtoTypeInfoOf(argexp->type));
|
||||
}
|
||||
|
||||
// apply initializer
|
||||
LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos);
|
||||
typeinfomem->setInitializer(tiinits);
|
||||
|
||||
// put data in d-array
|
||||
std::vector<LLConstant*> pinits;
|
||||
pinits.push_back(DtoConstSize_t(vtype->getNumElements()));
|
||||
pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
|
||||
const LLType* tiarrty = llfnty->getParamType(j)->getContainedType(0);
|
||||
tiinits = llvm::ConstantStruct::get(pinits);
|
||||
LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty,
|
||||
true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module);
|
||||
|
||||
// specify arguments
|
||||
llargs[j] = typeinfoarrayparam;;
|
||||
j++;
|
||||
llargs[j] = p->ir->CreateBitCast(mem, getPtrToType(LLType::Int8Ty), "tmp");
|
||||
j++;
|
||||
|
||||
// pass non variadic args
|
||||
for (int i=0; i<begin; i++)
|
||||
{
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
|
||||
llargs[j] = argval->getRVal();
|
||||
|
||||
if (fnarg->llvmByVal)
|
||||
palist = palist.addAttr(j, llvm::ParamAttr::ByVal);
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
// make sure arg vector has the right size
|
||||
llargs.resize(nimplicit+begin+2);
|
||||
}
|
||||
// normal function call
|
||||
else
|
||||
{
|
||||
Logger::println("doing normal arguments");
|
||||
for (int i=0; i<arguments->dim; i++,j++) {
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
if (global.params.llvmAnnotate)
|
||||
DtoAnnotation(((Expression*)arguments->data[i])->toChars());
|
||||
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
|
||||
llargs[j] = argval->getRVal();
|
||||
if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) {
|
||||
llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
|
||||
}
|
||||
|
||||
if (fnarg && fnarg->llvmByVal)
|
||||
palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
Logger::println("%d params passed", n);
|
||||
for (int i=0; i<llargs.size(); ++i) {
|
||||
assert(llargs[i]);
|
||||
Logger::cout() << "arg["<<i<<"] = " << *llargs[i] << '\n';
|
||||
}
|
||||
#endif
|
||||
|
||||
// void returns cannot not be named
|
||||
const char* varname = "";
|
||||
if (llfnty->getReturnType() != LLType::VoidTy)
|
||||
varname = "tmp";
|
||||
|
||||
//Logger::cout() << "Calling: " << *funcval << '\n';
|
||||
|
||||
// call the function
|
||||
CallOrInvoke* call = gIR->CreateCallOrInvoke(funcval, llargs.begin(), llargs.end(), varname);
|
||||
|
||||
LLValue* retllval = (retinptr) ? llargs[0] : call->get();
|
||||
|
||||
// if the type of retllval is abstract, refine to concrete
|
||||
if(retllval->getType()->isAbstract())
|
||||
retllval = DtoBitCast(retllval, getPtrToType(DtoType(type)), "retval");
|
||||
|
||||
// set calling convention
|
||||
if (dfn && dfn->func) {
|
||||
int li = dfn->func->llvmInternal;
|
||||
if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
}
|
||||
else {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
|
||||
// param attrs
|
||||
call->setParamAttrs(palist);
|
||||
|
||||
return new DImValue(type, retllval, false);
|
||||
return DtoCallFunction(type, fnval, arguments);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+10
-14
@@ -283,20 +283,6 @@ llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned DtoCallingConv(LINK l)
|
||||
{
|
||||
if (l == LINKc || l == LINKcpp)
|
||||
return llvm::CallingConv::C;
|
||||
else if (l == LINKd || l == LINKdefault)
|
||||
return llvm::CallingConv::Fast;
|
||||
else if (l == LINKwindows)
|
||||
return llvm::CallingConv::X86_StdCall;
|
||||
else
|
||||
assert(0 && "Unsupported calling convention");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue* DtoPointedType(LLValue* ptr, LLValue* val)
|
||||
{
|
||||
const LLType* ptrTy = ptr->getType()->getContainedType(0);
|
||||
@@ -596,6 +582,16 @@ const LLStructType* isaStruct(const LLType* t)
|
||||
return llvm::dyn_cast<LLStructType>(t);
|
||||
}
|
||||
|
||||
const LLFunctionType* isaFunction(LLValue* v)
|
||||
{
|
||||
return llvm::dyn_cast<LLFunctionType>(v->getType());
|
||||
}
|
||||
|
||||
const LLFunctionType* isaFunction(const LLType* t)
|
||||
{
|
||||
return llvm::dyn_cast<LLFunctionType>(t);
|
||||
}
|
||||
|
||||
LLConstant* isaConstant(LLValue* v)
|
||||
{
|
||||
return llvm::dyn_cast<llvm::Constant>(v);
|
||||
|
||||
+2
-3
@@ -34,9 +34,6 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym);
|
||||
LLGlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym);
|
||||
LLGlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym);
|
||||
|
||||
// convert DMD calling conv to LLVM
|
||||
unsigned DtoCallingConv(LINK l);
|
||||
|
||||
// TODO: this one should be removed!!!
|
||||
LLValue* DtoPointedType(LLValue* ptr, LLValue* val);
|
||||
|
||||
@@ -77,6 +74,8 @@ const LLArrayType* isaArray(LLValue* v);
|
||||
const LLArrayType* isaArray(const LLType* t);
|
||||
const LLStructType* isaStruct(LLValue* v);
|
||||
const LLStructType* isaStruct(const LLType* t);
|
||||
const LLFunctionType* isaFunction(LLValue* v);
|
||||
const LLFunctionType* isaFunction(const LLType* t);
|
||||
LLConstant* isaConstant(LLValue* v);
|
||||
LLConstantInt* isaConstantInt(LLValue* v);
|
||||
llvm::Argument* isaArgument(LLValue* v);
|
||||
|
||||
Reference in New Issue
Block a user