Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Factored out x86 ABI code to separate file.
- Loading branch information
1 parent
1c301aa
commit d5084d9
Showing
3 changed files
with
217 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,206 @@ | |||
#include "gen/llvm.h" | |||
|
|||
#include "mars.h" | |||
|
|||
#include "gen/irstate.h" | |||
#include "gen/llvmhelpers.h" | |||
#include "gen/tollvm.h" | |||
#include "gen/abi.h" | |||
#include "gen/logger.h" | |||
#include "gen/dvalue.h" | |||
#include "gen/abi-generic.h" | |||
#include "ir/irfunction.h" | |||
#include "ir/irfuncty.h" | |||
|
|||
struct X86_cfloat_rewrite : ABIRewrite | |||
{ | |||
// i64 -> {float,float} | |||
LLValue* get(Type*, DValue* dv) | |||
{ | |||
LLValue* in = dv->getRVal(); | |||
|
|||
// extract real part | |||
LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::getInt32Ty(gIR->context())); | |||
rpart = gIR->ir->CreateBitCast(rpart, LLType::getFloatTy(gIR->context()), ".re"); | |||
|
|||
// extract imag part | |||
LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); | |||
ipart = gIR->ir->CreateTrunc(ipart, LLType::getInt32Ty(gIR->context())); | |||
ipart = gIR->ir->CreateBitCast(ipart, LLType::getFloatTy(gIR->context()), ".im"); | |||
|
|||
// return {float,float} aggr pair with same bits | |||
return DtoAggrPair(rpart, ipart, ".final_cfloat"); | |||
} | |||
|
|||
// {float,float} -> i64 | |||
LLValue* put(Type*, DValue* dv) | |||
{ | |||
LLValue* v = dv->getRVal(); | |||
|
|||
// extract real | |||
LLValue* r = gIR->ir->CreateExtractValue(v, 0); | |||
// cast to i32 | |||
r = gIR->ir->CreateBitCast(r, LLType::getInt32Ty(gIR->context())); | |||
// zext to i64 | |||
r = gIR->ir->CreateZExt(r, LLType::getInt64Ty(gIR->context())); | |||
|
|||
// extract imag | |||
LLValue* i = gIR->ir->CreateExtractValue(v, 1); | |||
// cast to i32 | |||
i = gIR->ir->CreateBitCast(i, LLType::getInt32Ty(gIR->context())); | |||
// zext to i64 | |||
i = gIR->ir->CreateZExt(i, LLType::getInt64Ty(gIR->context())); | |||
// shift up | |||
i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); | |||
|
|||
// combine and return | |||
return v = gIR->ir->CreateOr(r, i); | |||
} | |||
|
|||
// {float,float} -> i64 | |||
LLType* type(Type*, LLType* t) | |||
{ | |||
return LLType::getInt64Ty(gIR->context()); | |||
} | |||
}; | |||
|
|||
|
|||
struct X86TargetABI : TargetABI | |||
{ | |||
X87_complex_swap swapComplex; | |||
X86_cfloat_rewrite cfloatToInt; | |||
X86_struct_to_register structToReg; | |||
|
|||
bool returnInArg(TypeFunction* tf) | |||
{ | |||
#if DMDV2 | |||
if (tf->isref) | |||
return false; | |||
#endif | |||
Type* rt = tf->next->toBasetype(); | |||
// D only returns structs on the stack | |||
if (tf->linkage == LINKd) | |||
return (rt->ty == Tstruct); | |||
// other ABI's follow C, which is cdouble and creal returned on the stack | |||
// as well as structs | |||
else | |||
return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80); | |||
} | |||
|
|||
bool passByVal(Type* t) | |||
{ | |||
return t->toBasetype()->ty == Tstruct || t->toBasetype()->ty == Tsarray; | |||
} | |||
|
|||
void rewriteFunctionType(TypeFunction* tf) | |||
{ | |||
IrFuncTy& fty = tf->fty; | |||
Type* rt = fty.ret->type->toBasetype(); | |||
|
|||
// extern(D) | |||
if (tf->linkage == LINKd) | |||
{ | |||
// RETURN VALUE | |||
|
|||
// complex {re,im} -> {im,re} | |||
if (rt->iscomplex()) | |||
{ | |||
Logger::println("Rewriting complex return value"); | |||
fty.ret->rewrite = &swapComplex; | |||
} | |||
|
|||
// IMPLICIT PARAMETERS | |||
|
|||
// mark this/nested params inreg | |||
if (fty.arg_this) | |||
{ | |||
Logger::println("Putting 'this' in register"); | |||
fty.arg_this->attrs = llvm::Attribute::InReg; | |||
} | |||
else if (fty.arg_nest) | |||
{ | |||
Logger::println("Putting context ptr in register"); | |||
fty.arg_nest->attrs = llvm::Attribute::InReg; | |||
} | |||
else if (IrFuncTyArg* sret = fty.arg_sret) | |||
{ | |||
Logger::println("Putting sret ptr in register"); | |||
// sret and inreg are incompatible, but the ABI requires the | |||
// sret parameter to be in EAX in this situation... | |||
sret->attrs = (sret->attrs | llvm::Attribute::InReg) | |||
& ~llvm::Attribute::StructRet; | |||
} | |||
// otherwise try to mark the last param inreg | |||
else if (!fty.args.empty()) | |||
{ | |||
// The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met: | |||
// * It fits in EAX. | |||
// * It is not a 3 byte struct. | |||
// * It is not a floating point type. | |||
|
|||
IrFuncTyArg* last = fty.args.back(); | |||
Type* lastTy = last->type->toBasetype(); | |||
unsigned sz = lastTy->size(); | |||
|
|||
if (last->byref && !last->isByVal()) | |||
{ | |||
Logger::println("Putting last (byref) parameter in register"); | |||
last->attrs |= llvm::Attribute::InReg; | |||
} | |||
else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right? | |||
{ | |||
// rewrite the struct into an integer to make inreg work | |||
if (lastTy->ty == Tstruct) | |||
{ | |||
last->rewrite = &structToReg; | |||
last->ltype = structToReg.type(last->type, last->ltype); | |||
last->byref = false; | |||
// erase previous attributes | |||
last->attrs = 0; | |||
} | |||
else if (lastTy->ty == Tsarray) | |||
{ | |||
last->ltype = DtoType(last->type); | |||
last->byref = false; | |||
last->attrs &= ~llvm::Attribute::ByVal; | |||
} | |||
last->attrs |= llvm::Attribute::InReg; | |||
} | |||
} | |||
|
|||
// FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec: | |||
// "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee." | |||
|
|||
// EXPLICIT PARAMETERS | |||
|
|||
// reverse parameter order | |||
// for non variadics | |||
if (!fty.args.empty() && tf->varargs != 1) | |||
{ | |||
fty.reverseParams = true; | |||
} | |||
} | |||
|
|||
// extern(C) and all others | |||
else | |||
{ | |||
// RETURN VALUE | |||
|
|||
// cfloat -> i64 | |||
if (tf->next->toBasetype() == Type::tcomplex32) | |||
{ | |||
fty.ret->rewrite = &cfloatToInt; | |||
fty.ret->ltype = LLType::getInt64Ty(gIR->context()); | |||
} | |||
|
|||
// IMPLICIT PARAMETERS | |||
|
|||
// EXPLICIT PARAMETERS | |||
} | |||
} | |||
}; | |||
|
|||
// The public getter for abi.cpp. | |||
TargetABI* getX86TargetABI() { | |||
return new X86TargetABI; | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,8 @@ | |||
#ifndef __LDC_GEN_ABI_X86_H__ | |||
#define __LDC_GEN_ABI_X86_H__ | |||
|
|||
#include "gen/abi.h" | |||
|
|||
TargetABI* getX86TargetABI(); | |||
|
|||
#endif |
Oops, something went wrong.