[svn r248] Fixed: labels in inline asm block now work for the normal case.

Fixed: inline asm blocks are now emitted as a single asm entity.
This commit is contained in:
Tomas Lindquist Olsen
2008-06-08 06:15:51 +02:00
parent 3e62d80b4f
commit fd8cec14e1
9 changed files with 235 additions and 85 deletions

View File

@@ -3186,7 +3186,7 @@ Statement *Parser::parseStatement(int flags)
}
break;
}
s = new CompoundStatement(loc, statements);
s = new AsmBlockStatement(loc, statements);
nextToken();
break;
}

View File

@@ -467,7 +467,7 @@ Statement *CompoundStatement::semantic(Scope *sc)
}
i++;
}
if (statements->dim == 1)
if (statements->dim == 1 && !isAsmBlockStatement())
return s;
return this;
}
@@ -3593,9 +3593,7 @@ LabelDsymbol::LabelDsymbol(Identifier *ident)
: Dsymbol(ident)
{
statement = NULL;
#if IN_GCC
asmLabelNum = 0;
#endif
}
LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?

View File

@@ -41,6 +41,7 @@ struct CompoundStatement;
struct Argument;
struct StaticAssert;
struct AsmStatement;
struct AsmBlockStatement;
struct GotoStatement;
struct ScopeStatement;
struct TryCatchStatement;
@@ -90,6 +91,7 @@ struct Statement : Object
virtual TryCatchStatement *isTryCatchStatement() { return NULL; }
virtual GotoStatement *isGotoStatement() { return NULL; }
virtual AsmStatement *isAsmStatement() { return NULL; }
virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; }
#ifdef _DH
int incontract;
#endif
@@ -754,7 +756,8 @@ struct LabelStatement : Statement
Statement *inlineScan(InlineScanState *iss);
void toIR(IRState *irs);
// LLVMDC
llvm::BasicBlock* llvmBB;
};
@@ -788,4 +791,13 @@ struct AsmStatement : Statement
void toIR(IRState *irs);
};
struct AsmBlockStatement : CompoundStatement
{
AsmBlockStatement(Loc loc, Statements *s);
Statements *flatten(Scope *sc);
AsmBlockStatement *isAsmBlockStatement() { return this; }
void toIR(IRState *irs);
};
#endif /* DMD_STATEMENT_H */

View File

