# HG changeset patch # User lindquist # Date 1212898551 -7200 # Node ID 092468448d2577d2233d1f25b22d6e3063bebbbc # Parent 61aa721a6b7f0f47f1df09a4fa0ac4315d2c8933 [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. diff -r 61aa721a6b7f -r 092468448d25 dmd/parse.c --- a/dmd/parse.c Sun Jun 08 01:07:58 2008 +0200 +++ b/dmd/parse.c Sun Jun 08 06:15:51 2008 +0200 @@ -3186,7 +3186,7 @@ } break; } - s = new CompoundStatement(loc, statements); + s = new AsmBlockStatement(loc, statements); nextToken(); break; } diff -r 61aa721a6b7f -r 092468448d25 dmd/statement.c --- a/dmd/statement.c Sun Jun 08 01:07:58 2008 +0200 +++ b/dmd/statement.c Sun Jun 08 06:15:51 2008 +0200 @@ -467,7 +467,7 @@ } i++; } - if (statements->dim == 1) + if (statements->dim == 1 && !isAsmBlockStatement()) return s; return this; } @@ -3593,9 +3593,7 @@ : Dsymbol(ident) { statement = NULL; -#if IN_GCC asmLabelNum = 0; -#endif } LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? diff -r 61aa721a6b7f -r 092468448d25 dmd/statement.h --- a/dmd/statement.h Sun Jun 08 01:07:58 2008 +0200 +++ b/dmd/statement.h Sun Jun 08 06:15:51 2008 +0200 @@ -41,6 +41,7 @@ struct Argument; struct StaticAssert; struct AsmStatement; +struct AsmBlockStatement; struct GotoStatement; struct ScopeStatement; struct TryCatchStatement; @@ -90,6 +91,7 @@ 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 @@ Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); - + + // LLVMDC llvm::BasicBlock* llvmBB; }; @@ -788,4 +791,13 @@ 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 */ diff -r 61aa721a6b7f -r 092468448d25 gen/asmstmt.cpp --- a/gen/asmstmt.cpp Sun Jun 08 01:07:58 2008 +0200 +++ b/gen/asmstmt.cpp Sun Jun 08 06:15:51 2008 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include //#include "d-lang.h" //#include "d-codegen.h" @@ -67,41 +68,6 @@ } }; -llvm::InlineAsm* -d_build_asm_stmt(std::string const& code, - std::deque const& output_values, - std::deque const& input_values, - std::string const& constraints) -{ - std::vector 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 << "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 @@ 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::iterator it; for(it i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) { @@ -454,41 +423,182 @@ 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 callargs; - - size_t cn = output_values.size(); - for (size_t i=0; icode = 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] = { - callargs.push_back(input_values[i]); + "0","1","2","3","4", + "5","6","7","8","9" + }; + assert(nargs <= 10); + + static const std::string prefix("<<>>"); + 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("<<>>"); + 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; idim; i++) + { + Statement* s = (Statement*)statements->data[i]; + if (s) { + s->toIR(p); + } } - llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), ""); + // build asm block + std::vector outargs; + std::vector inargs; + std::vector outtypes; + std::vector 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; iASMs[i]; + assert(a); + size_t onn = a->out.size(); + for (size_t j=0; jout[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; iASMs[i]; + assert(a); + size_t inn = a->in.size(); + for (size_t j=0; jin[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 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 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; +} diff -r 61aa721a6b7f -r 092468448d25 gen/d-asm-i386.h --- a/gen/d-asm-i386.h Sun Jun 08 01:07:58 2008 +0200 +++ b/gen/d-asm-i386.h Sun Jun 08 06:15:51 2008 +0200 @@ -1408,12 +1408,12 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } diff -r 61aa721a6b7f -r 092468448d25 gen/irstate.cpp --- a/gen/irstate.cpp Sun Jun 08 01:07:58 2008 +0200 +++ b/gen/irstate.cpp Sun Jun 08 06:15:51 2008 +0200 @@ -53,6 +53,7 @@ emitMain = false; mainFunc = 0; ir.state = this; + inASM = false; } IrFunction* IRState::func() diff -r 61aa721a6b7f -r 092468448d25 gen/irstate.h --- a/gen/irstate.h Sun Jun 08 01:07:58 2008 +0200 +++ b/gen/irstate.h Sun Jun 08 06:15:51 2008 +0200 @@ -65,6 +65,16 @@ 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 out; + std::vector in; +}; + // represents the module struct IRState { @@ -140,6 +150,10 @@ FuncDeclVector ctors; FuncDeclVector dtors; FuncDeclVector unitTests; + + // for inline asm + std::vector ASMs; + bool inASM; }; #endif // LLVMDC_GEN_IRSTATE_H diff -r 61aa721a6b7f -r 092468448d25 gen/statements.cpp --- a/gen/statements.cpp Sun Jun 08 01:07:58 2008 +0200 +++ b/gen/statements.cpp Sun Jun 08 06:15:51 2008 +0200 @@ -992,6 +992,17 @@ 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(); diff -r 61aa721a6b7f -r 092468448d25 llvmdc.kdevelop.filelist --- a/llvmdc.kdevelop.filelist Sun Jun 08 01:07:58 2008 +0200 +++ b/llvmdc.kdevelop.filelist Sun Jun 08 06:15:51 2008 +0200 @@ -754,6 +754,7 @@ tangotests/asm2.d tangotests/asm3.d tangotests/asm4.d +tangotests/asm5.d tangotests/b.d tangotests/byval1.d tangotests/c.d