This commit is contained in:
Robert Clipsham
2009-06-01 19:02:20 +01:00
44 changed files with 256 additions and 243 deletions

View File

@@ -677,6 +677,13 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf) {
}
}
if (fty.arg_this) {
fty.arg_this->attrs |= llvm::Attribute::Nest;
}
if (fty.arg_nest) {
fty.arg_nest->attrs |= llvm::Attribute::Nest;
}
Logger::println("x86-64 D ABI: Transforming arguments");
LOG_SCOPE;

View File

@@ -132,7 +132,7 @@ struct X86_struct_to_register : ABIRewrite
assert(dv->isLVal());
LLValue* mem = dv->getLVal();
const LLType* t = LLIntegerType::get(dty->size()*8);
DtoLoad(DtoBitCast(mem, getPtrToType(t)));
return DtoLoad(DtoBitCast(mem, getPtrToType(t)));
}
const LLType* type(Type* t, const LLType*)
{
@@ -196,8 +196,16 @@ struct X86TargetABI : TargetABI
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.arg_sret && !fty.args.empty())
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.

View File

@@ -894,7 +894,10 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to)
Type* totype = to->toBasetype();
Type* fromtype = u->getType()->toBasetype();
assert(fromtype->ty == Tarray || fromtype->ty == Tsarray);
if (fromtype->ty != Tarray && fromtype->ty != Tsarray) {
error(loc, "can't cast %s to %s", u->getType()->toChars(), to->toChars());
fatal();
}
LLValue* rval;
LLValue* rval2;

View File

@@ -1528,9 +1528,8 @@ namespace AsmParserx8632
}
// osx needs an extra underscore
if ( global.params.os == OSMacOSX )
insnTemplate << "_";
if ( global.params.os == OSMacOSX || global.params.os == OSWindows )
insnTemplate << "_";
// print out the mangle
insnTemplate << vd->mangle();
vd->nakedUse = true;

View File

@@ -514,7 +514,7 @@ LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd)
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl)
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name)
{
// sanity checks
assert(fdecl->isVirtual());
@@ -533,7 +533,9 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl)
// load vtbl ptr
funcval = DtoLoad(funcval);
// index vtbl
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toChars());
std::string vtblname = name;
vtblname.append("@vtbl");
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str());
// load funcptr
funcval = DtoAlignedLoad(funcval);
@@ -542,6 +544,10 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl)
// cast to final funcptr type
funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type)));
// postpone naming until after casting to get the name in call instructions
funcval->setName(name);
if (Logger::enabled())
Logger::cout() << "funcval casted: " << *funcval << '\n';

View File

@@ -32,6 +32,6 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* to);
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* sd, VarDeclaration* vd);
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl);
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name);
#endif

View File

@@ -410,7 +410,7 @@ LLValue* DtoComplexEquals(Loc& loc, TOK op, DValue* lhs, DValue* rhs)
DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to)
{
Type* to = _to->toBasetype();
Type* vty = val->getType();
Type* vty = val->getType()->toBasetype();
if (to->iscomplex()) {
if (vty->size() == to->size())
return val;
@@ -438,17 +438,25 @@ DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to)
DImValue* im = new DImValue(to, impart);
return DtoCastFloat(loc, im, to);
}
else if (to->isfloating()) {
// FIXME: this loads both values, even when we only need one
LLValue* v = val->getRVal();
LLValue* repart = gIR->ir->CreateExtractValue(v, 0, ".re_part");
DImValue* re = new DImValue(to, repart);
return DtoCastFloat(loc, re, to);
}
else if (to->ty == Tbool) {
return new DImValue(_to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty)));
}
else if (to->isfloating() || to->isintegral()) {
// FIXME: this loads both values, even when we only need one
LLValue* v = val->getRVal();
LLValue* repart = gIR->ir->CreateExtractValue(v, 0, ".re_part");
Type *extractty;
if (vty->ty == Tcomplex32) {
extractty = Type::tfloat32;
} else if (vty->ty == Tcomplex64) {
extractty = Type::tfloat64;
} else if (vty->ty == Tcomplex80) {
extractty = Type::tfloat80;
}
DImValue* re = new DImValue(extractty, repart);
return DtoCastFloat(loc, re, to);
}
else
assert(0);
error(loc, "Don't know how to cast %s to %s", vty->toChars(), to->toChars());
}

View File