@@ -16,6 +16,7 @@
#include <deque>
#include <iostream>
#include <sstream>
#include <cstring>
//#include "d-lang.h"
//#include "d-codegen.h"
@@ -67,41 +68,6 @@ struct AsmCode {
}
};
llvm::InlineAsm*
d_build_asm_stmt(std::string const& code,
std::deque<LLValue*> const& output_values,
std::deque<LLValue*> const& input_values,
std::string const& constraints)
{
std::vector<const LLType*> params;
// outputs
const LLType* ret = LLType::VoidTy;
if (!output_values.empty())
{
assert(output_values.size() == 1);
const LLType* llty = output_values[0]->getType();
std::cout << "out: " << *llty << '\n';
params.push_back(llty);
}
// inputs
if (!input_values.empty())
{
assert(input_values.size() == 1);
const LLType* llty = input_values[0]->getType();
std::cout << "in: " << *llty << '\n';
params.push_back(llty);
}
llvm::FunctionType* asmfnty = llvm::FunctionType::get(ret, params, false);
std::cout << "function type: " << std::endl;
std::cout << *asmfnty << std::endl;
return llvm::InlineAsm::get(asmfnty, code, constraints, true);
}
AsmStatement::AsmStatement(Loc loc, Token *tokens) :
Statement(loc)
{
@@ -302,6 +268,7 @@ std::cout << std::endl;
std::cout << "asm fixme Arg_Pointer" << std::endl;
if (arg->expr->op == TOKdsymbol)
{
assert(0);
DsymbolExp* dse = (DsymbolExp*)arg->expr;
LabelDsymbol* lbl = dse->s->isLabel();
assert(lbl);
@@ -439,7 +406,9 @@ assert(0);
std::string insnt(code->insnTemplate, code->insnTemplateLen);
// rewrite GCC-style constraints to LLVM-style constraints
std::string llvmConstraints;
std::string llvmOutConstraints;
std::string llvmInConstraints;
std::string llvmClobbers;
int n = 0;
typedef std::deque<std::string>::iterator it;
for(it i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) {
@@ -454,41 +423,182 @@ assert(0);
input_constraints.push_front(input_constraint);
input_values.push_front(output_values[n]);
}
llvmConstraints += *i;
llvmConstraints += ",";
llvmOutConstraints += *i;
llvmOutConstraints += ",";
}
for(it i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
llvmConstraints += *i;
llvmConstraints += ",";
llvmInConstraints += *i;
llvmInConstraints += ",";
}
for(it i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
llvmConstraints += "~{" + *i + "},";
}
if(llvmConstraints.size() > 0)
llvmConstraints.resize(llvmConstraints.size()-1);
std::cout << "Inline Asm code: " << std::endl;
std::cout << insnt << std::endl;
std::cout << "LLVM constraints: " << llvmConstraints << std::endl;
llvm::InlineAsm* t = d_build_asm_stmt(insnt, output_values, input_values, llvmConstraints);
std::cout << "llvm::InlineAsm: " << std::endl;
std::cout << *t << std::endl;
LLSmallVector<LLValue*, 2> callargs;
size_t cn = output_values.size();
for (size_t i=0; i<cn; ++i)
{
callargs.push_back(output_values[i]);
llvmClobbers += "~{" + *i + "},";
}
cn = input_values.size();
for (size_t i=0; i<cn; ++i)
{
callargs.push_back(input_values[i]);
}
// excessive commas are removed later...
llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), "");
// push asm statement
IRAsmStmt* asmStmt = new IRAsmStmt;
asmStmt->code = insnt;
asmStmt->out_c = llvmOutConstraints;
asmStmt->in_c = llvmInConstraints;
asmStmt->clobbers = llvmClobbers;
asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end());
asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end());
irs->ASMs.push_back(asmStmt);
}
//////////////////////////////////////////////////////////////////////////////
AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
: CompoundStatement(loc, s)
{
}
// rewrite argument indices to the block scope indices
static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx)
{
static const std::string digits[10] =
{
"0","1","2","3","4",
"5","6","7","8","9"
};
assert(nargs <= 10);
static const std::string prefix("<<<out");
static const std::string suffix(">>>");
std::string argnum;
std::string needle;
char buf[10];
for (unsigned i = 0; i < nargs; i++) {
needle = prefix + digits[i] + suffix;
sprintf(buf, "%u", idx++);
insnt.replace(insnt.find(needle), needle.size(), buf);
}
}
// rewrite argument indices to the block scope indices
static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx)
{
static const std::string digits[10] =
{
"0","1","2","3","4",
"5","6","7","8","9"
};
assert(nargs <= 10);
static const std::string prefix("<<<in");
static const std::string suffix(">>>");
std::string argnum;
std::string needle;
char buf[10];
for (unsigned i = 0; i < nargs; i++) {
needle = prefix + digits[i] + suffix;
sprintf(buf, "%u", idx++);
insnt.replace(insnt.find(needle), needle.size(), buf);
}
}
void AsmBlockStatement::toIR(IRState* p)
{
Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
Logger::println("BEGIN ASM");
assert(!p->inASM);
p->inASM = true;
// rest idx
size_t asmIdx = 0;
assert(p->ASMs.empty());
// do asm statements
for (int i=0; i<statements->dim; i++)
{
Statement* s = (Statement*)statements->data[i];
if (s) {
s->toIR(p);
}
}
// build asm block
std::vector<LLValue*> outargs;
std::vector<LLValue*> inargs;
std::vector<const LLType*> outtypes;
std::vector<const LLType*> intypes;
std::string out_c;
std::string in_c;
std::string clobbers;
std::string code;
size_t n = p->ASMs.size();
for (size_t i=0; i<n; ++i)
{
IRAsmStmt* a = p->ASMs[i];
assert(a);
size_t onn = a->out.size();
for (size_t j=0; j<onn; ++j)
{
outargs.push_back(a->out[j]);
outtypes.push_back(a->out[j]->getType());
}
if (!a->out_c.empty())
{
out_c += a->out_c;
}
if (!a->clobbers.empty())
{
clobbers += a->clobbers;
}
remap_outargs(a->code, onn, asmIdx);
}
for (size_t i=0; i<n; ++i)
{
IRAsmStmt* a = p->ASMs[i];
assert(a);
size_t inn = a->in.size();
for (size_t j=0; j<inn; ++j)
{
inargs.push_back(a->in[j]);
intypes.push_back(a->in[j]->getType());
}
if (!a->in_c.empty())
{
in_c += a->in_c;
}
remap_inargs(a->code, inn, asmIdx);
if (!code.empty())
code += " ; ";
code += a->code;
}
p->ASMs.clear();
out_c += in_c;
out_c += clobbers;
if (!out_c.empty())
out_c.resize(out_c.size()-1);
Logger::println("code = \"%s\"", code.c_str());
Logger::println("constraints = \"%s\"", out_c.c_str());
std::vector<const LLType*> types;
types.insert(types.end(), outtypes.begin(), outtypes.end());
types.insert(types.end(), intypes.begin(), intypes.end());
llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, types, false);
Logger::cout() << "function type = " << *fty << '\n';
llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true);
std::vector<LLValue*> args;
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(), "");
p->inASM = false;
Logger::println("END ASM");
}
// the whole idea of this statement is to avoid the flattening
Statements* AsmBlockStatement::flatten(Scope* sc)
{
return NULL;
}

