Mercurial > projects > ldc
comparison gen/asmstmt.cpp @ 302:bef811104734 trunk
[svn r323] Branching out of inline asm works.
Renamed emit_finallyblocks to DtoFinallyBlocks and moved to llvmhelpers.
Added enclosingtryfinally to AsmBlockStatement, so branches out of asm blocks respect finallys.
Refactored some GotoStatement code into DtoGoto.
author | ChristianK |
---|---|
date | Wed, 25 Jun 2008 20:39:09 +0200 |
parents | f42a1090e895 |
children | 4aa2b6753059 |
comparison
equal
deleted
inserted
replaced
301:f42a1090e895 | 302:bef811104734 |
---|---|
24 #include "gen/irstate.h" | 24 #include "gen/irstate.h" |
25 #include "gen/dvalue.h" | 25 #include "gen/dvalue.h" |
26 #include "gen/tollvm.h" | 26 #include "gen/tollvm.h" |
27 #include "gen/logger.h" | 27 #include "gen/logger.h" |
28 #include "gen/todebug.h" | 28 #include "gen/todebug.h" |
29 #include "gen/llvmhelpers.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, |
442 ////////////////////////////////////////////////////////////////////////////// | 443 ////////////////////////////////////////////////////////////////////////////// |
443 | 444 |
444 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) | 445 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) |
445 : CompoundStatement(loc, s) | 446 : CompoundStatement(loc, s) |
446 { | 447 { |
448 enclosingtryfinally = NULL; | |
447 } | 449 } |
448 | 450 |
449 // rewrite argument indices to the block scope indices | 451 // rewrite argument indices to the block scope indices |
450 static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx) | 452 static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx) |
451 { | 453 { |
462 std::string needle; | 464 std::string needle; |
463 char buf[10]; | 465 char buf[10]; |
464 for (unsigned i = 0; i < nargs; i++) { | 466 for (unsigned i = 0; i < nargs; i++) { |
465 needle = prefix + digits[i] + suffix; | 467 needle = prefix + digits[i] + suffix; |
466 size_t pos = insnt.find(needle); | 468 size_t pos = insnt.find(needle); |
467 if(pos != std::string::npos) { | 469 if(std::string::npos != pos) |
468 sprintf(buf, "%u", idx++); | 470 sprintf(buf, "%u", idx++); |
471 while(std::string::npos != (pos = insnt.find(needle))) | |
469 insnt.replace(pos, needle.size(), buf); | 472 insnt.replace(pos, needle.size(), buf); |
470 } | |
471 } | 473 } |
472 } | 474 } |
473 | 475 |
474 // rewrite argument indices to the block scope indices | 476 // rewrite argument indices to the block scope indices |
475 static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx) | 477 static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx) |
487 std::string needle; | 489 std::string needle; |
488 char buf[10]; | 490 char buf[10]; |
489 for (unsigned i = 0; i < nargs; i++) { | 491 for (unsigned i = 0; i < nargs; i++) { |
490 needle = prefix + digits[i] + suffix; | 492 needle = prefix + digits[i] + suffix; |
491 size_t pos = insnt.find(needle); | 493 size_t pos = insnt.find(needle); |
492 if(pos != std::string::npos) { | 494 if(std::string::npos != pos) |
493 sprintf(buf, "%u", idx++); | 495 sprintf(buf, "%u", idx++); |
496 while(std::string::npos != (pos = insnt.find(needle))) | |
494 insnt.replace(pos, needle.size(), buf); | 497 insnt.replace(pos, needle.size(), buf); |
495 } | |
496 } | 498 } |
497 } | 499 } |
498 | 500 |
499 void AsmBlockStatement::toIR(IRState* p) | 501 void AsmBlockStatement::toIR(IRState* p) |
500 { | 502 { |
520 // build forwarder for in-asm branches to external labels | 522 // build forwarder for in-asm branches to external labels |
521 // this additional asm code sets the __llvm_jump_target variable | 523 // this additional asm code sets the __llvm_jump_target variable |
522 // to a unique value that will identify the jump target in | 524 // to a unique value that will identify the jump target in |
523 // a post-asm switch | 525 // a post-asm switch |
524 | 526 |
525 // create storage for and initialize the temporary | 527 // maps each special value to a goto destination |
526 llvm::AllocaInst* jump_target = new llvm::AllocaInst(llvm::IntegerType::get(32), "__llvm_jump_target", p->topallocapoint()); | 528 std::map<int, LabelDsymbol*> valToGoto; |
527 gIR->ir->CreateStore(llvm::ConstantInt::get(llvm::IntegerType::get(32), 0), jump_target); | 529 |
528 | 530 // location of the value containing the index into the valToGoto map |
529 IRAsmStmt* outSetterStmt = new IRAsmStmt; | 531 // will be set if post-asm dispatcher block is needed |
530 std::string asmGotoEnd = "jmp __llvm_asm_end ; "; | 532 llvm::AllocaInst* jump_target; |
531 outSetterStmt->code = asmGotoEnd; | 533 |
532 outSetterStmt->out_c = "=*m,"; | 534 { |
533 outSetterStmt->out.push_back(jump_target); | 535 // initialize the setter statement we're going to build |
534 | 536 IRAsmStmt* outSetterStmt = new IRAsmStmt; |
535 int n_goto = 1; | 537 std::string asmGotoEnd = "jmp __llvm_asm_end ; "; |
536 | 538 std::ostringstream code; |
537 size_t n = asmblock->s.size(); | 539 code << asmGotoEnd; |
538 for(size_t i=0; i<n; ++i) | 540 |
539 { | 541 int n_goto = 1; |
540 IRAsmStmt* a = asmblock->s[i]; | 542 |
541 | 543 size_t n = asmblock->s.size(); |
542 // skip non-branch statements | 544 for(size_t i=0; i<n; ++i) |
543 if(!a->isBranchToLabel) | 545 { |
544 continue; | 546 IRAsmStmt* a = asmblock->s[i]; |
545 | 547 |
546 // if internal, no special handling is necessary, skip | 548 // skip non-branch statements |
547 std::vector<Identifier*>::const_iterator it, end; | 549 if(!a->isBranchToLabel) |
548 end = asmblock->internalLabels.end(); | 550 continue; |
549 bool skip = false; | 551 |
550 for(it = asmblock->internalLabels.begin(); it != end; ++it) | 552 // if internal, no special handling is necessary, skip |
551 if((*it)->equals(a->isBranchToLabel)) | 553 std::vector<Identifier*>::const_iterator it, end; |
552 skip = true; | 554 end = asmblock->internalLabels.end(); |
553 if(skip) | 555 bool skip = false; |
554 continue; | 556 for(it = asmblock->internalLabels.begin(); it != end; ++it) |
555 | 557 if((*it)->equals(a->isBranchToLabel->ident)) |
556 // provide an in-asm target for the branch and set value | 558 skip = true; |
557 Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->string); | 559 if(skip) |
558 outSetterStmt->code += a->isBranchToLabel->string; | 560 continue; |
559 outSetterStmt->code += ": ; "; | 561 |
560 outSetterStmt->code += "movl $<<in1>>, $<<out0>> ; "; | 562 // record that the jump needs to be handled in the post-asm dispatcher |
561 //FIXME: Store the value -> label mapping somewhere, so it can be referenced later | 563 valToGoto[n_goto] = a->isBranchToLabel; |
562 outSetterStmt->in.push_back(llvm::ConstantInt::get(llvm::IntegerType::get(32), n_goto++)); | 564 |
563 outSetterStmt->in_c += "i,"; | 565 // provide an in-asm target for the branch and set value |
564 outSetterStmt->code += asmGotoEnd; | 566 Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->ident->string); |
565 } | 567 code << a->isBranchToLabel->ident->string << ": ; "; |
566 if(outSetterStmt->code != asmGotoEnd) | 568 code << "movl $<<in" << n_goto << ">>, $<<out0>> ; "; |
567 { | 569 //FIXME: Store the value -> label mapping somewhere, so it can be referenced later |
568 outSetterStmt->code += "__llvm_asm_end: ; "; | 570 outSetterStmt->in.push_back(llvm::ConstantInt::get(llvm::IntegerType::get(32), n_goto)); |
569 asmblock->s.push_back(outSetterStmt); | 571 outSetterStmt->in_c += "i,"; |
570 } | 572 code << asmGotoEnd; |
571 else | 573 |
572 delete outSetterStmt; | 574 ++n_goto; |
575 } | |
576 if(code.str() != asmGotoEnd) | |
577 { | |
578 // finalize code | |
579 outSetterStmt->code = code.str(); | |
580 outSetterStmt->code += "__llvm_asm_end: ; "; | |
581 | |
582 // create storage for and initialize the temporary | |
583 jump_target = new llvm::AllocaInst(llvm::IntegerType::get(32), "__llvm_jump_target", p->topallocapoint()); | |
584 gIR->ir->CreateStore(llvm::ConstantInt::get(llvm::IntegerType::get(32), 0), jump_target); | |
585 // setup variable for output from asm | |
586 outSetterStmt->out_c = "=*m,"; | |
587 outSetterStmt->out.push_back(jump_target); | |
588 | |
589 asmblock->s.push_back(outSetterStmt); | |
590 } | |
591 else | |
592 delete outSetterStmt; | |
593 } | |
573 | 594 |
574 | 595 |
575 // build asm block | 596 // build asm block |
576 std::vector<LLValue*> outargs; | 597 std::vector<LLValue*> outargs; |
577 std::vector<LLValue*> inargs; | 598 std::vector<LLValue*> inargs; |
581 std::string in_c; | 602 std::string in_c; |
582 std::string clobbers; | 603 std::string clobbers; |
583 std::string code; | 604 std::string code; |
584 size_t asmIdx = 0; | 605 size_t asmIdx = 0; |
585 | 606 |
586 n = asmblock->s.size(); | 607 size_t n = asmblock->s.size(); |
587 for (size_t i=0; i<n; ++i) | 608 for (size_t i=0; i<n; ++i) |
588 { | 609 { |
589 IRAsmStmt* a = asmblock->s[i]; | 610 IRAsmStmt* a = asmblock->s[i]; |
590 assert(a); | 611 assert(a); |
591 size_t onn = a->out.size(); | 612 size_t onn = a->out.size(); |
651 llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); | 672 llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); |
652 | 673 |
653 p->asmBlock = NULL; | 674 p->asmBlock = NULL; |
654 Logger::println("END ASM"); | 675 Logger::println("END ASM"); |
655 | 676 |
656 //FIXME: Emit goto forwarder code here | 677 // if asm contained external branches, emit goto forwarder code |
678 if(!valToGoto.empty()) | |
679 { | |
680 assert(jump_target); | |
681 | |
682 // make new blocks | |
683 llvm::BasicBlock* oldend = gIR->scopeend(); | |
684 llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterasmgotoforwarder", p->topfunc(), oldend); | |
685 | |
686 llvm::LoadInst* val = p->ir->CreateLoad(jump_target, "__llvm_jump_target_value"); | |
687 llvm::SwitchInst* sw = p->ir->CreateSwitch(val, bb, valToGoto.size()); | |
688 | |
689 // add all cases | |
690 std::map<int, LabelDsymbol*>::iterator it, end = valToGoto.end(); | |
691 for(it = valToGoto.begin(); it != end; ++it) | |
692 { | |
693 llvm::BasicBlock* casebb = llvm::BasicBlock::Create("case", p->topfunc(), bb); | |
694 sw->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(32), it->first), casebb); | |
695 | |
696 p->scope() = IRScope(casebb,bb); | |
697 DtoGoto(&loc, it->second, enclosingtryfinally); | |
698 } | |
699 | |
700 p->scope() = IRScope(bb,oldend); | |
701 } | |
657 } | 702 } |
658 | 703 |
659 // the whole idea of this statement is to avoid the flattening | 704 // the whole idea of this statement is to avoid the flattening |
660 Statements* AsmBlockStatement::flatten(Scope* sc) | 705 Statements* AsmBlockStatement::flatten(Scope* sc) |
661 { | 706 { |
674 a->data[i] = s; | 719 a->data[i] = s; |
675 } | 720 } |
676 AsmBlockStatement *cs = new AsmBlockStatement(loc, a); | 721 AsmBlockStatement *cs = new AsmBlockStatement(loc, a); |
677 return cs; | 722 return cs; |
678 } | 723 } |
724 | |
725 // necessary for in-asm branches | |
726 Statement *AsmBlockStatement::semantic(Scope *sc) | |
727 { | |
728 enclosingtryfinally = sc->tfOfTry; | |
729 | |
730 return CompoundStatement::semantic(sc); | |
731 } |