mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-12 09:53:14 +01:00
[svn r59] Added support for C-style variadic functions. Currently only works on x86, x86-64 va_arg is broken in LLVM 2.1. PPC and PPC64 unknown.
Updates to runtime. Rebuild!
This commit is contained in:
44
dmd/attrib.c
44
dmd/attrib.c
@@ -29,8 +29,10 @@
|
||||
#include "aggregate.h"
|
||||
#include "module.h"
|
||||
#include "parse.h"
|
||||
#include "template.h"
|
||||
|
||||
#include "../gen/enums.h"
|
||||
#include "../gen/logger.h"
|
||||
|
||||
extern void obj_includelib(char *name);
|
||||
|
||||
@@ -752,9 +754,9 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
#if IN_LLVM
|
||||
int llvm_internal = 0;
|
||||
char* llvm_str1 = NULL;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
|
||||
if (ident == Id::msg)
|
||||
{
|
||||
@@ -873,6 +875,18 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
llvm_internal = LLVMbind;
|
||||
assert(args->dim == 2);
|
||||
}
|
||||
else if (strcmp(str,"va_start")==0) {
|
||||
llvm_internal = LLVMva_start;
|
||||
assert(args->dim == 1);
|
||||
}
|
||||
else if (strcmp(str,"va_arg")==0) {
|
||||
llvm_internal = LLVMva_arg;
|
||||
assert(args->dim == 1);
|
||||
}
|
||||
else if (strcmp(str,"va_intrinsic")==0) {
|
||||
llvm_internal = LLVMva_intrinsic;
|
||||
assert(args->dim == 2);
|
||||
}
|
||||
else {
|
||||
error("unknown pragma command: %s", str);
|
||||
}
|
||||
@@ -886,6 +900,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
case LLVMintrinsic:
|
||||
case LLVMmangle:
|
||||
case LLVMbind:
|
||||
case LLVMva_intrinsic:
|
||||
e = (Expression *)args->data[1];
|
||||
e = e->semantic(sc);
|
||||
e = e->optimize(WANTvalue);
|
||||
@@ -897,6 +912,8 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
break;
|
||||
|
||||
case LLVMnull:
|
||||
case LLVMva_arg:
|
||||
case LLVMva_start:
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -923,6 +940,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
{
|
||||
case LLVMintrinsic:
|
||||
case LLVMmangle:
|
||||
case LLVMva_intrinsic:
|
||||
if (FuncDeclaration* fd = s->isFuncDeclaration()) {
|
||||
fd->llvmInternal = llvm_internal;
|
||||
fd->llvmInternal1 = llvm_str1;
|
||||
@@ -932,7 +950,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LLVMnull:
|
||||
if (StaticCtorDeclaration* sd = s->isStaticCtorDeclaration()) {
|
||||
sd->llvmInternal = llvm_internal;
|
||||
@@ -942,7 +960,7 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LLVMbind:
|
||||
if (VarDeclaration* vd = s->isVarDeclaration()) {
|
||||
vd->llvmInternal = llvm_internal;
|
||||
@@ -953,7 +971,23 @@ void PragmaDeclaration::semantic(Scope *sc)
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LLVMva_start:
|
||||
case LLVMva_arg:
|
||||
if (TemplateDeclaration* td = s->isTemplateDeclaration()) {
|
||||
td->llvmInternal = llvm_internal;
|
||||
assert(td->parameters->dim == 1);
|
||||
assert(!td->overnext);
|
||||
assert(!td->overroot);
|
||||
assert(td->onemember);
|
||||
Logger::println("template->onemember = %s", td->onemember->toChars());
|
||||
}
|
||||
else {
|
||||
error("can only be used on templates");
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "invalid LLVM_internal pragma got through :/");
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ Dsymbol::Dsymbol()
|
||||
this->llvmInternal1 = NULL;
|
||||
this->llvmInternal2 = NULL;
|
||||
this->llvmValue = NULL;
|
||||
this->llvmDModule = NULL;
|
||||
}
|
||||
|
||||
Dsymbol::Dsymbol(Identifier *ident)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string>
|
||||
#include <vaarg.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
@@ -667,6 +668,10 @@ int main(int argc, char *argv[])
|
||||
global.params.llvmArch = const_cast<char*>(e->Name);
|
||||
if (global.params.verbose || very_verbose)
|
||||
printf("Default target found: %s\n", global.params.llvmArch);
|
||||
if (very_verbose) {
|
||||
int X = sizeof(va_list);
|
||||
printf("valist.sizeof = %d\n", X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,4 +5,7 @@ enum
|
||||
LLVMmangle,
|
||||
LLVMintrinsic,
|
||||
LLVMbind,
|
||||
LLVMva_arg,
|
||||
LLVMva_start,
|
||||
LLVMva_intrinsic
|
||||
};
|
||||
|
||||
72
gen/toir.c
72
gen/toir.c
@@ -210,12 +210,12 @@ elem* VarExp::toElem(IRState* p)
|
||||
else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
|
||||
{
|
||||
Logger::println("FuncDeclaration");
|
||||
if (fdecl->llvmValue == 0) {
|
||||
if (fdecl->llvmInternal != LLVMva_arg && fdecl->llvmValue == 0)
|
||||
fdecl->toObjFile();
|
||||
}
|
||||
e->val = fdecl->llvmValue;
|
||||
e->type = elem::FUNC;
|
||||
e->funcdecl = fdecl;
|
||||
return e;
|
||||
}
|
||||
else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration())
|
||||
{
|
||||
@@ -971,21 +971,21 @@ elem* CallExp::toElem(IRState* p)
|
||||
{
|
||||
Logger::print("CallExp::toElem: %s\n", toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
elem* e = new elem;
|
||||
elem* fn = e1->toElem(p);
|
||||
LINK dlink = LINKdefault;
|
||||
|
||||
TypeFunction* tf = 0;
|
||||
Type* e1type = LLVM_DtoDType(e1->type);
|
||||
|
||||
bool delegateCall = false;
|
||||
llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false);
|
||||
llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty,1,false);
|
||||
LINK dlink = LINKdefault;
|
||||
|
||||
// hidden struct return parameter handling
|
||||
bool retinptr = false;
|
||||
|
||||
TypeFunction* tf = 0;
|
||||
|
||||
Type* e1type = LLVM_DtoDType(e1->type);
|
||||
|
||||
// regular functions
|
||||
if (e1type->ty == Tfunction) {
|
||||
tf = (TypeFunction*)e1type;
|
||||
@@ -1012,7 +1012,38 @@ elem* CallExp::toElem(IRState* p)
|
||||
assert(tf);
|
||||
}
|
||||
|
||||
// va args
|
||||
bool va_magic = false;
|
||||
bool va_intrinsic = false;
|
||||
if (fn->funcdecl) {
|
||||
if (fn->funcdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
va_magic = true;
|
||||
va_intrinsic = true;
|
||||
}
|
||||
else if (fn->funcdecl->llvmInternal == LLVMva_start) {
|
||||
va_magic = true;
|
||||
}
|
||||
else if (fn->funcdecl->llvmInternal == LLVMva_arg) {
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, 0);
|
||||
Expression* exp = (Expression*)arguments->data[0];
|
||||
elem* expelem = exp->toElem(p);
|
||||
assert(expelem->mem);
|
||||
elem* e = new elem;
|
||||
Type* t = LLVM_DtoDType(type);
|
||||
const llvm::Type* llt = LLVM_DtoType(type);
|
||||
if (LLVM_DtoIsPassedByRef(t))
|
||||
llt = llvm::PointerType::get(llt);
|
||||
e->type = elem::VAL;
|
||||
e->val = p->ir->CreateVAArg(expelem->mem,llt,"tmp");
|
||||
delete expelem;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
// args
|
||||
size_t n = arguments->dim;
|
||||
if (fn->funcdecl && fn->funcdecl->llvmInternal == LLVMva_start)
|
||||
n = 1;
|
||||
if (fn->arg || delegateCall) n++;
|
||||
if (retinptr) n++;
|
||||
|
||||
@@ -1113,11 +1144,26 @@ elem* CallExp::toElem(IRState* p)
|
||||
|
||||
Logger::println("regular arguments");
|
||||
|
||||
// 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];
|
||||
elem* expelem = exp->toElem(p);
|
||||
assert(expelem->mem);
|
||||
llargs[j] = p->ir->CreateBitCast(expelem->mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
|
||||
delete expelem;
|
||||
}
|
||||
}
|
||||
// regular arguments
|
||||
for (int i=0; i<arguments->dim; i++,j++)
|
||||
{
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
llargs[j] = LLVM_DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
|
||||
else {
|
||||
for (int i=0; i<arguments->dim; i++,j++)
|
||||
{
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
llargs[j] = LLVM_DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// void returns cannot not be named
|
||||
@@ -1131,7 +1177,7 @@ elem* CallExp::toElem(IRState* p)
|
||||
Logger::cout() << *llargs[i] << '\n';
|
||||
}
|
||||
|
||||
//Logger::cout() << "Calling: " << *funcval->getType() << '\n';
|
||||
Logger::cout() << "Calling: " << *funcval->getType() << '\n';
|
||||
|
||||
// call the function
|
||||
llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
|
||||
@@ -1141,7 +1187,7 @@ elem* CallExp::toElem(IRState* p)
|
||||
e->val = call;
|
||||
|
||||
// set calling convention
|
||||
if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall)
|
||||
if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic && fn->funcdecl->llvmInternal != LLVMva_start)) || delegateCall)
|
||||
call->setCallingConv(LLVM_DtoCallingConv(dlink));
|
||||
else if (fn->callconv != (unsigned)-1)
|
||||
call->setCallingConv(fn->callconv);
|
||||
|
||||
187
gen/tollvm.c
187
gen/tollvm.c
@@ -221,8 +221,39 @@ const llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thispa
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const llvm::FunctionType* LLVM_DtoVaFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)fdecl->type;
|
||||
assert(f != 0);
|
||||
|
||||
const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
std::vector<const llvm::Type*> args;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
|
||||
f->llvmType = fty;
|
||||
return fty;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
return LLVM_DtoVaFunctionType(fdecl);
|
||||
}
|
||||
|
||||
TypeFunction* f = (TypeFunction*)fdecl->type;
|
||||
assert(f != 0);
|
||||
|
||||
@@ -260,73 +291,79 @@ const llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl)
|
||||
// parameter types
|
||||
std::vector<const llvm::Type*> paramvec;
|
||||
|
||||
if (retinptr) {
|
||||
Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
||||
paramvec.push_back(rettype);
|
||||
}
|
||||
|
||||
if (fdecl->needThis()) {
|
||||
if (AggregateDeclaration* ad = fdecl->isMember()) {
|
||||
Logger::print("isMember = this is: %s\n", ad->type->toChars());
|
||||
const llvm::Type* thisty = LLVM_DtoType(ad->type);
|
||||
Logger::cout() << "this llvm type: " << *thisty << '\n';
|
||||
if (llvm::isa<llvm::StructType>(thisty) || thisty == gIR->topstruct().recty.get())
|
||||
thisty = llvm::PointerType::get(thisty);
|
||||
paramvec.push_back(thisty);
|
||||
usesthis = true;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
else if (fdecl->isNested()) {
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
|
||||
usesthis = true;
|
||||
}
|
||||
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
// ensure scalar
|
||||
Type* argT = LLVM_DtoDType(arg->type);
|
||||
assert(argT);
|
||||
|
||||
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
|
||||
//assert(arg->vardecl);
|
||||
//arg->vardecl->refparam = true;
|
||||
else {
|
||||
if (retinptr) {
|
||||
Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
||||
paramvec.push_back(rettype);
|
||||
}
|
||||
else
|
||||
arg->llvmCopy = true;
|
||||
|
||||
const llvm::Type* at = LLVM_DtoType(argT);
|
||||
if (llvm::isa<llvm::StructType>(at)) {
|
||||
Logger::println("struct param");
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::ArrayType>(at)) {
|
||||
Logger::println("sarray param");
|
||||
assert(argT->ty == Tsarray);
|
||||
//paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::OpaqueType>(at)) {
|
||||
Logger::println("opaque param");
|
||||
if (argT->ty == Tstruct || argT->ty == Tclass)
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
if (fdecl->needThis()) {
|
||||
if (AggregateDeclaration* ad = fdecl->isMember()) {
|
||||
Logger::print("isMember = this is: %s\n", ad->type->toChars());
|
||||
const llvm::Type* thisty = LLVM_DtoType(ad->type);
|
||||
Logger::cout() << "this llvm type: " << *thisty << '\n';
|
||||
if (llvm::isa<llvm::StructType>(thisty) || thisty == gIR->topstruct().recty.get())
|
||||
thisty = llvm::PointerType::get(thisty);
|
||||
paramvec.push_back(thisty);
|
||||
usesthis = true;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
/*if (llvm::isa<llvm::StructType>(at) || argT->ty == Tstruct || argT->ty == Tsarray) {
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}*/
|
||||
else {
|
||||
if (!arg->llvmCopy) {
|
||||
Logger::println("ref param");
|
||||
at = llvm::PointerType::get(at);
|
||||
else if (fdecl->isNested()) {
|
||||
paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
|
||||
usesthis = true;
|
||||
}
|
||||
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
// ensure scalar
|
||||
Type* argT = LLVM_DtoDType(arg->type);
|
||||
assert(argT);
|
||||
|
||||
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
|
||||
//assert(arg->vardecl);
|
||||
//arg->vardecl->refparam = true;
|
||||
}
|
||||
else
|
||||
arg->llvmCopy = true;
|
||||
|
||||
const llvm::Type* at = LLVM_DtoType(argT);
|
||||
if (llvm::isa<llvm::StructType>(at)) {
|
||||
Logger::println("struct param");
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::ArrayType>(at)) {
|
||||
Logger::println("sarray param");
|
||||
assert(argT->ty == Tsarray);
|
||||
//paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::OpaqueType>(at)) {
|
||||
Logger::println("opaque param");
|
||||
if (argT->ty == Tstruct || argT->ty == Tclass)
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
/*if (llvm::isa<llvm::StructType>(at) || argT->ty == Tstruct || argT->ty == Tsarray) {
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}*/
|
||||
else {
|
||||
Logger::println("in param");
|
||||
if (!arg->llvmCopy) {
|
||||
Logger::println("ref param");
|
||||
at = llvm::PointerType::get(at);
|
||||
}
|
||||
else {
|
||||
Logger::println("in param");
|
||||
}
|
||||
paramvec.push_back(at);
|
||||
}
|
||||
paramvec.push_back(at);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,10 +968,44 @@ llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::Function* LLVM_DtoDeclareVaFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)LLVM_DtoDType(fdecl->type);
|
||||
const llvm::FunctionType* fty = LLVM_DtoVaFunctionType(fdecl);
|
||||
llvm::Constant* fn = 0;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
|
||||
assert(fn);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
|
||||
assert(fn);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
llvm::Function* func = llvm::cast_or_null<llvm::Function>(fn);
|
||||
assert(func);
|
||||
assert(func->isIntrinsic());
|
||||
fdecl->llvmValue = func;
|
||||
return func;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Function* LLVM_DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
return LLVM_DtoDeclareVaFunction(fdecl);
|
||||
}
|
||||
|
||||
// mangled name
|
||||
char* mangled_name = (fdecl->llvmInternal == LLVMintrinsic) ? fdecl->llvmInternal1 : fdecl->mangle();
|
||||
char* mangled_name;
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
mangled_name = fdecl->llvmInternal1;
|
||||
else
|
||||
mangled_name = fdecl->mangle();
|
||||
|
||||
// unit test special handling
|
||||
if (fdecl->isUnitTestDeclaration())
|
||||
|
||||
25
gen/toobj.c
25
gen/toobj.c
@@ -646,8 +646,31 @@ void FuncDeclaration::toObjFile()
|
||||
return;
|
||||
}
|
||||
|
||||
Type* t = LLVM_DtoDType(type);
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
bool declareOnly = false;
|
||||
if (TemplateInstance* tinst = parent->isTemplateInstance()) {
|
||||
TemplateDeclaration* tempdecl = tinst->tempdecl;
|
||||
if (tempdecl->llvmInternal == LLVMva_start)
|
||||
{
|
||||
Logger::println("magic va_start found");
|
||||
llvmInternal = LLVMva_start;
|
||||
declareOnly = true;
|
||||
}
|
||||
else if (tempdecl->llvmInternal == LLVMva_arg)
|
||||
{
|
||||
Logger::println("magic va_arg found");
|
||||
llvmInternal = LLVMva_arg;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Function* func = LLVM_DtoDeclareFunction(this);
|
||||
|
||||
if (declareOnly)
|
||||
return;
|
||||
|
||||
if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) {
|
||||
if (!llvmQueued) {
|
||||
Logger::println("queueing %s", toChars());
|
||||
@@ -657,8 +680,6 @@ void FuncDeclaration::toObjFile()
|
||||
return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete
|
||||
}
|
||||
|
||||
Type* t = LLVM_DtoDType(type);
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
assert(f->llvmType);
|
||||
const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ echo "compiling typeinfos"
|
||||
rebuild typeinfos.d -c -oqobj -dc=llvmdc-posix || exit 1
|
||||
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo.*.bc` ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "compiling llvm runtime support"
|
||||
rebuild llvmsupport.d -c -oqobj -dc=llvmdc-posix || exit
|
||||
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
echo "optimizing"
|
||||
opt -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
|
||||
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
module llvm.intrinsic;
|
||||
|
||||
// variable argument handling intrinsics
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.va_start")
|
||||
void llvm_va_start(void* args);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.va_end")
|
||||
void llvm_va_end(void* args);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.va_copy")
|
||||
void llvm_va_copy(void* dst, void* src);
|
||||
|
||||
// code generator intrinsics
|
||||
/*
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
|
||||
|
||||
25
lphobos/llvm/va_list.d
Normal file
25
lphobos/llvm/va_list.d
Normal file
@@ -0,0 +1,25 @@
|
||||
module llvm.va_list;
|
||||
|
||||
alias void* va_list;
|
||||
|
||||
/*
|
||||
|
||||
version(X86)
|
||||
{
|
||||
alias void* va_list;
|
||||
}
|
||||
else version(X86_64)
|
||||
{
|
||||
struct X86_64_va_list
|
||||
{
|
||||
uint gp_offset;
|
||||
uint fp_offset;
|
||||
void* overflow_arg_area;
|
||||
void* reg_save_area;
|
||||
}
|
||||
alias X86_64_va_list va_list;
|
||||
}
|
||||
else
|
||||
static assert("only x86 and x86-64 support va_list");
|
||||
|
||||
*/
|
||||
5
lphobos/llvmsupport.d
Normal file
5
lphobos/llvmsupport.d
Normal file
@@ -0,0 +1,5 @@
|
||||
module llvmsupport;
|
||||
|
||||
import
|
||||
llvm.intrinsic,
|
||||
llvm.va_list;
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
/**
|
||||
* C's <stdarg.h>
|
||||
* Authors: Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com
|
||||
* Authors: Hauke Duden, Walter Bright and Tomas Lindquist Olsen, Digital Mars, www.digitalmars.com
|
||||
* License: Public Domain
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdCStdarg
|
||||
@@ -11,32 +11,16 @@
|
||||
|
||||
module std.c.stdarg;
|
||||
|
||||
alias void* va_list;
|
||||
public import llvm.va_list;
|
||||
|
||||
template va_start(T)
|
||||
{
|
||||
void va_start(out va_list ap, inout T parmn)
|
||||
{
|
||||
ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
|
||||
}
|
||||
}
|
||||
pragma(LLVM_internal, "va_start")
|
||||
void va_start(T)(va_list ap, ref T);
|
||||
|
||||
template va_arg(T)
|
||||
{
|
||||
T va_arg(inout va_list ap)
|
||||
{
|
||||
T arg = *cast(T*)ap;
|
||||
ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
pragma(LLVM_internal, "va_arg")
|
||||
T va_arg(T)(va_list ap);
|
||||
|
||||
void va_end(va_list ap)
|
||||
{
|
||||
pragma(LLVM_internal, "va_intrinsic", "llvm.va_end")
|
||||
void va_end(va_list args);
|
||||
|
||||
}
|
||||
|
||||
void va_copy(out va_list dest, va_list src)
|
||||
{
|
||||
dest = src;
|
||||
}
|
||||
pragma(LLVM_internal, "va_intrinsic", "llvm.va_copy")
|
||||
void va_copy(va_list dst, va_list src);
|
||||
|
||||
21
test/vararg1.d
Normal file
21
test/vararg1.d
Normal file
@@ -0,0 +1,21 @@
|
||||
module vararg1;
|
||||
|
||||
import std.c.stdarg;
|
||||
|
||||
extern(C) int add(int n, ...)
|
||||
{
|
||||
va_list ap=void;
|
||||
va_start(ap, n);
|
||||
int r;
|
||||
//for (int i=0; i<n; i++)
|
||||
// r += va_arg!(int)(ap);
|
||||
r = va_arg!(int)(ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int i = add(4,1,2,3,4);
|
||||
assert(i == 10);
|
||||
}
|
||||
Reference in New Issue
Block a user