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 }