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 }