View File

@@ -1408,12 +1408,12 @@ struct AsmProcessor
void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
insnTemplate->writestring((char*) fmt);
insnTemplate->printf("%d", asmcode->args.dim);
insnTemplate->printf("<<<%s%d>>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
asmcode->args.push( new AsmArg(type, e, mode) );
}
void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
insnTemplate->writestring((char*) fmtpre);
insnTemplate->printf("%d", asmcode->args.dim);
insnTemplate->printf("<<<%s%d>>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
insnTemplate->writestring((char*) fmtpost);
asmcode->args.push( new AsmArg(type, e, mode) );
}
@@ -1426,6 +1426,11 @@ struct AsmProcessor
insnTemplate->writestring(buf);
}
void addLabel(char* id) {
insnTemplate->writestring(".LDASM");
insnTemplate->writestring(id);
}
/* Determines whether the operand is a register, memory reference
or immediate. Immediate addresses are currently classified as
memory. This function is called before the exact instructions
@@ -1887,7 +1892,7 @@ struct AsmProcessor
addOperand(fmt, Arg_Memory, e, asmcode, mode);
} else {
addOperand("$a", Arg_FrameRelative, e, asmcode);
addOperand2("${",":a}", Arg_FrameRelative, e, asmcode);
}
if (opInfo->operands[i] & Opr_Dest)
asmcode->clobbersMemory = 1;
@@ -1905,14 +1910,12 @@ struct AsmProcessor
addLabel(lbl_num);
asmcode->dollarLabel = lbl_num; // could make the dollar label part of the same asm..
} else if (e->op == TOKdsymbol) {
// LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
// if (! lbl->asmLabelNum)
// lbl->asmLabelNum = ++d_priv_asm_label_serial;
//
// use_star = false;
// addLabel(lbl->asmLabelNum);
use_star = false;
addOperand("$", Arg_Pointer, e, asmcode);
LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
if (! lbl->asmLabelNum)
lbl->asmLabelNum = ++d_priv_asm_label_serial;
use_star = false;
addLabel(lbl->ident->toChars());
} else if ((decl && decl->isCodeseg())) { // if function or label
use_star = false;
addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
@@ -1921,9 +1924,9 @@ struct AsmProcessor
insnTemplate->writebyte('*');
use_star = false;
}
Type* tt = e->type->pointerTo();
e = new AddrExp(0, e);
assert(decl);
e->type = decl->type->pointerTo();
e->type = tt;
addOperand(fmt, Arg_Memory, e, asmcode, mode);
}
@@ -1934,7 +1937,7 @@ struct AsmProcessor
if (operand->constDisplacement) {
if (operand->symbolDisplacement.dim)
insnTemplate->writebyte('+');
addOperand("$a", Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
addOperand2("${",":a}", Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
if (opInfo->operands[i] & Opr_Dest)
asmcode->clobbersMemory = 1;
}

View File

@@ -53,6 +53,7 @@ IRState::IRState()
emitMain = false;
mainFunc = 0;
ir.state = this;
inASM = false;
}
IrFunction* IRState::func()

View File

@@ -65,6 +65,16 @@ struct IRExp
IRExp(Expression* l, Expression* r, DValue* val);
};
struct IRAsmStmt
{
std::string code;
std::string out_c;
std::string in_c;
std::string clobbers;
std::vector<LLValue*> out;
std::vector<LLValue*> in;
};
// represents the module
struct IRState
{
@@ -140,6 +150,10 @@ struct IRState
FuncDeclVector ctors;
FuncDeclVector dtors;
FuncDeclVector unitTests;
// for inline asm
std::vector<IRAsmStmt*> ASMs;
bool inASM;
};
#endif // LLVMDC_GEN_IRSTATE_H

View File

@@ -992,6 +992,17 @@ 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->inASM)
{
IRAsmStmt* a = new IRAsmStmt;
a->code = ".LDASM";
a->code += ident->toChars();
a->code += ":";
p->ASMs.push_back(a);
return;
}
assert(tf == NULL);
llvm::BasicBlock* oldend = gIR->scopeend();

View File

@@ -754,6 +754,7 @@ tangotests/asm1.d
tangotests/asm2.d
tangotests/asm3.d
tangotests/asm4.d
tangotests/asm5.d
tangotests/b.d
tangotests/byval1.d
tangotests/c.d