mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
[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:
@@ -3186,7 +3186,7 @@ Statement *Parser::parseStatement(int flags)
|
||||
}
|
||||
break;
|
||||
}
|
||||
s = new CompoundStatement(loc, statements);
|
||||
s = new AsmBlockStatement(loc, statements);
|
||||
nextToken();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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()?
|
||||
|
||||
@@ -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 */
|
||||
|
||||
242
gen/asmstmt.cpp
242
gen/asmstmt.cpp
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ IRState::IRState()
|
||||
emitMain = false;
|
||||
mainFunc = 0;
|
||||
ir.state = this;
|
||||
inASM = false;
|
||||
}
|
||||
|
||||
IrFunction* IRState::func()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user