mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-21 23:33:13 +01:00
[svn r323] Branching out of inline asm works.
Renamed emit_finallyblocks to DtoFinallyBlocks and moved to llvmhelpers. Added enclosingtryfinally to AsmBlockStatement, so branches out of asm blocks respect finallys. Refactored some GotoStatement code into DtoGoto.
This commit is contained in:
@@ -794,14 +794,17 @@ struct AsmStatement : Statement
|
||||
|
||||
// LLVMDC
|
||||
// non-zero if this is a branch, contains the target
|
||||
Identifier* isBranchToLabel;
|
||||
LabelDsymbol* isBranchToLabel;
|
||||
};
|
||||
|
||||
struct AsmBlockStatement : CompoundStatement
|
||||
{
|
||||
TryFinallyStatement *enclosingtryfinally;
|
||||
|
||||
AsmBlockStatement(Loc loc, Statements *s);
|
||||
Statements *flatten(Scope *sc);
|
||||
Statement *syntaxCopy();
|
||||
Statement *semantic(Scope *sc);
|
||||
|
||||
CompoundStatement *isCompoundStatement() { return NULL; }
|
||||
AsmBlockStatement *isAsmBlockStatement() { return this; }
|
||||
|
||||
147
gen/asmstmt.cpp
147
gen/asmstmt.cpp
@@ -26,6 +26,7 @@
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
|
||||
typedef enum {
|
||||
Arg_Integer,
|
||||
@@ -444,6 +445,7 @@ assert(0);
|
||||
AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
|
||||
: CompoundStatement(loc, s)
|
||||
{
|
||||
enclosingtryfinally = NULL;
|
||||
}
|
||||
|
||||
// rewrite argument indices to the block scope indices
|
||||
@@ -464,10 +466,10 @@ static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx)
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
needle = prefix + digits[i] + suffix;
|
||||
size_t pos = insnt.find(needle);
|
||||
if(pos != std::string::npos) {
|
||||
if(std::string::npos != pos)
|
||||
sprintf(buf, "%u", idx++);
|
||||
while(std::string::npos != (pos = insnt.find(needle)))
|
||||
insnt.replace(pos, needle.size(), buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,10 +491,10 @@ static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx)
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
needle = prefix + digits[i] + suffix;
|
||||
size_t pos = insnt.find(needle);
|
||||
if(pos != std::string::npos) {
|
||||
if(std::string::npos != pos)
|
||||
sprintf(buf, "%u", idx++);
|
||||
while(std::string::npos != (pos = insnt.find(needle)))
|
||||
insnt.replace(pos, needle.size(), buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,54 +524,73 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||
// to a unique value that will identify the jump target in
|
||||
// a post-asm switch
|
||||
|
||||
// create storage for and initialize the temporary
|
||||
llvm::AllocaInst* jump_target = new llvm::AllocaInst(llvm::IntegerType::get(32), "__llvm_jump_target", p->topallocapoint());
|
||||
gIR->ir->CreateStore(llvm::ConstantInt::get(llvm::IntegerType::get(32), 0), jump_target);
|
||||
// maps each special value to a goto destination
|
||||
std::map<int, LabelDsymbol*> valToGoto;
|
||||
|
||||
IRAsmStmt* outSetterStmt = new IRAsmStmt;
|
||||
std::string asmGotoEnd = "jmp __llvm_asm_end ; ";
|
||||
outSetterStmt->code = asmGotoEnd;
|
||||
outSetterStmt->out_c = "=*m,";
|
||||
outSetterStmt->out.push_back(jump_target);
|
||||
// location of the value containing the index into the valToGoto map
|
||||
// will be set if post-asm dispatcher block is needed
|
||||
llvm::AllocaInst* jump_target;
|
||||
|
||||
int n_goto = 1;
|
||||
|
||||
size_t n = asmblock->s.size();
|
||||
for(size_t i=0; i<n; ++i)
|
||||
{
|
||||
IRAsmStmt* a = asmblock->s[i];
|
||||
// initialize the setter statement we're going to build
|
||||
IRAsmStmt* outSetterStmt = new IRAsmStmt;
|
||||
std::string asmGotoEnd = "jmp __llvm_asm_end ; ";
|
||||
std::ostringstream code;
|
||||
code << asmGotoEnd;
|
||||
|
||||
// skip non-branch statements
|
||||
if(!a->isBranchToLabel)
|
||||
continue;
|
||||
int n_goto = 1;
|
||||
|
||||
// if internal, no special handling is necessary, skip
|
||||
std::vector<Identifier*>::const_iterator it, end;
|
||||
end = asmblock->internalLabels.end();
|
||||
bool skip = false;
|
||||
for(it = asmblock->internalLabels.begin(); it != end; ++it)
|
||||
if((*it)->equals(a->isBranchToLabel))
|
||||
skip = true;
|
||||
if(skip)
|
||||
continue;
|
||||
size_t n = asmblock->s.size();
|
||||
for(size_t i=0; i<n; ++i)
|
||||
{
|
||||
IRAsmStmt* a = asmblock->s[i];
|
||||
|
||||
// provide an in-asm target for the branch and set value
|
||||
Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->string);
|
||||
outSetterStmt->code += a->isBranchToLabel->string;
|
||||
outSetterStmt->code += ": ; ";
|
||||
outSetterStmt->code += "movl $<<in1>>, $<<out0>> ; ";
|
||||
//FIXME: Store the value -> label mapping somewhere, so it can be referenced later
|
||||
outSetterStmt->in.push_back(llvm::ConstantInt::get(llvm::IntegerType::get(32), n_goto++));
|
||||
outSetterStmt->in_c += "i,";
|
||||
outSetterStmt->code += asmGotoEnd;
|
||||
// skip non-branch statements
|
||||
if(!a->isBranchToLabel)
|
||||
continue;
|
||||
|
||||
// if internal, no special handling is necessary, skip
|
||||
std::vector<Identifier*>::const_iterator it, end;
|
||||
end = asmblock->internalLabels.end();
|
||||
bool skip = false;
|
||||
for(it = asmblock->internalLabels.begin(); it != end; ++it)
|
||||
if((*it)->equals(a->isBranchToLabel->ident))
|
||||
skip = true;
|
||||
if(skip)
|
||||
continue;
|
||||
|
||||
// record that the jump needs to be handled in the post-asm dispatcher
|
||||
valToGoto[n_goto] = a->isBranchToLabel;
|
||||
|
||||
// provide an in-asm target for the branch and set value
|
||||
Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->ident->string);
|
||||
code << a->isBranchToLabel->ident->string << ": ; ";
|
||||
code << "movl $<<in" << n_goto << ">>, $<<out0>> ; ";
|
||||
//FIXME: Store the value -> label mapping somewhere, so it can be referenced later
|
||||
outSetterStmt->in.push_back(llvm::ConstantInt::get(llvm::IntegerType::get(32), n_goto));
|
||||
outSetterStmt->in_c += "i,";
|
||||
code << asmGotoEnd;
|
||||
|
||||
++n_goto;
|
||||
}
|
||||
if(code.str() != asmGotoEnd)
|
||||
{
|
||||
// finalize code
|
||||
outSetterStmt->code = code.str();
|
||||
outSetterStmt->code += "__llvm_asm_end: ; ";
|
||||
|
||||
// create storage for and initialize the temporary
|
||||
jump_target = new llvm::AllocaInst(llvm::IntegerType::get(32), "__llvm_jump_target", p->topallocapoint());
|
||||
gIR->ir->CreateStore(llvm::ConstantInt::get(llvm::IntegerType::get(32), 0), jump_target);
|
||||
// setup variable for output from asm
|
||||
outSetterStmt->out_c = "=*m,";
|
||||
outSetterStmt->out.push_back(jump_target);
|
||||
|
||||
asmblock->s.push_back(outSetterStmt);
|
||||
}
|
||||
else
|
||||
delete outSetterStmt;
|
||||
}
|
||||
if(outSetterStmt->code != asmGotoEnd)
|
||||
{
|
||||
outSetterStmt->code += "__llvm_asm_end: ; ";
|
||||
asmblock->s.push_back(outSetterStmt);
|
||||
}
|
||||
else
|
||||
delete outSetterStmt;
|
||||
|
||||
|
||||
// build asm block
|
||||
@@ -583,7 +604,7 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||
std::string code;
|
||||
size_t asmIdx = 0;
|
||||
|
||||
n = asmblock->s.size();
|
||||
size_t n = asmblock->s.size();
|
||||
for (size_t i=0; i<n; ++i)
|
||||
{
|
||||
IRAsmStmt* a = asmblock->s[i];
|
||||
@@ -653,7 +674,31 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||
p->asmBlock = NULL;
|
||||
Logger::println("END ASM");
|
||||
|
||||
//FIXME: Emit goto forwarder code here
|
||||
// if asm contained external branches, emit goto forwarder code
|
||||
if(!valToGoto.empty())
|
||||
{
|
||||
assert(jump_target);
|
||||
|
||||
// make new blocks
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterasmgotoforwarder", p->topfunc(), oldend);
|
||||
|
||||
llvm::LoadInst* val = p->ir->CreateLoad(jump_target, "__llvm_jump_target_value");
|
||||
llvm::SwitchInst* sw = p->ir->CreateSwitch(val, bb, valToGoto.size());
|
||||
|
||||
// add all cases
|
||||
std::map<int, LabelDsymbol*>::iterator it, end = valToGoto.end();
|
||||
for(it = valToGoto.begin(); it != end; ++it)
|
||||
{
|
||||
llvm::BasicBlock* casebb = llvm::BasicBlock::Create("case", p->topfunc(), bb);
|
||||
sw->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(32), it->first), casebb);
|
||||
|
||||
p->scope() = IRScope(casebb,bb);
|
||||
DtoGoto(&loc, it->second, enclosingtryfinally);
|
||||
}
|
||||
|
||||
p->scope() = IRScope(bb,oldend);
|
||||
}
|
||||
}
|
||||
|
||||
// the whole idea of this statement is to avoid the flattening
|
||||
@@ -676,3 +721,11 @@ Statement *AsmBlockStatement::syntaxCopy()
|
||||
AsmBlockStatement *cs = new AsmBlockStatement(loc, a);
|
||||
return cs;
|
||||
}
|
||||
|
||||
// necessary for in-asm branches
|
||||
Statement *AsmBlockStatement::semantic(Scope *sc)
|
||||
{
|
||||
enclosingtryfinally = sc->tfOfTry;
|
||||
|
||||
return CompoundStatement::semantic(sc);
|
||||
}
|
||||
|
||||
@@ -1915,7 +1915,7 @@ struct AsmProcessor
|
||||
if (! lbl->asmLabelNum)
|
||||
lbl->asmLabelNum = ++d_priv_asm_label_serial;
|
||||
|
||||
stmt->isBranchToLabel = lbl->ident;
|
||||
stmt->isBranchToLabel = lbl;
|
||||
|
||||
use_star = false;
|
||||
addLabel(lbl->ident->toChars());
|
||||
|
||||
@@ -73,8 +73,8 @@ struct IRAsmStmt
|
||||
std::vector<LLValue*> out;
|
||||
std::vector<LLValue*> in;
|
||||
|
||||
// if this is nonzero, it contains the target ident
|
||||
Identifier* isBranchToLabel;
|
||||
// if this is nonzero, it contains the target label
|
||||
LabelDsymbol* isBranchToLabel;
|
||||
};
|
||||
|
||||
struct IRAsmBlock
|
||||
|
||||
@@ -150,6 +150,54 @@ void DtoAssert(Loc* loc, DValue* msg)
|
||||
gIR->ir->CreateUnreachable();
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GOTO HELPER
|
||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||
void DtoGoto(Loc* loc, LabelDsymbol* target, TryFinallyStatement* enclosingtryfinally)
|
||||
{
|
||||
assert(!gIR->scopereturned());
|
||||
|
||||
if (target->statement->llvmBB == NULL)
|
||||
target->statement->llvmBB = llvm::BasicBlock::Create("label", gIR->topfunc());
|
||||
|
||||
// find finallys between goto and label
|
||||
TryFinallyStatement* endfinally = enclosingtryfinally;
|
||||
while(endfinally != NULL && endfinally != target->statement->enclosingtryfinally) {
|
||||
endfinally = endfinally->enclosingtryfinally;
|
||||
}
|
||||
|
||||
// error if didn't find tf statement of label
|
||||
if(endfinally != target->statement->enclosingtryfinally)
|
||||
error("cannot goto into try block", loc->toChars());
|
||||
|
||||
// emit code for finallys between goto and label
|
||||
DtoFinallyBlocks(enclosingtryfinally, endfinally);
|
||||
|
||||
llvm::BranchInst::Create(target->statement->llvmBB, gIR->scopebb());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TRY FINALLY HELPER
|
||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||
void DtoFinallyBlocks(TryFinallyStatement* start, TryFinallyStatement* end)
|
||||
{
|
||||
// verify that end encloses start
|
||||
TryFinallyStatement* endfinally = start;
|
||||
while(endfinally != NULL && endfinally != end) {
|
||||
endfinally = endfinally->enclosingtryfinally;
|
||||
}
|
||||
assert(endfinally == end);
|
||||
|
||||
// emit code for finallys between start and end
|
||||
TryFinallyStatement* tf = start;
|
||||
while(tf != end) {
|
||||
tf->finalbody->toIR(gIR);
|
||||
tf = tf->enclosingtryfinally;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NESTED VARIABLE HELPERS
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef LLVMDC_GEN_LLVMHELPERS_H
|
||||
#define LLVMDC_GEN_LLVMHELPERS_H
|
||||
|
||||
#include "statement.h"
|
||||
|
||||
// dynamic memory helpers
|
||||
LLValue* DtoNew(Type* newtype);
|
||||
void DtoDeleteMemory(LLValue* ptr);
|
||||
@@ -11,6 +13,14 @@ void DtoDeleteArray(DValue* arr);
|
||||
// assertion generator
|
||||
void DtoAssert(Loc* loc, DValue* msg);
|
||||
|
||||
// emit goto
|
||||
void DtoGoto(Loc* loc, LabelDsymbol* target, TryFinallyStatement* enclosingtryfinally);
|
||||
|
||||
// generates IR for finally blocks between the 'start' and 'end' statements
|
||||
// will begin with the finally block belonging to 'start' and does not include
|
||||
// the finally block of 'end'
|
||||
void DtoFinallyBlocks(TryFinallyStatement* start, TryFinallyStatement* end);
|
||||
|
||||
// nested variable/class helpers
|
||||
LLValue* DtoNestedContext(FuncDeclaration* func);
|
||||
LLValue* DtoNestedVariable(VarDeclaration* vd);
|
||||
|
||||
@@ -44,27 +44,6 @@ void CompoundStatement::toIR(IRState* p)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// generates IR for finally blocks between the 'start' and 'end' statements
|
||||
// will begin with the finally block belonging to 'start' and does not include
|
||||
// the finally block of 'end'
|
||||
void emit_finallyblocks(IRState* p, TryFinallyStatement* start, TryFinallyStatement* end)
|
||||
{
|
||||
// verify that end encloses start
|
||||
TryFinallyStatement* endfinally = start;
|
||||
while(endfinally != NULL && endfinally != end) {
|
||||
endfinally = endfinally->enclosingtryfinally;
|
||||
}
|
||||
assert(endfinally == end);
|
||||
|
||||
// emit code for finallys between start and end
|
||||
TryFinallyStatement* tf = start;
|
||||
while(tf != end) {
|
||||
tf->finalbody->toIR(p);
|
||||
tf = tf->enclosingtryfinally;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -91,7 +70,7 @@ void ReturnStatement::toIR(IRState* p)
|
||||
if (!e->inPlace())
|
||||
DtoAssign(rvar, e);
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, NULL);
|
||||
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
||||
|
||||
if (f->inVolatile) {
|
||||
// store-load barrier
|
||||
@@ -116,7 +95,7 @@ void ReturnStatement::toIR(IRState* p)
|
||||
Logger::cout() << "return value after cast: " << *v << '\n';
|
||||
}
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, NULL);
|
||||
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
||||
|
||||
if (gIR->func()->inVolatile) {
|
||||
// store-load barrier
|
||||
@@ -130,7 +109,7 @@ void ReturnStatement::toIR(IRState* p)
|
||||
else
|
||||
{
|
||||
assert(p->topfunc()->getReturnType() == LLType::VoidTy);
|
||||
emit_finallyblocks(p, enclosingtryfinally, NULL);
|
||||
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
||||
|
||||
if (gIR->func()->inVolatile) {
|
||||
// store-load barrier
|
||||
@@ -431,7 +410,7 @@ void BreakStatement::toIR(IRState* p)
|
||||
if (ident != 0) {
|
||||
Logger::println("ident = %s", ident->toChars());
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, target->enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally);
|
||||
|
||||
// get the loop statement the label refers to
|
||||
Statement* targetLoopStatement = target->statement;
|
||||
@@ -452,7 +431,7 @@ void BreakStatement::toIR(IRState* p)
|
||||
assert(found);
|
||||
}
|
||||
else {
|
||||
emit_finallyblocks(p, enclosingtryfinally, p->loopbbs.back().enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, p->loopbbs.back().enclosingtryfinally);
|
||||
llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb());
|
||||
}
|
||||
|
||||
@@ -475,7 +454,7 @@ void ContinueStatement::toIR(IRState* p)
|
||||
if (ident != 0) {
|
||||
Logger::println("ident = %s", ident->toChars());
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, target->enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally);
|
||||
|
||||
// get the loop statement the label refers to
|
||||
Statement* targetLoopStatement = target->statement;
|
||||
@@ -494,7 +473,7 @@ void ContinueStatement::toIR(IRState* p)
|
||||
assert(0);
|
||||
}
|
||||
else {
|
||||
emit_finallyblocks(p, enclosingtryfinally, gIR->loopbbs.back().enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, gIR->loopbbs.back().enclosingtryfinally);
|
||||
llvm::BranchInst::Create(gIR->loopbbs.back().begin, gIR->scopebb());
|
||||
}
|
||||
}
|
||||
@@ -1108,24 +1087,8 @@ void GotoStatement::toIR(IRState* p)
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend);
|
||||
|
||||
if (label->statement->llvmBB == NULL)
|
||||
label->statement->llvmBB = llvm::BasicBlock::Create("label", p->topfunc());
|
||||
assert(!p->scopereturned());
|
||||
DtoGoto(&loc, label, enclosingtryfinally);
|
||||
|
||||
// find finallys between goto and label
|
||||
TryFinallyStatement* endfinally = enclosingtryfinally;
|
||||
while(endfinally != NULL && endfinally != label->statement->enclosingtryfinally) {
|
||||
endfinally = endfinally->enclosingtryfinally;
|
||||
}
|
||||
|
||||
// error if didn't find tf statement of label
|
||||
if(endfinally != label->statement->enclosingtryfinally)
|
||||
error("cannot goto into try block", loc.toChars());
|
||||
|
||||
// emit code for finallys between goto and label
|
||||
emit_finallyblocks(p, enclosingtryfinally, endfinally);
|
||||
|
||||
llvm::BranchInst::Create(label->statement->llvmBB, p->scopebb());
|
||||
p->scope() = IRScope(bb,oldend);
|
||||
}
|
||||
|
||||
@@ -1145,7 +1108,7 @@ void GotoDefaultStatement::toIR(IRState* p)
|
||||
assert(!p->scopereturned());
|
||||
assert(sw->sdefault->bodyBB);
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, sw->enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally);
|
||||
|
||||
llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb());
|
||||
p->scope() = IRScope(bb,oldend);
|
||||
@@ -1170,7 +1133,7 @@ void GotoCaseStatement::toIR(IRState* p)
|
||||
cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend());
|
||||
}
|
||||
|
||||
emit_finallyblocks(p, enclosingtryfinally, sw->enclosingtryfinally);
|
||||
DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally);
|
||||
|
||||
llvm::BranchInst::Create(cs->bodyBB, p->scopebb());
|
||||
p->scope() = IRScope(bb,oldend);
|
||||
|
||||
Reference in New Issue
Block a user