Mercurial > projects > ldc
comparison gen/asmstmt.cpp @ 945:03d7c4aac654
SWITCHED TO LLVM 2.5 !
Applied patch from ticket #129 to compile against latest LLVM. Thanks Frits van Bommel.
Fixed implicit return by asm block at the end of a function on x86-32. Other architectures will produce an error at the moment. Adding support for new targets is fairly simple.
Fixed return calling convention for complex numbers, ST and ST(1) were switched around.
Added some testcases.
I've run a dstress test and there are no regressions. However, the runtime does not seem to compile with symbolic debug information. -O3 -release -inline works well and is what I used for the dstress run. Tango does not compile, a small workaround is needed in tango.io.digest.Digest.Digest.hexDigest. See ticket #206 .
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 08 Feb 2009 05:26:54 +0100 |
parents | 545f54041d91 |
children | e048e36bc155 |
comparison
equal
deleted
inserted
replaced
944:eb310635d80e | 945:03d7c4aac654 |
---|---|
24 #include "gen/dvalue.h" | 24 #include "gen/dvalue.h" |
25 #include "gen/tollvm.h" | 25 #include "gen/tollvm.h" |
26 #include "gen/logger.h" | 26 #include "gen/logger.h" |
27 #include "gen/todebug.h" | 27 #include "gen/todebug.h" |
28 #include "gen/llvmhelpers.h" | 28 #include "gen/llvmhelpers.h" |
29 #include "gen/functions.h" | |
29 | 30 |
30 typedef enum { | 31 typedef enum { |
31 Arg_Integer, | 32 Arg_Integer, |
32 Arg_Pointer, | 33 Arg_Pointer, |
33 Arg_Memory, | 34 Arg_Memory, |
398 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) | 399 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) |
399 : CompoundStatement(loc, s) | 400 : CompoundStatement(loc, s) |
400 { | 401 { |
401 enclosinghandler = NULL; | 402 enclosinghandler = NULL; |
402 tf = NULL; | 403 tf = NULL; |
404 | |
405 abiret = NULL; | |
403 } | 406 } |
404 | 407 |
405 // rewrite argument indices to the block scope indices | 408 // rewrite argument indices to the block scope indices |
406 static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx) | 409 static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx) |
407 { | 410 { |
450 while(std::string::npos != (pos = insnt.find(needle))) | 453 while(std::string::npos != (pos = insnt.find(needle))) |
451 insnt.replace(pos, needle.size(), buf); | 454 insnt.replace(pos, needle.size(), buf); |
452 } | 455 } |
453 } | 456 } |
454 | 457 |
458 LLValue* DtoAggrPairSwap(LLValue* aggr); | |
459 | |
455 void AsmBlockStatement::toIR(IRState* p) | 460 void AsmBlockStatement::toIR(IRState* p) |
456 { | 461 { |
457 Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars()); | 462 Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars()); |
458 LOG_SCOPE; | 463 LOG_SCOPE; |
459 Logger::println("BEGIN ASM"); | 464 Logger::println("BEGIN ASM"); |
460 | 465 |
461 // disable inlining | 466 // disable inlining by default |
462 gIR->func()->setNeverInline(); | 467 if (!p->func()->decl->allowInlining) |
468 p->func()->setNeverInline(); | |
463 | 469 |
464 // create asm block structure | 470 // create asm block structure |
465 assert(!p->asmBlock); | 471 assert(!p->asmBlock); |
466 IRAsmBlock* asmblock = new IRAsmBlock; | 472 IRAsmBlock* asmblock = new IRAsmBlock(this); |
467 assert(asmblock); | 473 assert(asmblock); |
468 p->asmBlock = asmblock; | 474 p->asmBlock = asmblock; |
469 | 475 |
470 // do asm statements | 476 // do asm statements |
471 for (int i=0; i<statements->dim; i++) | 477 for (int i=0; i<statements->dim; i++) |
560 else | 566 else |
561 delete outSetterStmt; | 567 delete outSetterStmt; |
562 } | 568 } |
563 | 569 |
564 | 570 |
571 // build a fall-off-end-properly asm statement | |
572 | |
573 FuncDeclaration* thisfunc = p->func()->decl; | |
574 bool useabiret = false; | |
575 p->asmBlock->asmBlock->abiret = NULL; | |
576 if (thisfunc->fbody->endsWithAsm() == this && thisfunc->type->nextOf()->ty != Tvoid) | |
577 { | |
578 // there can't be goto forwarders in this case | |
579 assert(gotoToVal.empty()); | |
580 emitABIReturnAsmStmt(asmblock, loc, thisfunc); | |
581 useabiret = true; | |
582 } | |
583 | |
584 | |
565 // build asm block | 585 // build asm block |
566 std::vector<LLValue*> outargs; | 586 std::vector<LLValue*> outargs; |
567 std::vector<LLValue*> inargs; | 587 std::vector<LLValue*> inargs; |
568 std::vector<const LLType*> outtypes; | 588 std::vector<const LLType*> outtypes; |
569 std::vector<const LLType*> intypes; | 589 std::vector<const LLType*> intypes; |
570 std::string out_c; | 590 std::string out_c; |
571 std::string in_c; | 591 std::string in_c; |
572 std::string clobbers; | 592 std::string clobbers; |
573 std::string code; | 593 std::string code; |
574 size_t asmIdx = 0; | 594 size_t asmIdx = asmblock->retn; |
575 | 595 |
596 Logger::println("do outputs"); | |
576 size_t n = asmblock->s.size(); | 597 size_t n = asmblock->s.size(); |
577 for (size_t i=0; i<n; ++i) | 598 for (size_t i=0; i<n; ++i) |
578 { | 599 { |
579 IRAsmStmt* a = asmblock->s[i]; | 600 IRAsmStmt* a = asmblock->s[i]; |
580 assert(a); | 601 assert(a); |
588 { | 609 { |
589 out_c += a->out_c; | 610 out_c += a->out_c; |
590 } | 611 } |
591 remap_outargs(a->code, onn+a->in.size(), asmIdx); | 612 remap_outargs(a->code, onn+a->in.size(), asmIdx); |
592 } | 613 } |
614 | |
615 Logger::println("do inputs"); | |
593 for (size_t i=0; i<n; ++i) | 616 for (size_t i=0; i<n; ++i) |
594 { | 617 { |
595 IRAsmStmt* a = asmblock->s[i]; | 618 IRAsmStmt* a = asmblock->s[i]; |
596 assert(a); | 619 assert(a); |
597 size_t inn = a->in.size(); | 620 size_t inn = a->in.size(); |
626 out_c.resize(out_c.size()-1); | 649 out_c.resize(out_c.size()-1); |
627 | 650 |
628 Logger::println("code = \"%s\"", code.c_str()); | 651 Logger::println("code = \"%s\"", code.c_str()); |
629 Logger::println("constraints = \"%s\"", out_c.c_str()); | 652 Logger::println("constraints = \"%s\"", out_c.c_str()); |
630 | 653 |
654 // build return types | |
655 const LLType* retty; | |
656 if (asmblock->retn) | |
657 retty = asmblock->retty; | |
658 else | |
659 retty = llvm::Type::VoidTy; | |
660 | |
661 // build argument types | |
631 std::vector<const LLType*> types; | 662 std::vector<const LLType*> types; |
632 types.insert(types.end(), outtypes.begin(), outtypes.end()); | 663 types.insert(types.end(), outtypes.begin(), outtypes.end()); |
633 types.insert(types.end(), intypes.begin(), intypes.end()); | 664 types.insert(types.end(), intypes.begin(), intypes.end()); |
634 llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, types, false); | 665 llvm::FunctionType* fty = llvm::FunctionType::get(retty, types, false); |
635 if (Logger::enabled()) | 666 if (Logger::enabled()) |
636 Logger::cout() << "function type = " << *fty << '\n'; | 667 Logger::cout() << "function type = " << *fty << '\n'; |
637 llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true); | 668 llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true); |
638 | 669 |
639 std::vector<LLValue*> args; | 670 std::vector<LLValue*> args; |
640 args.insert(args.end(), outargs.begin(), outargs.end()); | 671 args.insert(args.end(), outargs.begin(), outargs.end()); |
641 args.insert(args.end(), inargs.begin(), inargs.end()); | 672 args.insert(args.end(), inargs.begin(), inargs.end()); |
642 llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); | 673 llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); |
674 if (useabiret) | |
675 { | |
676 p->asmBlock->asmBlock->abiret = call; | |
677 } | |
643 | 678 |
644 p->asmBlock = NULL; | 679 p->asmBlock = NULL; |
645 Logger::println("END ASM"); | 680 Logger::println("END ASM"); |
646 | 681 |
647 // if asm contained external branches, emit goto forwarder code | 682 // if asm contained external branches, emit goto forwarder code |