Added support for using a temporary to implement emulated ABI return from inline asm, could be easier to use, but I think this will do. It's so extremely target dependent in any case that doing a completely generic approach seems hard.

This commit is contained in:
Tomas Lindquist Olsen
2009-02-14 15:25:48 +01:00
parent 3e17a21e0b
commit 4dee095dc3
3 changed files with 31 additions and 2 deletions

View File

@@ -629,7 +629,7 @@ void AsmBlockStatement::toIR(IRState* p)
}
remap_inargs(a->code, inn+a->out.size(), asmIdx);
if (!code.empty())
code += " ; ";
code += "\n\t";
code += a->code;
}
asmblock->s.clear();
@@ -671,8 +671,13 @@ void AsmBlockStatement::toIR(IRState* p)
args.insert(args.end(), outargs.begin(), outargs.end());
args.insert(args.end(), inargs.begin(), inargs.end());
llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), "");
// capture abi return value
if (useabiret)
{
if (p->asmBlock->retemu)
p->asmBlock->asmBlock->abiret = DtoLoad(p->asmBlock->asmBlock->abiret);
else
p->asmBlock->asmBlock->abiret = call;
}

View File

@@ -88,8 +88,9 @@ struct IRAsmBlock
AsmBlockStatement* asmBlock;
const LLType* retty;
unsigned retn;
bool retemu; // emulate abi ret with a temporary
IRAsmBlock(AsmBlockStatement* b) : asmBlock(b), retty(NULL), retn(0) {}
IRAsmBlock(AsmBlockStatement* b) : asmBlock(b), retty(NULL), retn(0), retemu(false) {}
};
// llvm::CallInst and llvm::InvokeInst don't share a common base

View File

@@ -207,6 +207,29 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
{
as->out_c = "={ax},={dx},";
asmblock->retn = 2;
#if 0
// this is to show how to allocate a temporary for the return value
// in case the appropriate multi register constraint isn't supported.
// this way abi return from inline asm can still be emulated.
// generate asm
as->out_c = "=*m,=*m,";
LLValue* tmp = DtoAlloca(llretTy, ".tmp_asm_ret");
as->out.push_back( tmp );
as->out.push_back( DtoGEPi(tmp, 0,1) );
as->code = "movd %eax, $<<out0>>" "\n\t" "mov %edx, $<<out1>>";
// fix asmblock
asmblock->retn = 0;
asmblock->retemu = true;
asmblock->asmBlock->abiret = tmp;
// add "ret" stmt
asmblock->s.push_back(as);
// done, we don't want anything pushed in the front of the block
return;
#endif
}
else
{