diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index b1e22f6c..e771648e 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -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; } diff --git a/gen/irstate.h b/gen/irstate.h index 897e9acf..e2e10bb4 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -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 diff --git a/gen/naked.cpp b/gen/naked.cpp index 3e672445..b7e182fa 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -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, $<>" "\n\t" "mov %edx, $<>"; + + // 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 {