@@ -369,7 +369,7 @@ int main(int argc, char** argv)
}
else
{
if (global.params.objname && files.dim > 1)
if (global.params.objname && files.dim > 1 && !singleObj)
{
error("multiple source files, but only one .obj name");
fatal();

View File

@@ -30,6 +30,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Target/TargetData.h"
@@ -43,24 +44,40 @@ STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas");
STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas");
STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused");
namespace {
struct Analysis {
TargetData& TD;
const Module& M;
CallGraph* CG;
CallGraphNode* CGNode;
const Type* getTypeFor(Value* typeinfo) const;
};
}
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len) {
void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len,
const Analysis& A) {
Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty));
Module *M = B.GetInsertBlock()->getParent()->getParent();
const Type* Tys[1];
Tys[0] = Len->getType();
Value *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1);
Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1);
Value *Align = ConstantInt::get(Type::Int32Ty, 1);
B.CreateCall4(MemSet, Dst, Val, Len, Align);
CallSite CS = B.CreateCall4(MemSet, Dst, Val, Len, Align);
if (A.CGNode)
A.CGNode->addCalledFunction(CS, A.CG->getOrInsertFunction(MemSet));
}
static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) {
EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len);
static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len,
const Analysis& A) {
EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len, A);
}
@@ -69,13 +86,6 @@ static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) {
//===----------------------------------------------------------------------===//
namespace {
struct Analysis {
TargetData& TD;
const Module& M;
const Type* getTypeFor(Value* typeinfo) const;
};
class FunctionInfo {
protected:
const Type* Ty;
@@ -174,7 +184,7 @@ namespace {
// Use the original B to put initialization at the
// allocation site.
Value* Size = B.CreateMul(TypeSize, arrSize);
EmitMemZero(B, alloca, Size);
EmitMemZero(B, alloca, Size, A);
}
return alloca;
@@ -252,6 +262,7 @@ namespace {
bool doInitialization(Module &M) {
this->M = &M;
return false;
}
bool runOnFunction(Function &F);
@@ -259,6 +270,7 @@ namespace {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
AU.addRequired<LoopInfo>();
AU.addPreserved<CallGraph>();
}
};
char GarbageCollect2Stack::ID = 0;
@@ -284,8 +296,9 @@ GarbageCollect2Stack::GarbageCollect2Stack()
KnownFunctions["_d_allocclass"] = &AllocClass;
}
static void RemoveCall(Instruction* Inst) {
if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) {
static void RemoveCall(CallSite CS, const Analysis& A) {
if (CS.isInvoke()) {
InvokeInst* Invoke = cast<InvokeInst>(CS.getInstruction());
// If this was an invoke instruction, we need to do some extra
// work to preserve the control flow.
@@ -296,7 +309,9 @@ static void RemoveCall(Instruction* Inst) {
BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent());
}
// Remove the runtime call.
Inst->eraseFromParent();
if (A.CGNode)
A.CGNode->removeCallEdgeFor(CS);
CS.getInstruction()->eraseFromParent();
}
/// runOnFunction - Top level algorithm.
@@ -306,8 +321,10 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
TargetData &TD = getAnalysis<TargetData>();
const LoopInfo &LI = getAnalysis<LoopInfo>();
CallGraph* CG = getAnalysisIfAvailable<CallGraph>();
CallGraphNode* CGNode = CG ? (*CG)[&F] : NULL;
Analysis A = { TD, *M };
Analysis A = { TD, *M, CG, CGNode };
BasicBlock& Entry = F.getEntryBlock();
@@ -351,7 +368,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
if (Inst->use_empty() && info->SafeToDelete) {
Changed = true;
NumDeleted++;
RemoveCall(Inst);
RemoveCall(CS, A);
continue;
}
@@ -374,7 +391,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
newVal = Builder.CreateBitCast(newVal, Inst->getType());
Inst->replaceAllUsesWith(newVal);
RemoveCall(Inst);
RemoveCall(CS, A);
}
}

View File

@@ -76,7 +76,7 @@ void RTTIBuilder::push_void_array(uint64_t dim, llvm::Constant* ptr)
void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* mangle_sym)
{
std::string initname(mangle_sym->mangle());
initname.append(".rtti.void[].data");
initname.append(".rtti.voidarr.data");
LLGlobalVariable* G = new llvm::GlobalVariable(
CI->getType(), true, TYPEINFO_LINKAGE_TYPE, CI, initname, gIR->module);
@@ -87,9 +87,14 @@ void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* ma
void RTTIBuilder::push_array(llvm::Constant * CI, uint64_t dim, Type* valtype, Dsymbol * mangle_sym)
{
std::string initname(mangle_sym?mangle_sym->mangle():".ldc");
std::string tmpStr(valtype->arrayOf()->toChars());
tmpStr.erase( remove( tmpStr.begin(), tmpStr.end(), '[' ), tmpStr.end() );
tmpStr.erase( remove( tmpStr.begin(), tmpStr.end(), ']' ), tmpStr.end() );
tmpStr.append("arr");
std::string initname(mangle_sym?mangle_sym->mangle():".ldc");
initname.append(".rtti.");
initname.append(valtype->arrayOf()->toChars());
initname.append(tmpStr);
initname.append(".data");
LLGlobalVariable* G = new llvm::GlobalVariable(

View File

@@ -322,7 +322,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
// add attrs for hidden ptr
Attr.Index = 1;
Attr.Attrs = tf->fty.arg_sret->attrs;
assert((Attr.Attrs & llvm::Attribute::StructRet) && "Sret arg not sret?");
assert((Attr.Attrs & (llvm::Attribute::StructRet | llvm::Attribute::InReg))
&& "Sret arg not sret or inreg?");
attrs.push_back(Attr);
}

View File

@@ -1134,22 +1134,8 @@ DValue* DotVarExp::toElem(IRState* p)
assert(funcval);
}
else {
assert(fdecl->vtblIndex > 0);
assert(e1type->ty == Tclass);
LLValue* zero = DtoConstUint(0);
size_t vtblidx = fdecl->vtblIndex;
if (Logger::enabled())
Logger::cout() << "vthis: " << *vthis << '\n';
funcval = DtoGEP(vthis, zero, zero);
funcval = DtoLoad(funcval);
Logger::println("vtblidx = %lu", vtblidx);
funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars());
funcval = DtoLoad(funcval);
funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type)));
if (Logger::enabled())
Logger::cout() << "funcval casted: " << *funcval << '\n';
DImValue vthis3(e1type, vthis);
funcval = DtoVirtualFunctionPointer(&vthis3, fdecl, toChars());
}
return new DFuncValue(fdecl, funcval, vthis2);
@@ -2031,7 +2017,7 @@ DValue* DelegateExp::toElem(IRState* p)
LLValue* castfptr;
if (func->isVirtual() && !func->isFinal())
castfptr = DtoVirtualFunctionPointer(u, func);
castfptr = DtoVirtualFunctionPointer(u, func, toChars());
else if (func->isAbstract())
assert(0 && "TODO delegate to abstract method");
else if (func->toParent()->isInterfaceDeclaration())