mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
Refactoring: move ABI-specific variadic stuff to TargetABI type.
This commit is contained in:
parent
a41a31d535
commit
aa38fe06ec
6 changed files with 85 additions and 86 deletions
|
@ -440,7 +440,13 @@ struct X86_64TargetABI : TargetABI {
|
|||
|
||||
void rewriteArgument(IrFuncTyArg& arg);
|
||||
|
||||
LLValue* prepareVaStart(LLValue* addressOfAp);
|
||||
|
||||
void vaCopy(LLValue* addressOfDest, LLValue* src);
|
||||
|
||||
private:
|
||||
LLType* getValistType();
|
||||
|
||||
// Rewrite structs and static arrays <= 64 bit and of a size that is a power of 2
|
||||
// to an integer of the same size.
|
||||
bool canRewriteAsInt(Type* t) {
|
||||
|
@ -559,12 +565,16 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty) {
|
|||
fty.reverseParams = true;
|
||||
}
|
||||
|
||||
bool isSystemVAMD64Target() {
|
||||
return global.params.targetTriple.getArch() == llvm::Triple::x86_64
|
||||
&& !global.params.targetTriple.isOSWindows();
|
||||
}
|
||||
|
||||
LLType* getSystemVAMD64NativeValistType() {
|
||||
/**
|
||||
* The System V AMD64 ABI uses a special native va_list type - a 24-bytes struct passed by
|
||||
* reference.
|
||||
* In druntime, the struct is defined as core.stdc.stdarg.__va_list; the actually used
|
||||
* core.stdc.stdarg.va_list type is a raw char* pointer though to achieve byref semantics.
|
||||
* This requires a little bit of compiler magic in the following implementations.
|
||||
*/
|
||||
|
||||
LLType* X86_64TargetABI::getValistType() {
|
||||
LLType* uintType = LLType::getInt32Ty(gIR->context());
|
||||
LLType* voidPointerType = getVoidPtrType();
|
||||
|
||||
|
@ -574,5 +584,27 @@ LLType* getSystemVAMD64NativeValistType() {
|
|||
parts.push_back(voidPointerType); // void* overflow_arg_area;
|
||||
parts.push_back(voidPointerType); // void* reg_save_area; }
|
||||
|
||||
return LLStructType::get(gIR->context(), parts, "__va_list");
|
||||
return LLStructType::get(gIR->context(), parts);
|
||||
}
|
||||
|
||||
LLValue* X86_64TargetABI::prepareVaStart(LLValue* pAp) {
|
||||
// Since the user only created a char* pointer (ap) on the stack before invoking va_start,
|
||||
// we first need to allocate the actual __va_list struct and set 'ap' to its address.
|
||||
LLValue* valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
||||
valistmem = DtoBitCast(valistmem, getVoidPtrType());
|
||||
DtoStore(valistmem, pAp); // ap = (void*)__va_list_mem
|
||||
|
||||
// pass a void* pointer to the actual struct to LLVM's va_start intrinsic
|
||||
return valistmem;
|
||||
}
|
||||
|
||||
void X86_64TargetABI::vaCopy(LLValue* pDest, LLValue* src) {
|
||||
// Analog to va_start, we need to allocate a __va_list struct on the stack first
|
||||
// and set the passed 'dest' char* pointer to its address.
|
||||
LLValue* valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
||||
DtoStore(DtoBitCast(valistmem, getVoidPtrType()), pDest);
|
||||
|
||||
// Now bitcopy the source struct over the destination struct.
|
||||
src = DtoBitCast(src, valistmem->getType());
|
||||
DtoStore(DtoLoad(src), valistmem); // *(__va_list*)dest = *(__va_list*)src
|
||||
}
|
||||
|
|
|
@ -20,8 +20,4 @@ namespace llvm { class Type; }
|
|||
|
||||
TargetABI* getX86_64TargetABI();
|
||||
|
||||
bool isSystemVAMD64Target();
|
||||
|
||||
llvm::Type* getSystemVAMD64NativeValistType();
|
||||
|
||||
#endif
|
||||
|
|
18
gen/abi.cpp
18
gen/abi.cpp
|
@ -26,7 +26,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ABIRewrite::getL(Type* dty, DValue* v, llvm::Value* lval)
|
||||
void ABIRewrite::getL(Type* dty, DValue* v, LLValue* lval)
|
||||
{
|
||||
LLValue* rval = get(dty, v);
|
||||
assert(rval->getType() == lval->getType()->getContainedType(0));
|
||||
|
@ -35,6 +35,22 @@ void ABIRewrite::getL(Type* dty, DValue* v, llvm::Value* lval)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue* TargetABI::prepareVaStart(LLValue* pAp)
|
||||
{
|
||||
// pass a void* pointer to ap to LLVM's va_start intrinsic
|
||||
return DtoBitCast(pAp, getVoidPtrType());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TargetABI::vaCopy(LLValue* pDest, LLValue* src)
|
||||
{
|
||||
// simply bitcopy src over dest
|
||||
DtoStore(src, pDest);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Some reasonable defaults for when we don't know what ABI to use.
|
||||
struct UnknownTargetABI : TargetABI
|
||||
{
|
||||
|
|
|
@ -91,6 +91,15 @@ struct TargetABI
|
|||
virtual void rewriteFunctionType(TypeFunction* t, IrFuncTy &fty) = 0;
|
||||
|
||||
virtual void rewriteArgument(IrFuncTyArg& arg) {}
|
||||
|
||||
// Prepares a va_start intrinsic call.
|
||||
// Input: pointer to passed ap argument (va_list*)
|
||||
// Output: value to be passed to LLVM's va_start intrinsic (void*)
|
||||
virtual llvm::Value* prepareVaStart(llvm::Value* pAp);
|
||||
|
||||
// Implements the va_copy intrinsic.
|
||||
// Input: pointer to dest argument (va_list*) and src argument (va_list)
|
||||
virtual void vaCopy(llvm::Value* pDest, llvm::Value* src);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "statement.h"
|
||||
#include "template.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/abi-x86-64.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/classes.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
@ -1179,30 +1178,17 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
|||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
{
|
||||
// allocate _argptr (of type core.stdc.stdarg.va_list)
|
||||
LLValue* argptrmem = DtoAlloca(Type::tvalist, "_argptr_mem"); // _argptr_mem = new va_list [most likely char**]
|
||||
LLValue* argptrmem = DtoAlloca(Type::tvalist, "_argptr_mem");
|
||||
irFunc->_argptr = argptrmem;
|
||||
|
||||
// initialize _argptr
|
||||
if (isSystemVAMD64Target()) { // System V AMD64 ABI:
|
||||
LLType* nativeValistType = getSystemVAMD64NativeValistType();
|
||||
LLValue* valistmem = DtoRawAlloca(nativeValistType,
|
||||
0, "__va_list_mem"); // __va_list_mem = new __va_list
|
||||
valistmem = DtoBitCast(valistmem, getVoidPtrType()); // valistmem = (char*)__va_list_mem
|
||||
DtoStore(valistmem, argptrmem); // *argptrmem = valistmem
|
||||
// => _argptr = (char*)__va_list_mem
|
||||
llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), // llvm.va_start(valistmem)
|
||||
valistmem, "", gIR->scopebb()); // => llvm.va_start(_argptr)
|
||||
} else { // all other ABIs:
|
||||
llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), // llvm.va_start((char*)&_argptr)
|
||||
DtoBitCast(argptrmem, getVoidPtrType()), "", gIR->scopebb());
|
||||
}
|
||||
// initialize _argptr with a call to the va_start intrinsic
|
||||
LLValue* vaStartArg = gABI->prepareVaStart(argptrmem);
|
||||
llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), vaStartArg, "", gIR->scopebb());
|
||||
|
||||
// copy _arguments to a memory location
|
||||
LLType* argumentsType = irFunc->_arguments->getType();
|
||||
LLValue* argumentsmem = DtoRawAlloca(argumentsType,
|
||||
0, "_arguments_mem"); // _arguments_mem = new TypeInfo[]
|
||||
new llvm::StoreInst(irFunc->_arguments, argumentsmem, // *_arguments_mem = <passed _arguments>
|
||||
gIR->scopebb());
|
||||
LLValue* argumentsmem = DtoRawAlloca(argumentsType, 0, "_arguments_mem");
|
||||
new llvm::StoreInst(irFunc->_arguments, argumentsmem, gIR->scopebb());
|
||||
irFunc->_arguments = argumentsmem;
|
||||
}
|
||||
|
||||
|
|
70
gen/toir.cpp
70
gen/toir.cpp
|
@ -19,7 +19,6 @@
|
|||
#include "template.h"
|
||||
#include "gen/aa.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/abi-x86-64.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/classes.h"
|
||||
#include "gen/complex.h"
|
||||
|
@ -828,16 +827,6 @@ public:
|
|||
{
|
||||
FuncDeclaration* fndecl = dfnval->func;
|
||||
|
||||
// The System V AMD64 ABI used for all x86-64 targets except for Windows
|
||||
// uses a special native va_list type - a 24-bytes struct passed by reference.
|
||||
// In druntime, the struct is defined as core.stdc.stdarg.__va_list;
|
||||
// the actually used core.stdc.stdarg.va_list type is a raw char* pointer
|
||||
// though to achieve byref semantics.
|
||||
// This requires a little bit of compiler magic here in the following
|
||||
// implementations of LDC's va_start and va_copy intrinsics.
|
||||
const bool isSystemVTarget = isSystemVAMD64Target();
|
||||
LLType* systemVValistType = getSystemVAMD64NativeValistType();
|
||||
|
||||
// as requested by bearophile, see if it's a C printf call and that it's valid.
|
||||
if (global.params.warnings && checkPrintf)
|
||||
{
|
||||
|
@ -849,31 +838,20 @@ public:
|
|||
|
||||
// va_start instruction
|
||||
if (fndecl->llvmInternal == LLVMva_start) {
|
||||
if (e->arguments->dim != 2) {
|
||||
e->error("va_start instruction expects 2 arguments");
|
||||
if (e->arguments->dim < 1 || e->arguments->dim > 2) {
|
||||
e->error("va_start instruction expects 1 (or 2) arguments");
|
||||
fatal();
|
||||
}
|
||||
Expression* exp = (*e->arguments)[0];
|
||||
LLValue* arg = toElem(exp)->getLVal(); // arg = &<passed ap> [va_list*]
|
||||
if (LLValue* argptr = p->func()->_argptr) { // variadic extern(D) function with hidden _argptr:
|
||||
DtoStore(DtoLoad(argptr), arg); // *arg = *_argptr_mem
|
||||
// => <passed ap> = _argptr
|
||||
result = new DImValue(e->type, arg);
|
||||
} else if (isSystemVTarget) { // System V AMD64 ABI:
|
||||
// Since the user only created a char* pointer on the stack before invoking va_start, we first
|
||||
// need to allocate the actual __va_list struct and set the passed pointer to its address
|
||||
// before invoking va_start.
|
||||
LLValue* valistmem = DtoRawAlloca(systemVValistType,
|
||||
0, "__va_list_mem"); // __va_list_mem = new __va_list
|
||||
valistmem = DtoBitCast(valistmem, getVoidPtrType()); // valistmem = (char*)__va_list_mem
|
||||
DtoStore(valistmem, arg); // *arg = valistmem
|
||||
// => <passed ap> = (char*)__va_list_mem
|
||||
result = new DImValue(e->type, gIR->ir->CreateCall( // llvm.va_start(valistmem)
|
||||
GET_INTRINSIC_DECL(vastart), valistmem, "")); // => llvm.va_start(<passed ap>)
|
||||
} else { // all other ABIs:
|
||||
arg = DtoBitCast(arg, getVoidPtrType()); // arg = (char*)arg
|
||||
result = new DImValue(e->type, gIR->ir->CreateCall( // llvm.va_start(arg)
|
||||
GET_INTRINSIC_DECL(vastart), arg, "")); // => llvm.va_start((char*)&<passed ap>)
|
||||
LLValue* pAp = toElem(exp)->getLVal(); // va_list*
|
||||
// variadic extern(D) function with implicit _argptr?
|
||||
if (LLValue* pArgptr = p->func()->_argptr) {
|
||||
DtoStore(DtoLoad(pArgptr), pAp); // ap = _argptr
|
||||
result = new DImValue(e->type, pAp);
|
||||
} else {
|
||||
LLValue* vaStartArg = gABI->prepareVaStart(pAp);
|
||||
result = new DImValue(e->type, gIR->ir->CreateCall(
|
||||
GET_INTRINSIC_DECL(vastart), vaStartArg, ""));
|
||||
}
|
||||
}
|
||||
// va_copy instruction
|
||||
|
@ -882,28 +860,10 @@ public:
|
|||
e->error("va_copy instruction expects 2 arguments");
|
||||
fatal();
|
||||
}
|
||||
|
||||
LLValue* arg1 = toElem((*e->arguments)[0])->getLVal(); // arg1 = &<passed dest> [va_list*]
|
||||
LLValue* arg2 = toElem((*e->arguments)[1])->getRVal(); // arg2 = <passed src> [va_list]
|
||||
|
||||
if (isSystemVTarget) {
|
||||
// Similar to va_start, we need to allocate a new __va_list struct on the stack first
|
||||
// and set the passed destination char* pointer to its address.
|
||||
LLValue* valistmem = DtoRawAlloca(systemVValistType,
|
||||
0, "__va_list_mem"); // __va_list_mem = new __va_list
|
||||
DtoStore(DtoBitCast(valistmem, getVoidPtrType()), // *arg1 = (char*)__va_list_mem
|
||||
arg1); // => <passed dest> = (char*)__va_list_mem
|
||||
|
||||
// Now simply bitcopy the source struct over the destination struct.
|
||||
arg2 = DtoBitCast(arg2, valistmem->getType()); // arg2 = (__va_list*)arg2
|
||||
DtoStore(DtoLoad(arg2), valistmem); // *__va_list_mem = *arg2
|
||||
// => *(__va_list*)<passed dest> = *(__va_list*)<passed src>
|
||||
} else { // all other ABIs:
|
||||
DtoStore(arg2, arg1); // *arg1 = arg2
|
||||
// => <passed dest> = <passed src>
|
||||
}
|
||||
|
||||
result = new DVarValue(e->type, arg1);
|
||||
LLValue* pDest = toElem((*e->arguments)[0])->getLVal(); // va_list*
|
||||
LLValue* src = toElem((*e->arguments)[1])->getRVal(); // va_list
|
||||
gABI->vaCopy(pDest, src);
|
||||
result = new DVarValue(e->type, pDest);
|
||||
}
|
||||
// va_arg instruction
|
||||
else if (fndecl->llvmInternal == LLVMva_arg) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue