Mercurial > projects > ldc
comparison gen/asmstmt.cpp @ 232:092468448d25 trunk
[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.
author | lindquist |
---|---|
date | Sun, 08 Jun 2008 06:15:51 +0200 |
parents | 61aa721a6b7f |
children | 76ee1bbe487e |
comparison
equal
deleted
inserted
replaced
231:61aa721a6b7f | 232:092468448d25 |
---|---|
14 | 14 |
15 #include <cassert> | 15 #include <cassert> |
16 #include <deque> | 16 #include <deque> |
17 #include <iostream> | 17 #include <iostream> |
18 #include <sstream> | 18 #include <sstream> |
19 #include <cstring> | |
19 | 20 |
20 //#include "d-lang.h" | 21 //#include "d-lang.h" |
21 //#include "d-codegen.h" | 22 //#include "d-codegen.h" |
22 | 23 |
23 #include "gen/irstate.h" | 24 #include "gen/irstate.h" |
64 moreRegs = 0; | 65 moreRegs = 0; |
65 dollarLabel = 0; | 66 dollarLabel = 0; |
66 clobbersMemory = 0; | 67 clobbersMemory = 0; |
67 } | 68 } |
68 }; | 69 }; |
69 | |
70 llvm::InlineAsm* | |
71 d_build_asm_stmt(std::string const& code, | |
72 std::deque<LLValue*> const& output_values, | |
73 std::deque<LLValue*> const& input_values, | |
74 std::string const& constraints) | |
75 { | |
76 std::vector<const LLType*> params; | |
77 | |
78 // outputs | |
79 const LLType* ret = LLType::VoidTy; | |
80 if (!output_values.empty()) | |
81 { | |
82 assert(output_values.size() == 1); | |
83 const LLType* llty = output_values[0]->getType(); | |
84 std::cout << "out: " << *llty << '\n'; | |
85 params.push_back(llty); | |
86 } | |
87 | |
88 // inputs | |
89 if (!input_values.empty()) | |
90 { | |
91 assert(input_values.size() == 1); | |
92 const LLType* llty = input_values[0]->getType(); | |
93 std::cout << "in: " << *llty << '\n'; | |
94 params.push_back(llty); | |
95 } | |
96 | |
97 llvm::FunctionType* asmfnty = llvm::FunctionType::get(ret, params, false); | |
98 | |
99 std::cout << "function type: " << std::endl; | |
100 std::cout << *asmfnty << std::endl; | |
101 | |
102 return llvm::InlineAsm::get(asmfnty, code, constraints, true); | |
103 } | |
104 | 70 |
105 AsmStatement::AsmStatement(Loc loc, Token *tokens) : | 71 AsmStatement::AsmStatement(Loc loc, Token *tokens) : |
106 Statement(loc) | 72 Statement(loc) |
107 { | 73 { |
108 this->tokens = tokens; // Do I need to copy these? | 74 this->tokens = tokens; // Do I need to copy these? |
300 case Arg_Pointer: | 266 case Arg_Pointer: |
301 // FIXME | 267 // FIXME |
302 std::cout << "asm fixme Arg_Pointer" << std::endl; | 268 std::cout << "asm fixme Arg_Pointer" << std::endl; |
303 if (arg->expr->op == TOKdsymbol) | 269 if (arg->expr->op == TOKdsymbol) |
304 { | 270 { |
271 assert(0); | |
305 DsymbolExp* dse = (DsymbolExp*)arg->expr; | 272 DsymbolExp* dse = (DsymbolExp*)arg->expr; |
306 LabelDsymbol* lbl = dse->s->isLabel(); | 273 LabelDsymbol* lbl = dse->s->isLabel(); |
307 assert(lbl); | 274 assert(lbl); |
308 arg_val = lbl->statement->llvmBB; | 275 arg_val = lbl->statement->llvmBB; |
309 if (!arg_val) | 276 if (!arg_val) |
437 printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate); | 404 printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate); |
438 | 405 |
439 std::string insnt(code->insnTemplate, code->insnTemplateLen); | 406 std::string insnt(code->insnTemplate, code->insnTemplateLen); |
440 | 407 |
441 // rewrite GCC-style constraints to LLVM-style constraints | 408 // rewrite GCC-style constraints to LLVM-style constraints |
442 std::string llvmConstraints; | 409 std::string llvmOutConstraints; |
410 std::string llvmInConstraints; | |
411 std::string llvmClobbers; | |
443 int n = 0; | 412 int n = 0; |
444 typedef std::deque<std::string>::iterator it; | 413 typedef std::deque<std::string>::iterator it; |
445 for(it i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) { | 414 for(it i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) { |
446 // rewrite update constraint to in and out constraints | 415 // rewrite update constraint to in and out constraints |
447 if((*i)[0] == '+') { | 416 if((*i)[0] == '+') { |
452 ss >> input_constraint; | 421 ss >> input_constraint; |
453 //FIXME: I think multiple inout constraints will mess up the order! | 422 //FIXME: I think multiple inout constraints will mess up the order! |
454 input_constraints.push_front(input_constraint); | 423 input_constraints.push_front(input_constraint); |
455 input_values.push_front(output_values[n]); | 424 input_values.push_front(output_values[n]); |
456 } | 425 } |
457 llvmConstraints += *i; | 426 llvmOutConstraints += *i; |
458 llvmConstraints += ","; | 427 llvmOutConstraints += ","; |
459 } | 428 } |
460 for(it i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) { | 429 for(it i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) { |
461 llvmConstraints += *i; | 430 llvmInConstraints += *i; |
462 llvmConstraints += ","; | 431 llvmInConstraints += ","; |
463 } | 432 } |
433 | |
464 for(it i = clobbers.begin(), e = clobbers.end(); i != e; ++i) { | 434 for(it i = clobbers.begin(), e = clobbers.end(); i != e; ++i) { |
465 llvmConstraints += "~{" + *i + "},"; | 435 llvmClobbers += "~{" + *i + "},"; |
466 } | 436 } |
467 if(llvmConstraints.size() > 0) | 437 |
468 llvmConstraints.resize(llvmConstraints.size()-1); | 438 // excessive commas are removed later... |
469 | 439 |
470 std::cout << "Inline Asm code: " << std::endl; | 440 // push asm statement |
471 std::cout << insnt << std::endl; | 441 IRAsmStmt* asmStmt = new IRAsmStmt; |
472 std::cout << "LLVM constraints: " << llvmConstraints << std::endl; | 442 asmStmt->code = insnt; |
473 | 443 asmStmt->out_c = llvmOutConstraints; |
474 llvm::InlineAsm* t = d_build_asm_stmt(insnt, output_values, input_values, llvmConstraints); | 444 asmStmt->in_c = llvmInConstraints; |
475 | 445 asmStmt->clobbers = llvmClobbers; |
476 std::cout << "llvm::InlineAsm: " << std::endl; | 446 asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end()); |
477 std::cout << *t << std::endl; | 447 asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end()); |
478 | 448 irs->ASMs.push_back(asmStmt); |
479 LLSmallVector<LLValue*, 2> callargs; | 449 } |
480 | 450 |
481 size_t cn = output_values.size(); | 451 ////////////////////////////////////////////////////////////////////////////// |
482 for (size_t i=0; i<cn; ++i) | 452 |
453 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) | |
454 : CompoundStatement(loc, s) | |
455 { | |
456 } | |
457 | |
458 // rewrite argument indices to the block scope indices | |
459 static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx) | |
460 { | |
461 static const std::string digits[10] = | |
483 { | 462 { |
484 callargs.push_back(output_values[i]); | 463 "0","1","2","3","4", |
485 } | 464 "5","6","7","8","9" |
486 | 465 }; |
487 cn = input_values.size(); | 466 assert(nargs <= 10); |
488 for (size_t i=0; i<cn; ++i) | 467 |
468 static const std::string prefix("<<<out"); | |
469 static const std::string suffix(">>>"); | |
470 std::string argnum; | |
471 std::string needle; | |
472 char buf[10]; | |
473 for (unsigned i = 0; i < nargs; i++) { | |
474 needle = prefix + digits[i] + suffix; | |
475 sprintf(buf, "%u", idx++); | |
476 insnt.replace(insnt.find(needle), needle.size(), buf); | |
477 } | |
478 } | |
479 | |
480 // rewrite argument indices to the block scope indices | |
481 static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx) | |
482 { | |
483 static const std::string digits[10] = | |
489 { | 484 { |
490 callargs.push_back(input_values[i]); | 485 "0","1","2","3","4", |
491 } | 486 "5","6","7","8","9" |
492 | 487 }; |
493 llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), ""); | 488 assert(nargs <= 10); |
494 } | 489 |
490 static const std::string prefix("<<<in"); | |
491 static const std::string suffix(">>>"); | |
492 std::string argnum; | |
493 std::string needle; | |
494 char buf[10]; | |
495 for (unsigned i = 0; i < nargs; i++) { | |
496 needle = prefix + digits[i] + suffix; | |
497 sprintf(buf, "%u", idx++); | |
498 insnt.replace(insnt.find(needle), needle.size(), buf); | |
499 } | |
500 } | |
501 | |
502 void AsmBlockStatement::toIR(IRState* p) | |
503 { | |
504 Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars()); | |
505 LOG_SCOPE; | |
506 Logger::println("BEGIN ASM"); | |
507 | |
508 assert(!p->inASM); | |
509 p->inASM = true; | |
510 | |
511 // rest idx | |
512 size_t asmIdx = 0; | |
513 assert(p->ASMs.empty()); | |
514 | |
515 // do asm statements | |
516 for (int i=0; i<statements->dim; i++) | |
517 { | |
518 Statement* s = (Statement*)statements->data[i]; | |
519 if (s) { | |
520 s->toIR(p); | |
521 } | |
522 } | |
523 | |
524 // build asm block | |
525 std::vector<LLValue*> outargs; | |
526 std::vector<LLValue*> inargs; | |
527 std::vector<const LLType*> outtypes; | |
528 std::vector<const LLType*> intypes; | |
529 std::string out_c; | |
530 std::string in_c; | |
531 std::string clobbers; | |
532 std::string code; | |
533 | |
534 size_t n = p->ASMs.size(); | |
535 for (size_t i=0; i<n; ++i) | |
536 { | |
537 IRAsmStmt* a = p->ASMs[i]; | |
538 assert(a); | |
539 size_t onn = a->out.size(); | |
540 for (size_t j=0; j<onn; ++j) | |
541 { | |
542 outargs.push_back(a->out[j]); | |
543 outtypes.push_back(a->out[j]->getType()); | |
544 } | |
545 if (!a->out_c.empty()) | |
546 { | |
547 out_c += a->out_c; | |
548 } | |
549 if (!a->clobbers.empty()) | |
550 { | |
551 clobbers += a->clobbers; | |
552 } | |
553 remap_outargs(a->code, onn, asmIdx); | |
554 } | |
555 for (size_t i=0; i<n; ++i) | |
556 { | |
557 IRAsmStmt* a = p->ASMs[i]; | |
558 assert(a); | |
559 size_t inn = a->in.size(); | |
560 for (size_t j=0; j<inn; ++j) | |
561 { | |
562 inargs.push_back(a->in[j]); | |
563 intypes.push_back(a->in[j]->getType()); | |
564 } | |
565 if (!a->in_c.empty()) | |
566 { | |
567 in_c += a->in_c; | |
568 } | |
569 remap_inargs(a->code, inn, asmIdx); | |
570 if (!code.empty()) | |
571 code += " ; "; | |
572 code += a->code; | |
573 } | |
574 p->ASMs.clear(); | |
575 | |
576 out_c += in_c; | |
577 out_c += clobbers; | |
578 if (!out_c.empty()) | |
579 out_c.resize(out_c.size()-1); | |
580 | |
581 Logger::println("code = \"%s\"", code.c_str()); | |
582 Logger::println("constraints = \"%s\"", out_c.c_str()); | |
583 | |
584 std::vector<const LLType*> types; | |
585 types.insert(types.end(), outtypes.begin(), outtypes.end()); | |
586 types.insert(types.end(), intypes.begin(), intypes.end()); | |
587 llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, types, false); | |
588 Logger::cout() << "function type = " << *fty << '\n'; | |
589 llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true); | |
590 | |
591 std::vector<LLValue*> args; | |
592 args.insert(args.end(), outargs.begin(), outargs.end()); | |
593 args.insert(args.end(), inargs.begin(), inargs.end()); | |
594 llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); | |
595 | |
596 p->inASM = false; | |
597 Logger::println("END ASM"); | |
598 } | |
599 | |
600 // the whole idea of this statement is to avoid the flattening | |
601 Statements* AsmBlockStatement::flatten(Scope* sc) | |
602 { | |
603 return NULL; | |
604 } |