mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 08:30:47 +03:00

Fixed problems with label collisions when using labels inside inline asm. LabelStatement is now easily reached given its Identifier, which should be useful elsewhere too. Enabled inline asm for building the lib/compiler/llvmdc runtime code, fixing branches out of asm makes this possible.
1287 lines
38 KiB
C++
1287 lines
38 KiB
C++
// Statements: D -> LLVM glue
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
#include "gen/llvm.h"
|
|
#include "llvm/InlineAsm.h"
|
|
#include "llvm/Support/CFG.h"
|
|
|
|
#include "mars.h"
|
|
#include "total.h"
|
|
#include "init.h"
|
|
#include "mtype.h"
|
|
#include "hdrgen.h"
|
|
#include "port.h"
|
|
|
|
#include "gen/irstate.h"
|
|
#include "gen/logger.h"
|
|
#include "gen/tollvm.h"
|
|
#include "gen/llvmhelpers.h"
|
|
#include "gen/runtime.h"
|
|
#include "gen/arrays.h"
|
|
#include "gen/todebug.h"
|
|
#include "gen/dvalue.h"
|
|
|
|
#include "ir/irfunction.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("CompoundStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
for (int i=0; i<statements->dim; i++)
|
|
{
|
|
Statement* s = (Statement*)statements->data[i];
|
|
if (s) {
|
|
s->toIR(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ReturnStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (exp)
|
|
{
|
|
if (p->topfunc()->getReturnType() == LLType::VoidTy) {
|
|
IrFunction* f = p->func();
|
|
assert(f->type->llvmRetInPtr);
|
|
assert(f->decl->ir.irFunc->retArg);
|
|
|
|
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
|
|
|
DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg, true);
|
|
|
|
p->exps.push_back(IRExp(NULL,exp,rvar));
|
|
DValue* e = exp->toElem(p);
|
|
p->exps.pop_back();
|
|
|
|
if (!e->inPlace())
|
|
DtoAssign(rvar, e);
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
|
|
|
if (f->inVolatile) {
|
|
// store-load barrier
|
|
DtoMemoryBarrier(false, false, true, false);
|
|
}
|
|
|
|
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
|
|
llvm::ReturnInst::Create(p->scopebb());
|
|
|
|
}
|
|
else {
|
|
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
|
DValue* e = exp->toElem(p);
|
|
LLValue* v = e->getRVal();
|
|
delete e;
|
|
Logger::cout() << "return value is '" <<*v << "'\n";
|
|
|
|
// can happen for classes
|
|
if (v->getType() != p->topfunc()->getReturnType())
|
|
{
|
|
v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp");
|
|
Logger::cout() << "return value after cast: " << *v << '\n';
|
|
}
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
|
|
|
if (gIR->func()->inVolatile) {
|
|
// store-load barrier
|
|
DtoMemoryBarrier(false, false, true, false);
|
|
}
|
|
|
|
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
|
llvm::ReturnInst::Create(v, p->scopebb());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(p->topfunc()->getReturnType() == LLType::VoidTy);
|
|
DtoFinallyBlocks(enclosingtryfinally, NULL);
|
|
|
|
if (gIR->func()->inVolatile) {
|
|
// store-load barrier
|
|
DtoMemoryBarrier(false, false, true, false);
|
|
}
|
|
|
|
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
|
llvm::ReturnInst::Create(p->scopebb());
|
|
}
|
|
|
|
// the return terminated this basicblock, start a new one
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterreturn", p->topfunc(), oldend);
|
|
p->scope() = IRScope(bb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ExpStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ExpStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
if (exp) {
|
|
if (global.params.llvmAnnotate)
|
|
DtoAnnotation(exp->toChars());
|
|
elem* e = exp->toElem(p);
|
|
delete e;
|
|
}
|
|
/*elem* e = exp->toElem(p);
|
|
p->buf.printf("%s", e->toChars());
|
|
delete e;
|
|
p->buf.writenl();*/
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void IfStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("IfStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
if (match)
|
|
{
|
|
LLValue* allocainst = new llvm::AllocaInst(DtoType(match->type), "._tmp_if_var", p->topallocapoint());
|
|
match->ir.irLocal = new IrLocal(match);
|
|
match->ir.irLocal->value = allocainst;
|
|
}
|
|
|
|
DValue* cond_e = condition->toElem(p);
|
|
LLValue* cond_val = cond_e->getRVal();
|
|
delete cond_e;
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
|
|
llvm::BasicBlock* ifbb = llvm::BasicBlock::Create("if", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endif", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* elsebb = elsebody ? llvm::BasicBlock::Create("else", gIR->topfunc(), endbb) : endbb;
|
|
|
|
if (cond_val->getType() != LLType::Int1Ty) {
|
|
Logger::cout() << "if conditional: " << *cond_val << '\n';
|
|
cond_val = DtoBoolean(cond_val);
|
|
}
|
|
LLValue* ifgoback = llvm::BranchInst::Create(ifbb, elsebb, cond_val, gIR->scopebb());
|
|
|
|
// replace current scope
|
|
gIR->scope() = IRScope(ifbb,elsebb);
|
|
|
|
// do scoped statements
|
|
if (ifbody)
|
|
ifbody->toIR(p);
|
|
if (!gIR->scopereturned()) {
|
|
llvm::BranchInst::Create(endbb,gIR->scopebb());
|
|
}
|
|
|
|
if (elsebody) {
|
|
//assert(0);
|
|
gIR->scope() = IRScope(elsebb,endbb);
|
|
elsebody->toIR(p);
|
|
if (!gIR->scopereturned()) {
|
|
llvm::BranchInst::Create(endbb,gIR->scopebb());
|
|
}
|
|
}
|
|
|
|
// rewrite the scope
|
|
gIR->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ScopeStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ScopeStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
/*llvm::BasicBlock* oldend = p->scopeend();
|
|
|
|
llvm::BasicBlock* beginbb = 0;
|
|
|
|
// remove useless branches by clearing and reusing the current basicblock
|
|
llvm::BasicBlock* bb = p->scopebb();
|
|
if (bb->empty()) {
|
|
beginbb = bb;
|
|
}
|
|
else {
|
|
beginbb = llvm::BasicBlock::Create("scope", p->topfunc(), oldend);
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(beginbb, bb);
|
|
}
|
|
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endscope", p->topfunc(), oldend);
|
|
if (beginbb != bb)
|
|
p->scope() = IRScope(beginbb, endbb);
|
|
else
|
|
p->scope().end = endbb;*/
|
|
|
|
if (statement)
|
|
statement->toIR(p);
|
|
|
|
/*p->scope().end = oldend;
|
|
Logger::println("Erasing scope endbb");
|
|
endbb->eraseFromParent();*/
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void WhileStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("WhileStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// create while blocks
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* whilebb = llvm::BasicBlock::Create("whilecond", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* whilebodybb = llvm::BasicBlock::Create("whilebody", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endwhile", gIR->topfunc(), oldend);
|
|
|
|
// move into the while block
|
|
p->ir->CreateBr(whilebb);
|
|
//llvm::BranchInst::Create(whilebb, gIR->scopebb());
|
|
|
|
// replace current scope
|
|
gIR->scope() = IRScope(whilebb,endbb);
|
|
|
|
// create the condition
|
|
DValue* cond_e = condition->toElem(p);
|
|
LLValue* cond_val = DtoBoolean(cond_e->getRVal());
|
|
delete cond_e;
|
|
|
|
// conditional branch
|
|
LLValue* ifbreak = llvm::BranchInst::Create(whilebodybb, endbb, cond_val, p->scopebb());
|
|
|
|
// rewrite scope
|
|
gIR->scope() = IRScope(whilebodybb,endbb);
|
|
|
|
// while body code
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,whilebb,endbb));
|
|
body->toIR(p);
|
|
p->loopbbs.pop_back();
|
|
|
|
// loop
|
|
if (!gIR->scopereturned())
|
|
llvm::BranchInst::Create(whilebb, gIR->scopebb());
|
|
|
|
// rewrite the scope
|
|
gIR->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DoStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("DoStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// create while blocks
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* dowhilebb = llvm::BasicBlock::Create("dowhile", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("enddowhile", gIR->topfunc(), oldend);
|
|
|
|
// move into the while block
|
|
assert(!gIR->scopereturned());
|
|
llvm::BranchInst::Create(dowhilebb, gIR->scopebb());
|
|
|
|
// replace current scope
|
|
gIR->scope() = IRScope(dowhilebb,endbb);
|
|
|
|
// do-while body code
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,dowhilebb,endbb));
|
|
body->toIR(p);
|
|
p->loopbbs.pop_back();
|
|
|
|
// create the condition
|
|
DValue* cond_e = condition->toElem(p);
|
|
LLValue* cond_val = DtoBoolean(cond_e->getRVal());
|
|
delete cond_e;
|
|
|
|
// conditional branch
|
|
LLValue* ifbreak = llvm::BranchInst::Create(dowhilebb, endbb, cond_val, gIR->scopebb());
|
|
|
|
// rewrite the scope
|
|
gIR->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ForStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ForStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// create for blocks
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* forbb = llvm::BasicBlock::Create("forcond", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* forbodybb = llvm::BasicBlock::Create("forbody", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* forincbb = llvm::BasicBlock::Create("forinc", gIR->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endfor", gIR->topfunc(), oldend);
|
|
|
|
// init
|
|
if (init != 0)
|
|
init->toIR(p);
|
|
|
|
// move into the for condition block, ie. start the loop
|
|
assert(!gIR->scopereturned());
|
|
llvm::BranchInst::Create(forbb, gIR->scopebb());
|
|
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,forincbb,endbb));
|
|
|
|
// replace current scope
|
|
gIR->scope() = IRScope(forbb,forbodybb);
|
|
|
|
// create the condition
|
|
DValue* cond_e = condition->toElem(p);
|
|
LLValue* cond_val = DtoBoolean(cond_e->getRVal());
|
|
delete cond_e;
|
|
|
|
// conditional branch
|
|
assert(!gIR->scopereturned());
|
|
llvm::BranchInst::Create(forbodybb, endbb, cond_val, gIR->scopebb());
|
|
|
|
// rewrite scope
|
|
gIR->scope() = IRScope(forbodybb,forincbb);
|
|
|
|
// do for body code
|
|
body->toIR(p);
|
|
|
|
// move into the for increment block
|
|
if (!gIR->scopereturned())
|
|
llvm::BranchInst::Create(forincbb, gIR->scopebb());
|
|
gIR->scope() = IRScope(forincbb, endbb);
|
|
|
|
// increment
|
|
if (increment) {
|
|
DValue* inc = increment->toElem(p);
|
|
delete inc;
|
|
}
|
|
|
|
// loop
|
|
if (!gIR->scopereturned())
|
|
llvm::BranchInst::Create(forbb, gIR->scopebb());
|
|
|
|
p->loopbbs.pop_back();
|
|
|
|
// rewrite the scope
|
|
gIR->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void BreakStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("BreakStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
// don't emit two terminators in a row
|
|
// happens just before DMD generated default statements if the last case terminates
|
|
if (p->scopereturned())
|
|
return;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
if (ident != 0) {
|
|
Logger::println("ident = %s", ident->toChars());
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally);
|
|
|
|
// get the loop statement the label refers to
|
|
Statement* targetLoopStatement = target->statement;
|
|
ScopeStatement* tmp;
|
|
while(tmp = targetLoopStatement->isScopeStatement())
|
|
targetLoopStatement = tmp->statement;
|
|
|
|
// find the right break block and jump there
|
|
bool found = false;
|
|
IRState::LoopScopeVec::reverse_iterator it;
|
|
for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) {
|
|
if(it->s == targetLoopStatement) {
|
|
llvm::BranchInst::Create(it->end, p->scopebb());
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
assert(found);
|
|
}
|
|
else {
|
|
DtoFinallyBlocks(enclosingtryfinally, p->loopbbs.back().enclosingtryfinally);
|
|
llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb());
|
|
}
|
|
|
|
// the break terminated this basicblock, start a new one
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterbreak", p->topfunc(), oldend);
|
|
p->scope() = IRScope(bb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ContinueStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
if (ident != 0) {
|
|
Logger::println("ident = %s", ident->toChars());
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally);
|
|
|
|
// get the loop statement the label refers to
|
|
Statement* targetLoopStatement = target->statement;
|
|
ScopeStatement* tmp;
|
|
while(tmp = targetLoopStatement->isScopeStatement())
|
|
targetLoopStatement = tmp->statement;
|
|
|
|
// find the right continue block and jump there
|
|
IRState::LoopScopeVec::reverse_iterator it;
|
|
for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
|
|
if(it->s == targetLoopStatement) {
|
|
llvm::BranchInst::Create(it->begin, gIR->scopebb());
|
|
return;
|
|
}
|
|
}
|
|
assert(0);
|
|
}
|
|
else {
|
|
DtoFinallyBlocks(enclosingtryfinally, gIR->loopbbs.back().enclosingtryfinally);
|
|
llvm::BranchInst::Create(gIR->loopbbs.back().begin, gIR->scopebb());
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void OnScopeStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("OnScopeStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
assert(statement);
|
|
//statement->toIR(p); // this seems to be redundant
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TryFinallyStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// create basic blocks
|
|
llvm::BasicBlock* oldend = p->scopeend();
|
|
|
|
llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend);
|
|
llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend);
|
|
|
|
// pass the previous BB into this
|
|
assert(!gIR->scopereturned());
|
|
llvm::BranchInst::Create(trybb, p->scopebb());
|
|
|
|
// do the try block
|
|
p->scope() = IRScope(trybb,finallybb);
|
|
|
|
assert(body);
|
|
body->toIR(p);
|
|
|
|
// terminate try BB
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(finallybb, p->scopebb());
|
|
|
|
// do finally block
|
|
p->scope() = IRScope(finallybb,endbb);
|
|
assert(finalbody);
|
|
finalbody->toIR(p);
|
|
|
|
// terminate finally
|
|
if (!gIR->scopereturned()) {
|
|
llvm::BranchInst::Create(endbb, p->scopebb());
|
|
}
|
|
|
|
// rewrite the scope
|
|
p->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TryCatchStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
Logger::attention(loc, "try-catch is not yet fully implemented");
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// create basic blocks
|
|
llvm::BasicBlock* oldend = p->scopeend();
|
|
|
|
llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend);
|
|
llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtrycatch", p->topfunc(), oldend);
|
|
|
|
// pass the previous BB into this
|
|
assert(!gIR->scopereturned());
|
|
llvm::BranchInst::Create(trybb, p->scopebb());
|
|
|
|
// do the try block
|
|
p->scope() = IRScope(trybb,catchbb);
|
|
assert(body);
|
|
body->toIR(p);
|
|
|
|
if (!gIR->scopereturned())
|
|
llvm::BranchInst::Create(endbb, p->scopebb());
|
|
|
|
// do catch
|
|
p->scope() = IRScope(catchbb,oldend);
|
|
llvm::BranchInst::Create(endbb, p->scopebb());
|
|
/*assert(catches);
|
|
for(size_t i=0; i<catches->dim; ++i)
|
|
{
|
|
Catch* c = (Catch*)catches->data[i];
|
|
c->handler->toIR(p);
|
|
}*/
|
|
|
|
// rewrite the scope
|
|
p->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ThrowStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
Logger::attention(loc, "throw is not yet fully implemented");
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
assert(exp);
|
|
DValue* e = exp->toElem(p);
|
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_throw_exception");
|
|
//Logger::cout() << "calling: " << *fn << '\n';
|
|
LLValue* arg = DtoBitCast(e->getRVal(), fn->getFunctionType()->getParamType(0));
|
|
//Logger::cout() << "arg: " << *arg << '\n';
|
|
gIR->ir->CreateCall(fn, arg, "");
|
|
gIR->ir->CreateUnreachable();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// used to build the sorted list of cases
|
|
struct Case : Object
|
|
{
|
|
StringExp* str;
|
|
size_t index;
|
|
|
|
Case(StringExp* s, size_t i) {
|
|
str = s;
|
|
index = i;
|
|
}
|
|
|
|
int compare(Object *obj) {
|
|
Case* c2 = (Case*)obj;
|
|
return str->compare(c2->str);
|
|
}
|
|
};
|
|
|
|
static LLValue* call_string_switch_runtime(llvm::GlobalVariable* table, Expression* e)
|
|
{
|
|
Type* dt = DtoDType(e->type);
|
|
Type* dtnext = DtoDType(dt->next);
|
|
TY ty = dtnext->ty;
|
|
const char* fname;
|
|
if (ty == Tchar) {
|
|
fname = "_d_switch_string";
|
|
}
|
|
else if (ty == Twchar) {
|
|
fname = "_d_switch_ustring";
|
|
}
|
|
else if (ty == Tdchar) {
|
|
fname = "_d_switch_dstring";
|
|
}
|
|
else {
|
|
assert(0 && "not char/wchar/dchar");
|
|
}
|
|
|
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);
|
|
|
|
Logger::cout() << *table->getType() << '\n';
|
|
Logger::cout() << *fn->getFunctionType()->getParamType(0) << '\n';
|
|
assert(table->getType() == fn->getFunctionType()->getParamType(0));
|
|
|
|
DValue* val = e->toElem(gIR);
|
|
LLValue* llval;
|
|
if (DSliceValue* sval = val->isSlice())
|
|
{
|
|
// give storage
|
|
llval = new llvm::AllocaInst(DtoType(e->type), "tmp", gIR->topallocapoint());
|
|
DVarValue* vv = new DVarValue(e->type, llval, true);
|
|
DtoAssign(vv, val);
|
|
}
|
|
else
|
|
{
|
|
llval = val->getRVal();
|
|
}
|
|
assert(llval->getType() == fn->getFunctionType()->getParamType(1));
|
|
|
|
llvm::CallInst* call = gIR->ir->CreateCall2(fn, table, llval, "tmp");
|
|
|
|
llvm::PAListPtr palist;
|
|
palist = palist.addAttr(1, llvm::ParamAttr::ByVal);
|
|
palist = palist.addAttr(2, llvm::ParamAttr::ByVal);
|
|
call->setParamAttrs(palist);
|
|
|
|
return call;
|
|
}
|
|
|
|
void SwitchStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
|
|
// clear data from previous passes... :/
|
|
for (int i=0; i<cases->dim; ++i)
|
|
{
|
|
CaseStatement* cs = (CaseStatement*)cases->data[i];
|
|
cs->bodyBB = NULL;
|
|
cs->llvmIdx = NULL;
|
|
}
|
|
|
|
// string switch?
|
|
llvm::GlobalVariable* switchTable = 0;
|
|
Array caseArray;
|
|
if (!condition->type->isintegral())
|
|
{
|
|
Logger::println("is string switch");
|
|
// build array of the stringexpS
|
|
caseArray.reserve(cases->dim);
|
|
for (int i=0; i<cases->dim; ++i)
|
|
{
|
|
CaseStatement* cs = (CaseStatement*)cases->data[i];
|
|
|
|
assert(cs->exp->op == TOKstring);
|
|
caseArray.push(new Case((StringExp*)cs->exp, i));
|
|
}
|
|
// first sort it
|
|
caseArray.sort();
|
|
// iterate and add indices to cases
|
|
std::vector<LLConstant*> inits(caseArray.dim);
|
|
for (size_t i=0; i<caseArray.dim; ++i)
|
|
{
|
|
Case* c = (Case*)caseArray.data[i];
|
|
CaseStatement* cs = (CaseStatement*)cases->data[c->index];
|
|
cs->llvmIdx = DtoConstUint(i);
|
|
inits[i] = c->str->toConstElem(p);
|
|
}
|
|
// build static array for ptr or final array
|
|
const LLType* elemTy = DtoType(condition->type);
|
|
const llvm::ArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size());
|
|
LLConstant* arrInit = llvm::ConstantArray::get(arrTy, inits);
|
|
llvm::GlobalVariable* arr = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, ".string_switch_table_data", gIR->module);
|
|
|
|
const LLType* elemPtrTy = getPtrToType(elemTy);
|
|
LLConstant* arrPtr = llvm::ConstantExpr::getBitCast(arr, elemPtrTy);
|
|
|
|
// build the static table
|
|
std::vector<const LLType*> types;
|
|
types.push_back(DtoSize_t());
|
|
types.push_back(elemPtrTy);
|
|
const llvm::StructType* sTy = llvm::StructType::get(types);
|
|
std::vector<LLConstant*> sinits;
|
|
sinits.push_back(DtoConstSize_t(inits.size()));
|
|
sinits.push_back(arrPtr);
|
|
LLConstant* sInit = llvm::ConstantStruct::get(sTy, sinits);
|
|
|
|
switchTable = new llvm::GlobalVariable(sTy, true, llvm::GlobalValue::InternalLinkage, sInit, ".string_switch_table", gIR->module);
|
|
}
|
|
|
|
// body block
|
|
llvm::BasicBlock* bodybb = llvm::BasicBlock::Create("switchbody", p->topfunc(), oldend);
|
|
|
|
// default
|
|
llvm::BasicBlock* defbb = 0;
|
|
if (sdefault) {
|
|
Logger::println("has default");
|
|
defbb = llvm::BasicBlock::Create("default", p->topfunc(), oldend);
|
|
sdefault->bodyBB = defbb;
|
|
}
|
|
|
|
// end (break point)
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("switchend", p->topfunc(), oldend);
|
|
|
|
// condition var
|
|
LLValue* condVal;
|
|
// integral switch
|
|
if (condition->type->isintegral()) {
|
|
DValue* cond = condition->toElem(p);
|
|
condVal = cond->getRVal();
|
|
}
|
|
// string switch
|
|
else {
|
|
condVal = call_string_switch_runtime(switchTable, condition);
|
|
}
|
|
llvm::SwitchInst* si = llvm::SwitchInst::Create(condVal, defbb ? defbb : endbb, cases->dim, p->scopebb());
|
|
|
|
// do switch body
|
|
assert(body);
|
|
|
|
p->scope() = IRScope(bodybb, endbb);
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb));
|
|
body->toIR(p);
|
|
p->loopbbs.pop_back();
|
|
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(endbb, p->scopebb());
|
|
|
|
// add the cases
|
|
for (int i=0; i<cases->dim; ++i)
|
|
{
|
|
CaseStatement* cs = (CaseStatement*)cases->data[i];
|
|
si->addCase(cs->llvmIdx, cs->bodyBB);
|
|
}
|
|
|
|
gIR->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void CaseStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("CaseStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
llvm::BasicBlock* nbb = llvm::BasicBlock::Create("case", p->topfunc(), p->scopeend());
|
|
|
|
if (bodyBB && !bodyBB->getTerminator())
|
|
{
|
|
llvm::BranchInst::Create(nbb, bodyBB);
|
|
}
|
|
bodyBB = nbb;
|
|
|
|
if (llvmIdx == NULL) {
|
|
LLConstant* c = exp->toConstElem(p);
|
|
llvmIdx = isaConstantInt(c);
|
|
}
|
|
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(bodyBB, p->scopebb());
|
|
|
|
p->scope() = IRScope(bodyBB, p->scopeend());
|
|
|
|
assert(statement);
|
|
statement->toIR(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void DefaultStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("DefaultStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
assert(bodyBB);
|
|
|
|
llvm::BasicBlock* nbb = llvm::BasicBlock::Create("default", p->topfunc(), p->scopeend());
|
|
|
|
if (!bodyBB->getTerminator())
|
|
{
|
|
llvm::BranchInst::Create(nbb, bodyBB);
|
|
}
|
|
bodyBB = nbb;
|
|
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(bodyBB, p->scopebb());
|
|
|
|
p->scope() = IRScope(bodyBB, p->scopeend());
|
|
|
|
assert(statement);
|
|
statement->toIR(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UnrolledLoopStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("UnrolledLoopStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("unrolledend", p->topfunc(), oldend);
|
|
|
|
p->scope() = IRScope(p->scopebb(),endbb);
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb));
|
|
|
|
for (int i=0; i<statements->dim; ++i)
|
|
{
|
|
Statement* s = (Statement*)statements->data[i];
|
|
s->toIR(p);
|
|
}
|
|
|
|
p->loopbbs.pop_back();
|
|
|
|
llvm::BranchInst::Create(endbb, p->scopebb());
|
|
p->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ForeachStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("ForeachStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
//assert(arguments->dim == 1);
|
|
assert(value != 0);
|
|
assert(body != 0);
|
|
assert(aggr != 0);
|
|
assert(func != 0);
|
|
|
|
//Argument* arg = (Argument*)arguments->data[0];
|
|
//Logger::println("Argument is %s", arg->toChars());
|
|
|
|
Logger::println("aggr = %s", aggr->toChars());
|
|
|
|
// key
|
|
const LLType* keytype = key ? DtoType(key->type) : DtoSize_t();
|
|
LLValue* keyvar = new llvm::AllocaInst(keytype, "foreachkey", p->topallocapoint());
|
|
if (key)
|
|
{
|
|
//key->llvmValue = keyvar;
|
|
assert(!key->ir.irLocal);
|
|
key->ir.irLocal = new IrLocal(key);
|
|
key->ir.irLocal->value = keyvar;
|
|
}
|
|
LLValue* zerokey = llvm::ConstantInt::get(keytype,0,false);
|
|
|
|
// value
|
|
Logger::println("value = %s", value->toPrettyChars());
|
|
const LLType* valtype = DtoType(value->type);
|
|
LLValue* valvar = NULL;
|
|
if (!value->isRef() && !value->isOut())
|
|
valvar = new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint());
|
|
if (!value->ir.irLocal)
|
|
value->ir.irLocal = new IrLocal(value);
|
|
|
|
// what to iterate
|
|
DValue* aggrval = aggr->toElem(p);
|
|
Type* aggrtype = DtoDType(aggr->type);
|
|
|
|
// get length and pointer
|
|
LLValue* val = 0;
|
|
LLValue* niters = 0;
|
|
|
|
// static array
|
|
if (aggrtype->ty == Tsarray)
|
|
{
|
|
Logger::println("foreach over static array");
|
|
val = aggrval->getRVal();
|
|
assert(isaPointer(val->getType()));
|
|
const llvm::ArrayType* arrty = isaArray(val->getType()->getContainedType(0));
|
|
assert(arrty);
|
|
size_t nelems = arrty->getNumElements();
|
|
if(nelems == 0)
|
|
return;
|
|
niters = llvm::ConstantInt::get(keytype,nelems,false);
|
|
}
|
|
// dynamic array
|
|
else if (aggrtype->ty == Tarray)
|
|
{
|
|
if (DSliceValue* slice = aggrval->isSlice()) {
|
|
Logger::println("foreach over slice");
|
|
niters = slice->len;
|
|
assert(niters);
|
|
val = slice->ptr;
|
|
assert(val);
|
|
}
|
|
else {
|
|
Logger::println("foreach over dynamic array");
|
|
val = aggrval->getRVal();
|
|
niters = DtoGEPi(val,0,0);
|
|
niters = DtoLoad(niters, "numiterations");
|
|
val = DtoGEPi(val,0,1);
|
|
val = DtoLoad(val, "collection");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "aggregate type is not Tarray or Tsarray");
|
|
}
|
|
|
|
if (niters->getType() != keytype)
|
|
{
|
|
size_t sz1 = getTypeBitSize(niters->getType());
|
|
size_t sz2 = getTypeBitSize(keytype);
|
|
if (sz1 < sz2)
|
|
niters = gIR->ir->CreateZExt(niters, keytype, "foreachtrunckey");
|
|
else if (sz1 > sz2)
|
|
niters = gIR->ir->CreateTrunc(niters, keytype, "foreachtrunckey");
|
|
else
|
|
niters = gIR->ir->CreateBitCast(niters, keytype, "foreachtrunckey");
|
|
}
|
|
|
|
LLConstant* delta = 0;
|
|
if (op == TOKforeach) {
|
|
new llvm::StoreInst(zerokey, keyvar, p->scopebb());
|
|
}
|
|
else {
|
|
new llvm::StoreInst(niters, keyvar, p->scopebb());
|
|
}
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* condbb = llvm::BasicBlock::Create("foreachcond", p->topfunc(), oldend);
|
|
llvm::BasicBlock* bodybb = llvm::BasicBlock::Create("foreachbody", p->topfunc(), oldend);
|
|
llvm::BasicBlock* nextbb = llvm::BasicBlock::Create("foreachnext", p->topfunc(), oldend);
|
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("foreachend", p->topfunc(), oldend);
|
|
|
|
llvm::BranchInst::Create(condbb, p->scopebb());
|
|
|
|
// condition
|
|
p->scope() = IRScope(condbb,bodybb);
|
|
|
|
LLValue* done = 0;
|
|
LLValue* load = DtoLoad(keyvar);
|
|
if (op == TOKforeach) {
|
|
done = new llvm::ICmpInst(llvm::ICmpInst::ICMP_ULT, load, niters, "tmp", p->scopebb());
|
|
}
|
|
else if (op == TOKforeach_reverse) {
|
|
done = new llvm::ICmpInst(llvm::ICmpInst::ICMP_UGT, load, zerokey, "tmp", p->scopebb());
|
|
load = llvm::BinaryOperator::createSub(load,llvm::ConstantInt::get(keytype, 1, false),"tmp",p->scopebb());
|
|
new llvm::StoreInst(load, keyvar, p->scopebb());
|
|
}
|
|
llvm::BranchInst::Create(bodybb, endbb, done, p->scopebb());
|
|
|
|
// init body
|
|
p->scope() = IRScope(bodybb,nextbb);
|
|
|
|
// get value for this iteration
|
|
LLConstant* zero = llvm::ConstantInt::get(keytype,0,false);
|
|
LLValue* loadedKey = p->ir->CreateLoad(keyvar,"tmp");
|
|
if (aggrtype->ty == Tsarray)
|
|
value->ir.irLocal->value = DtoGEP(val,zero,loadedKey,"tmp");
|
|
else if (aggrtype->ty == Tarray)
|
|
value->ir.irLocal->value = llvm::GetElementPtrInst::Create(val,loadedKey,"tmp",p->scopebb());
|
|
|
|
if (!value->isRef() && !value->isOut()) {
|
|
DValue* dst = new DVarValue(value->type, valvar, true);
|
|
DValue* src = new DVarValue(value->type, value->ir.irLocal->value, true);
|
|
DtoAssign(dst, src);
|
|
value->ir.irLocal->value = valvar;
|
|
}
|
|
|
|
// emit body
|
|
p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,nextbb,endbb));
|
|
body->toIR(p);
|
|
p->loopbbs.pop_back();
|
|
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(nextbb, p->scopebb());
|
|
|
|
// next
|
|
p->scope() = IRScope(nextbb,endbb);
|
|
if (op == TOKforeach) {
|
|
LLValue* load = DtoLoad(keyvar);
|
|
load = p->ir->CreateAdd(load, llvm::ConstantInt::get(keytype, 1, false), "tmp");
|
|
DtoStore(load, keyvar);
|
|
}
|
|
llvm::BranchInst::Create(condbb, p->scopebb());
|
|
|
|
// end
|
|
p->scope() = IRScope(endbb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void LabelStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("LabelStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
// if it's an inline asm label, we don't create a basicblock, just emit it in the asm
|
|
if (p->asmBlock)
|
|
{
|
|
IRAsmStmt* a = new IRAsmStmt;
|
|
a->code += p->func()->decl->mangle();
|
|
a->code += "_";
|
|
a->code += ident->toChars();
|
|
a->code += ":";
|
|
p->asmBlock->s.push_back(a);
|
|
p->asmBlock->internalLabels.push_back(ident);
|
|
}
|
|
else
|
|
{
|
|
assert(tf == NULL);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
if (llvmBB)
|
|
llvmBB->moveBefore(oldend);
|
|
else
|
|
llvmBB = llvm::BasicBlock::Create("label", p->topfunc(), oldend);
|
|
|
|
if (!p->scopereturned())
|
|
llvm::BranchInst::Create(llvmBB, p->scopebb());
|
|
|
|
p->scope() = IRScope(llvmBB,oldend);
|
|
}
|
|
|
|
if (statement)
|
|
statement->toIR(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GotoStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("GotoStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
assert(tf == NULL);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend);
|
|
|
|
DtoGoto(&loc, label->ident, enclosingtryfinally);
|
|
|
|
p->scope() = IRScope(bb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GotoDefaultStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("GotoDefaultStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotodefault", p->topfunc(), oldend);
|
|
|
|
assert(!p->scopereturned());
|
|
assert(sw->sdefault->bodyBB);
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally);
|
|
|
|
llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb());
|
|
p->scope() = IRScope(bb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GotoCaseStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("GotoCaseStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotocase", p->topfunc(), oldend);
|
|
|
|
assert(!p->scopereturned());
|
|
if (!cs->bodyBB)
|
|
{
|
|
cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend());
|
|
}
|
|
|
|
DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally);
|
|
|
|
llvm::BranchInst::Create(cs->bodyBB, p->scopebb());
|
|
p->scope() = IRScope(bb,oldend);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void WithStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("WithStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
assert(exp);
|
|
assert(body);
|
|
|
|
DValue* e = exp->toElem(p);
|
|
assert(!wthis->ir.isSet());
|
|
wthis->ir.irLocal = new IrLocal(wthis);
|
|
wthis->ir.irLocal->value = e->getRVal();
|
|
|
|
body->toIR(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SynchronizedStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
Logger::attention(loc, "synchronized is currently ignored. only the body will be emitted");
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
body->toIR(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* this has moved to asmstmt.cpp
|
|
void AsmStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("AsmStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
// error("%s: inline asm is not yet implemented", loc.toChars());
|
|
// fatal();
|
|
|
|
assert(!asmcode && !asmalign && !refparam && !naked && !regs);
|
|
|
|
Token* t = tokens;
|
|
assert(t);
|
|
|
|
std::string asmstr;
|
|
|
|
do {
|
|
Logger::println("token: %s", t->toChars());
|
|
asmstr.append(t->toChars());
|
|
asmstr.append(" ");
|
|
} while (t = t->next);
|
|
|
|
Logger::println("asm expr = '%s'", asmstr.c_str());
|
|
|
|
// create function type
|
|
std::vector<const LLType*> args;
|
|
const llvm::FunctionType* fty = llvm::FunctionType::get(DtoSize_t(), args, false);
|
|
|
|
// create inline asm callee
|
|
llvm::InlineAsm* inasm = llvm::InlineAsm::get(fty, asmstr, "r,r", false);
|
|
|
|
assert(0);
|
|
}
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void VolatileStatement::toIR(IRState* p)
|
|
{
|
|
Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
|
|
LOG_SCOPE;
|
|
|
|
if (global.params.symdebug)
|
|
DtoDwarfStopPoint(loc.linnum);
|
|
|
|
// mark in-volatile
|
|
bool old = gIR->func()->inVolatile;
|
|
gIR->func()->inVolatile = true;
|
|
|
|
// has statement
|
|
if (statement != NULL)
|
|
{
|
|
// load-store
|
|
DtoMemoryBarrier(false, true, false, false);
|
|
|
|
// do statement
|
|
statement->toIR(p);
|
|
|
|
// no point in a unreachable barrier, terminating statements should insert this themselves.
|
|
if (statement->fallOffEnd())
|
|
{
|
|
// store-load
|
|
DtoMemoryBarrier(false, false, true, false);
|
|
}
|
|
}
|
|
// barrier only
|
|
else
|
|
{
|
|
// load-store & store-load
|
|
DtoMemoryBarrier(false, true, true, false);
|
|
}
|
|
|
|
// restore volatile state
|
|
gIR->func()->inVolatile = old;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
|
|
//STUBST(BreakStatement);
|
|
//STUBST(ForStatement);
|
|
//STUBST(WithStatement);
|
|
//STUBST(SynchronizedStatement);
|
|
//STUBST(ReturnStatement);
|
|
//STUBST(ContinueStatement);
|
|
//STUBST(DefaultStatement);
|
|
//STUBST(CaseStatement);
|
|
//STUBST(SwitchStatement);
|
|
STUBST(SwitchErrorStatement);
|
|
STUBST(Statement);
|
|
//STUBST(IfStatement);
|
|
//STUBST(ForeachStatement);
|
|
//STUBST(DoStatement);
|
|
//STUBST(WhileStatement);
|
|
//STUBST(ExpStatement);
|
|
//STUBST(CompoundStatement);
|
|
//STUBST(ScopeStatement);
|
|
//STUBST(AsmStatement);
|
|
//STUBST(TryCatchStatement);
|
|
//STUBST(TryFinallyStatement);
|
|
//STUBST(VolatileStatement);
|
|
//STUBST(LabelStatement);
|
|
//STUBST(ThrowStatement);
|
|
//STUBST(GotoCaseStatement);
|
|
//STUBST(GotoDefaultStatement);
|
|
//STUBST(GotoStatement);
|
|
//STUBST(UnrolledLoopStatement);
|
|
//STUBST(OnScopeStatement);
|