From 346d04aa8aa20900955c9a31b38e2c585f1efd3f Mon Sep 17 00:00:00 2001 From: Tomas Lindquist Olsen Date: Fri, 6 Jun 2008 20:14:51 +0200 Subject: [PATCH] [svn r236] added initial codegen of inline asm, pretty buggy and incomplete still. see the tangotests/asm1.d test for a sample of what does work! --- dmd/mars.c | 22 +++++--- dmd/mars.h | 1 + gen/asmstmt.cpp | 108 +++++++++++++++++++++++++++++++-------- gen/d-asm-i386.h | 8 +-- llvmdc.kdevelop.filelist | 2 + tangotests/asm1.d | 21 ++++++++ 6 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 tangotests/asm1.d diff --git a/dmd/mars.c b/dmd/mars.c index efa9caf8..af5aa07c 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -215,7 +215,10 @@ Usage:\n\ -version=level compile in version code >= level\n\ -version=ident compile in version code identified by ident\n\ -w enable warnings\n\ - -fp80 enable 80bit reals on x86 32bit (EXPERIMENTAL)\n\ +\n\ +Experimental features:\n\ + -inlineasm allow use of inline asm\n\ + -fp80 enable 80bit reals on x86 32bit\n\ ", #if WIN32 " @cmdfile read arguments from cmdfile\n" @@ -320,8 +323,6 @@ int main(int argc, char *argv[]) #endif /* linux */ //VersionCondition::addPredefinedGlobalIdent("D_Bits"); - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); VersionCondition::addPredefinedGlobalIdent("all"); #if _WIN32 @@ -401,6 +402,8 @@ int main(int argc, char *argv[]) global.params.llvmAnnotate = 1; else if (strcmp(p + 1, "fp80") == 0) global.params.useFP80 = 1; + else if (strcmp(p + 1, "inlineasm") == 0) + global.params.useInlineAsm = 1; else if (p[1] == 'o') { switch (p[2]) @@ -752,13 +755,18 @@ int main(int argc, char *argv[]) VersionCondition::addPredefinedGlobalIdent("LLVM64"); } + if (!is_x86 && (global.params.useFP80 || global.params.useInlineAsm)) { + error("the -fp80 option is only valid for the x86 32bit architecture"); + fatal(); + } + if (global.params.useFP80) { - if (!is_x86) { - error("the -fp80 option is only valid for the x86 32bit architecture"); - fatal(); - } VersionCondition::addPredefinedGlobalIdent("LLVM_X86_FP80"); } + if (global.params.useInlineAsm) { + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); + } assert(tt_arch != 0); assert(tt_os != 0); diff --git a/dmd/mars.h b/dmd/mars.h index e3b05a7f..05e17b71 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -134,6 +134,7 @@ struct Param char llvmAnnotate; char *runtimePath; char useFP80; + char useInlineAsm; char fqnPaths; // use fully qualified object names }; diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index 009e195e..9fab499f 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -2,6 +2,9 @@ // // Taken from an earlier version of DMD -- why is it missing from 0.79? +#include "gen/llvm.h" +#include "llvm/InlineAsm.h" + //#include "d-gcc-includes.h" //#include "total.h" #include "dmd/statement.h" @@ -9,8 +12,6 @@ #include "dmd/declaration.h" #include "dmd/dsymbol.h" -#include "llvm/InlineAsm.h" - #include #include #include @@ -19,6 +20,11 @@ //#include "d-lang.h" //#include "d-codegen.h" +#include "gen/irstate.h" +#include "gen/dvalue.h" +#include "gen/tollvm.h" +#include "gen/logger.h" + typedef enum { Arg_Integer, Arg_Pointer, @@ -64,8 +70,33 @@ struct AsmCode { llvm::InlineAsm* d_build_asm_stmt(std::string code, std::deque const& output_values, std::deque const& input_values, std::string constraints) { - //FIXME: Return InlineAsm::get(..) here. - return NULL; + std::vector params; + + // outputs + const LLType* ret = LLType::VoidTy; + if (!output_values.empty()) + { + std::cout << "memory outputs" << std::endl; + assert(output_values.size() == 1); + const LLType* llty = DtoType(output_values[0]->getType()); + params.push_back(llty); + } + + // inputs + if (!input_values.empty()) + { + std::cout << "inputs" << std::endl; + assert(input_values.size() == 1); + const LLType* llty = DtoType(input_values[0]->getType()); + 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) : @@ -214,6 +245,9 @@ Statement *AsmStatement::semantic(Scope *sc) void AsmStatement::toIR(IRState * irs) { + Logger::println("AsmStatement::toIR(): %s", loc.toChars()); + LOG_SCOPE; + // FIXME // gen.doLineNote( loc ); @@ -248,9 +282,11 @@ AsmStatement::toIR(IRState * irs) AsmArg * arg = (AsmArg *) code->args.data[i]; bool is_input = true; - DValue* arg_val; + DValue* arg_val = 0; std::string cns; - + +std::cout << std::endl; + switch (arg->type) { case Arg_Integer: arg_val = arg->expr->toElem(irs); @@ -259,23 +295,24 @@ AsmStatement::toIR(IRState * irs) break; case Arg_Pointer: // FIXME -/* if (arg->expr->op == TOKvar) - arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree; - else if (arg->expr->op == TOKdsymbol) { - arg_val = irs->getLabelTree( (LabelDsymbol *) ((DsymbolExp *) arg->expr)->s ); - } else - assert(0); - arg_val = irs->addressOf(arg_val);*/ +std::cout << "asm fixme Arg_Pointer" << std::endl; + if (arg->expr->op == TOKvar) + arg_val = arg->expr->toElem(irs); + else if (arg->expr->op == TOKdsymbol) + arg_val = arg->expr->toElem(irs); + else + assert(0); + cns = p_cns; break; case Arg_Memory: // FIXME -/* if (arg->expr->op == TOKvar) - arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree; - else - arg_val = arg->expr->toElem(irs); - if (DECL_P( arg_val )) - TREE_ADDRESSABLE( arg_val ) = 1;*/ +std::cout << "asm fixme Arg_Memory" << std::endl; + if (arg->expr->op == TOKvar) + arg_val = arg->expr->toElem(irs); + else + arg_val = arg->expr->toElem(irs); + switch (arg->mode) { case Mode_Input: cns = m_cns; break; case Mode_Output: cns = mw_cns; is_input = false; break; @@ -285,6 +322,7 @@ AsmStatement::toIR(IRState * irs) break; case Arg_FrameRelative: // FIXME +std::cout << "asm fixme Arg_FrameRelative" << std::endl; /* if (arg->expr->op == TOKvar) arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree; else @@ -301,6 +339,7 @@ AsmStatement::toIR(IRState * irs) break; case Arg_LocalSize: // FIXME +std::cout << "asm fixme Arg_LocalSize" << std::endl; /* var_frame_offset = cfun->x_frame_offset; if (var_frame_offset < 0) var_frame_offset = - var_frame_offset; @@ -372,7 +411,7 @@ AsmStatement::toIR(IRState * irs) ++p; } - //printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate); + printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate); std::string insnt(code->insnTemplate, code->insnTemplateLen); @@ -407,12 +446,37 @@ AsmStatement::toIR(IRState * irs) std::cout << "Inline Asm code: " << std::endl; std::cout << insnt << std::endl; std::cout << "LLVM constraints: " << llvmConstraints << std::endl; -std::cout << 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; igetLVal(); + callargs.push_back(val); + } + + cn = input_values.size(); + for (size_t i=0; igetRVal(); + callargs.push_back(val); + } + + llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), ""); + +/* // FIXME //ASM_VOLATILE_P( t ) = 1; //irs->addExp( t ); if (code->dollarLabel) - d_expand_priv_asm_label(irs, code->dollarLabel); + d_expand_priv_asm_label(irs, code->dollarLabel); +*/ } diff --git a/gen/d-asm-i386.h b/gen/d-asm-i386.h index 47d271ee..82f0c4f3 100644 --- a/gen/d-asm-i386.h +++ b/gen/d-asm-i386.h @@ -1730,7 +1730,7 @@ struct AsmProcessor stmt->regs |= (1 << Reg_EAX)| (1 << Reg_ECX)|(1 << Reg_EDX); - insnTemplate->writebyte('\t'); + insnTemplate->writebyte(' '); for (int i__ = 0; i__ < nOperands; i__++) { int i; if (i__ != 0) @@ -1857,7 +1857,7 @@ struct AsmProcessor e = new AddrExp(0, e); e->type = decl->type->pointerTo(); - +#if !IN_LLVM /* DMD uses the same frame offsets for naked functions. */ if (sc->func->naked) operand->constDisplacement += 4; @@ -1870,7 +1870,7 @@ struct AsmProcessor } e = new PtrExp(0, e); e->type = decl->type; - +#endif operand->constDisplacement = 0; operand->baseReg = Reg_Invalid; @@ -2542,7 +2542,7 @@ struct AsmProcessor machine_mode mode; insnTemplate->writestring((char*) directives[op - Op_db]); - insnTemplate->writebyte('\t'); + insnTemplate->writebyte(' '); do { // DMD is pretty strict here, not even constant expressions are allowed.. diff --git a/llvmdc.kdevelop.filelist b/llvmdc.kdevelop.filelist index a5d541d7..828ee1da 100644 --- a/llvmdc.kdevelop.filelist +++ b/llvmdc.kdevelop.filelist @@ -750,6 +750,8 @@ tangotests/aa1.d tangotests/aa2.d tangotests/align1.d tangotests/arrays1.d +tangotests/asm1.d +tangotests/asm2.d tangotests/b.d tangotests/byval1.d tangotests/c.d diff --git a/tangotests/asm1.d b/tangotests/asm1.d new file mode 100644 index 00000000..fce416f8 --- /dev/null +++ b/tangotests/asm1.d @@ -0,0 +1,21 @@ +module tangotests.asm1; + +extern(C) int printf(char*, ...); + +int main() +{ + int i = 12; + int* ip = &i; + printf("%d\n", i); + asm + { + mov EBX, ip; + mov EAX, [EBX]; + add EAX, 8; + mul EAX, EAX; + mov [EBX], EAX; + } + printf("%d\n", i); + assert(i == 400); + return 0; +}