Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/gen/asmstmt.cpp

Revision 1650:40bd4a0d4870, 23.5 kB (checked in by Tomas Lindquist Olsen, 2 years ago)

Update to work with LLVM 2.7.

Removed use of dyn_cast, llvm no compiles
without exceptions and rtti by
default. We do need exceptions for the libconfig stuff, but rtti isn't
necessary (anymore).

Debug info needs to be rewritten, as in LLVM 2.7 the format has
completely changed. To have something to look at while rewriting, the
old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means
that you have to define this to compile at the moment.

Updated tango 0.99.9 patch to include updated EH runtime code, which is
needed for LLVM 2.7 as well.

Line 
1 // Taken from GDC source tree. Original by David Friedman.
2 // Released under the Artistic License found in dmd/artistic.txt
3
4 #include "gen/llvm.h"
5 #include "llvm/InlineAsm.h"
6
7 //#include "d-gcc-includes.h"
8 //#include "total.h"
9 #include "mars.h"
10 #include "statement.h"
11 #include "scope.h"
12 #include "declaration.h"
13 #include "dsymbol.h"
14
15 #include <cassert>
16 #include <deque>
17 #include <cstring>
18 #include <string>
19 #include <sstream>
20
21 //#include "d-lang.h"
22 //#include "d-codegen.h"
23
24 #include "gen/irstate.h"
25 #include "gen/dvalue.h"
26 #include "gen/tollvm.h"
27 #include "gen/logger.h"
28 #include "gen/todebug.h"
29 #include "gen/llvmhelpers.h"
30 #include "gen/functions.h"
31
32 typedef enum {
33     Arg_Integer,
34     Arg_Pointer,
35     Arg_Memory,
36     Arg_FrameRelative,
37     Arg_LocalSize,
38     Arg_Dollar
39 } AsmArgType;
40
41 typedef enum {
42     Mode_Input,
43     Mode_Output,
44     Mode_Update
45 } AsmArgMode;
46
47 struct AsmArg {
48     Expression * expr;
49     AsmArgType   type;
50     AsmArgMode   mode;
51     AsmArg(AsmArgType type, Expression * expr, AsmArgMode mode) {
52     this->type = type;
53     this->expr = expr;
54     this->mode = mode;
55     }
56 };
57
58 struct AsmCode {
59     std::string insnTemplate;
60     std::vector<AsmArg> args;
61     std::vector<bool> regs;
62     unsigned dollarLabel;
63     int      clobbersMemory;
64     AsmCode(int n_regs) {
65     regs.resize(n_regs, false);
66     dollarLabel = 0;
67     clobbersMemory = 0;
68     }
69 };
70
71 AsmStatement::AsmStatement(Loc loc, Token *tokens) :
72     Statement(loc)
73 {
74     this->tokens = tokens; // Do I need to copy these?
75     asmcode = 0;
76     asmalign = 0;
77     refparam = 0;
78     naked = 0;
79
80     isBranchToLabel = NULL;
81 }
82
83 Statement *AsmStatement::syntaxCopy()
84 {
85     // copy tokens? copy 'code'?
86     AsmStatement * a_s = new AsmStatement(loc,tokens);
87     a_s->asmcode = asmcode;
88     a_s->refparam = refparam;
89     a_s->naked = naked;
90     return a_s;
91 }
92
93 void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
94 {
95     bool sep = 0, nsep = 0;
96     buf->writestring("asm { ");
97
98     for (Token * t = tokens; t; t = t->next) {
99     switch (t->value) {
100     case TOKlparen:
101     case TOKrparen:
102     case TOKlbracket:
103     case TOKrbracket:
104     case TOKcolon:
105     case TOKsemicolon:
106     case TOKcomma:
107     case TOKstring:
108     case TOKcharv:
109     case TOKwcharv:
110     case TOKdcharv:
111         nsep = 0;
112         break;
113     default:
114         nsep = 1;
115     }
116     if (sep + nsep == 2)
117             buf->writeByte(' ');
118     sep = nsep;
119     buf->writestring(t->toChars());
120     }
121     buf->writestring("; }");
122     buf->writenl();
123 }
124
125 int AsmStatement::comeFrom()
126 {
127     return FALSE;
128 }
129
130 struct AsmParserCommon
131 {
132     virtual void run(Scope* sc, AsmStatement* asmst) = 0;
133     virtual std::string getRegName(int i) = 0;
134 };
135 AsmParserCommon* asmparser = NULL;
136
137 #include "asm-x86-32.h"
138 #include "asm-x86-64.h"
139
140 bool d_have_inline_asm() { return true; }
141
142 Statement *AsmStatement::semantic(Scope *sc)
143 {
144     bool err = false;
145     if ((global.params.cpu != ARCHx86) && (global.params.cpu != ARCHx86_64))
146     {
147         error("inline asm is not supported for the \"%s\" architecture", global.params.llvmArch);
148         err = true;
149     }
150     if (!global.params.useInlineAsm)
151     {
152         error("inline asm is not allowed when the -noasm switch is used");
153         err = true;
154     }
155     if (err)
156         fatal();
157
158     //puts(toChars());
159
160     sc->func->inlineAsm = 1;
161     sc->func->inlineStatus = ILSno; // %% not sure
162     // %% need to set DECL_UNINLINABLE too?
163     sc->func->hasReturnExp = 1; // %% DMD does this, apparently...
164
165     // empty statement -- still do the above things because they might be expected?
166     if (! tokens)
167     return this;
168
169     if (!asmparser)
170         if (global.params.cpu == ARCHx86)
171             asmparser = new AsmParserx8632::AsmParser;
172         else if (global.params.cpu == ARCHx86_64)
173             asmparser = new AsmParserx8664::AsmParser;
174
175     asmparser->run(sc, this);
176
177     return this;
178 }
179
180 int AsmStatement::blockExit()
181 {
182     //printf("AsmStatement::blockExit(%p)\n", this);
183     return BEfallthru | BEreturn | BEgoto | BEhalt;
184 }
185
186 void
187 AsmStatement::toIR(IRState * irs)
188 {
189     Logger::println("AsmStatement::toIR(): %s", loc.toChars());
190     LOG_SCOPE;
191
192     // sanity check
193     assert(irs->func()->decl->inlineAsm);
194
195     // get asm block
196     IRAsmBlock* asmblock = irs->asmBlock;
197     assert(asmblock);
198
199     #ifndef DISABLE_DEBUG_INFO
200     // debug info
201     if (global.params.symdebug)
202         DtoDwarfStopPoint(loc.linnum);
203     #endif
204
205     if (! asmcode)
206     return;
207
208     static std::string i_cns = "i";
209     static std::string p_cns = "i";
210     static std::string m_cns = "*m";
211     static std::string mw_cns = "=*m";
212     static std::string mrw_cns = "+*m";
213     static std::string memory_name = "memory";
214
215     AsmCode * code = (AsmCode *) asmcode;
216     std::vector<LLValue*> input_values;
217     std::vector<std::string> input_constraints;
218     std::vector<LLValue*> output_values;
219     std::vector<std::string> output_constraints;
220     std::vector<std::string> clobbers;
221
222 // FIXME
223     //#define HOST_WIDE_INT long
224     //HOST_WIDE_INT var_frame_offset; // "frame_offset" is a macro
225     bool clobbers_mem = code->clobbersMemory;
226     int input_idx = 0;
227     int n_outputs = 0;
228     int arg_map[10];
229
230     assert(code->args.size() <= 10);
231
232     std::vector<AsmArg>::iterator arg = code->args.begin();
233     for (unsigned i = 0; i < code->args.size(); i++, ++arg) {
234     bool is_input = true;
235     LLValue* arg_val = 0;
236     std::string cns;
237
238     switch (arg->type) {
239     case Arg_Integer:
240         arg_val = arg->expr->toElem(irs)->getRVal();
241     do_integer:
242         cns = i_cns;
243         break;
244     case Arg_Pointer:
245         assert(arg->expr->op == TOKvar);
246         arg_val = arg->expr->toElem(irs)->getRVal();
247         cns = p_cns;
248
249         break;
250     case Arg_Memory:
251         arg_val = arg->expr->toElem(irs)->getRVal();
252
253         switch (arg->mode) {
254         case Mode_Input:  cns = m_cns; break;
255         case Mode_Output: cns = mw_cns;  is_input = false; break;
256         case Mode_Update: cns = mrw_cns; is_input = false; break;
257         default: assert(0); break;
258         }
259         break;
260     case Arg_FrameRelative:
261 // FIXME
262 assert(0 && "asm fixme Arg_FrameRelative");
263 /*      if (arg->expr->op == TOKvar)
264         arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
265         else
266         assert(0);
267         if ( getFrameRelativeValue(arg_val, & var_frame_offset) ) {
268 //      arg_val = irs->integerConstant(var_frame_offset);
269         cns = i_cns;
270         } else {
271         this->error("%s", "argument not frame relative");
272         return;
273         }
274         if (arg->mode != Mode_Input)
275         clobbers_mem = true;
276         break;*/
277     case Arg_LocalSize:
278 // FIXME
279 assert(0 && "asm fixme Arg_LocalSize");
280 /*      var_frame_offset = cfun->x_frame_offset;
281         if (var_frame_offset < 0)
282         var_frame_offset = - var_frame_offset;
283         arg_val = irs->integerConstant( var_frame_offset );*/
284         goto do_integer;
285     default:
286         assert(0);
287     }
288
289     if (is_input) {
290         arg_map[i] = --input_idx;
291         input_values.push_back(arg_val);
292         input_constraints.push_back(cns);
293     } else {
294         arg_map[i] = n_outputs++;
295         output_values.push_back(arg_val);
296         output_constraints.push_back(cns);
297     }
298     }
299
300     // Telling GCC that callee-saved registers are clobbered makes it preserve
301     // those registers.   This changes the stack from what a naked function
302     // expects.
303
304 // FIXME
305 //    if (! irs->func->naked) {
306         assert(asmparser);
307     for (int i = 0; i < code->regs.size(); i++) {
308         if (code->regs[i]) {
309         clobbers.push_back(asmparser->getRegName(i));
310         }
311     }
312     if (clobbers_mem)
313         clobbers.push_back(memory_name);
314 //    }
315
316     // Remap argument numbers
317     for (unsigned i = 0; i < code->args.size(); i++) {
318     if (arg_map[i] < 0)
319         arg_map[i] = -arg_map[i] - 1 + n_outputs;
320     }
321
322     bool pct = false;
323     std::string::iterator
324         p = code->insnTemplate.begin(),
325         q = code->insnTemplate.end();
326     //printf("start: %.*s\n", code->insnTemplateLen, code->insnTemplate);
327     while (p < q) {
328     if (pct) {
329         if (*p >= '0' && *p <= '9') {
330         // %% doesn't check against nargs
331         *p = '0' + arg_map[*p - '0'];
332         pct = false;
333         } else if (*p == '$') {
334         pct = false;
335         }
336         //assert(*p == '%');// could be 'a', etc. so forget it..
337     } else if (*p == '$')
338         pct = true;
339     ++p;
340     }
341
342     typedef std::vector<std::string>::iterator It;
343     if (Logger::enabled()) {
344         Logger::cout() << "final asm: " << code->insnTemplate << '\n';
345         std::ostringstream ss;
346
347         ss << "GCC-style output constraints: {";
348         for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) {
349             ss << " " << *i;
350         }
351         ss << " }";
352         Logger::println("%s", ss.str().c_str());
353
354         ss.str("");
355         ss << "GCC-style input constraints: {";
356         for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
357             ss << " " << *i;
358         }
359         ss << " }";
360         Logger::println("%s", ss.str().c_str());
361
362         ss.str("");
363         ss << "GCC-style clobbers: {";
364         for (It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
365             ss << " " << *i;
366         }
367         ss << " }";
368         Logger::println("%s", ss.str().c_str());
369     }
370
371     // rewrite GCC-style constraints to LLVM-style constraints
372     std::string llvmOutConstraints;
373     std::string llvmInConstraints;
374     int n = 0;
375     for(It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) {
376         // rewrite update constraint to in and out constraints
377         if((*i)[0] == '+') {
378             assert(*i == mrw_cns && "What else are we updating except memory?");
379             /* LLVM doesn't support updating operands, so split into an input
380              * and an output operand.
381              */
382
383             // Change update operand to pure output operand.
384             *i = mw_cns;
385
386             // Add input operand with same value, with original as "matching output".
387             std::ostringstream ss;
388             ss << '*' << (n + asmblock->outputcount);
389             // Must be at the back; unused operands before used ones screw up numbering.
390             input_constraints.push_back(ss.str());
391             input_values.push_back(output_values[n]);
392         }
393         llvmOutConstraints += *i;
394         llvmOutConstraints += ",";
395     }
396     asmblock->outputcount += n;
397
398     for(It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
399         llvmInConstraints += *i;
400         llvmInConstraints += ",";
401     }
402
403     std::string clobstr;
404     for(It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
405         clobstr = "~{" + *i + "},";
406         asmblock->clobs.insert(clobstr);
407     }
408
409     if (Logger::enabled()) {
410         typedef std::vector<LLValue*>::iterator It;
411         {
412             Logger::println("Output values:");
413             LOG_SCOPE
414             size_t i = 0;
415             for (It I = output_values.begin(), E = output_values.end(); I != E; ++I) {
416                 Logger::cout() << "Out " << i++ << " = " << **I << '\n';
417             }
418         }
419         {
420             Logger::println("Input values:");
421             LOG_SCOPE
422             size_t i = 0;
423             for (It I = input_values.begin(), E = input_values.end(); I != E; ++I) {
424                 Logger::cout() << "In  " << i++ << " = " << **I << '\n';
425             }
426         }
427     }
428
429     // excessive commas are removed later...
430
431     // push asm statement
432     IRAsmStmt* asmStmt = new IRAsmStmt;
433     asmStmt->code = code->insnTemplate;
434     asmStmt->out_c = llvmOutConstraints;
435     asmStmt->in_c = llvmInConstraints;
436     asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end());
437     asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end());
438     asmStmt->isBranchToLabel = isBranchToLabel;
439     asmblock->s.push_back(asmStmt);
440 }
441
442 //////////////////////////////////////////////////////////////////////////////
443
444 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
445 :   CompoundStatement(loc, s)
446 {
447     enclosingFinally = NULL;
448     enclosingScopeExit = NULL;
449
450     abiret = NULL;
451 }
452
453 // rewrite argument indices to the block scope indices
454 static void remap_outargs(std::string& insnt, size_t nargs, size_t idx)
455 {
456     static const std::string digits[10] =
457     {
458         "0","1","2","3","4",
459         "5","6","7","8","9"
460     };
461     assert(nargs <= 10);
462
463     static const std::string prefix("<<out");
464     static const std::string suffix(">>");
465     std::string argnum;
466     std::string needle;
467     char buf[10];
468     for (unsigned i = 0; i < nargs; i++) {
469         needle = prefix + digits[i] + suffix;
470         size_t pos = insnt.find(needle);
471         if(std::string::npos != pos)
472             sprintf(buf, "%lu", idx++);
473         while(std::string::npos != (pos = insnt.find(needle)))
474             insnt.replace(pos, needle.size(), buf);
475     }
476 }
477
478 // rewrite argument indices to the block scope indices
479 static void remap_inargs(std::string& insnt, size_t nargs, size_t idx)
480 {
481     static const std::string digits[10] =
482     {
483         "0","1","2","3","4",
484         "5","6","7","8","9"
485     };
486     assert(nargs <= 10);
487
488     static const std::string prefix("<<in");
489     static const std::string suffix(">>");
490     std::string argnum;
491     std::string needle;
492     char buf[10];
493     for (unsigned i = 0; i < nargs; i++) {
494         needle = prefix + digits[i] + suffix;
495         size_t pos = insnt.find(needle);
496         if(std::string::npos != pos)
497             sprintf(buf, "%lu", idx++);
498         while(std::string::npos != (pos = insnt.find(needle)))
499             insnt.replace(pos, needle.size(), buf);
500     }
501 }
502
503 LLValue* DtoAggrPairSwap(LLValue* aggr);
504
505 void AsmBlockStatement::toIR(IRState* p)
506 {
507     Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars());
508     LOG_SCOPE;
509     Logger::println("BEGIN ASM");
510
511     // disable inlining by default
512     if (!p->func()->decl->allowInlining)
513         p->func()->setNeverInline();
514
515     // create asm block structure
516     assert(!p->asmBlock);
517     IRAsmBlock* asmblock = new IRAsmBlock(this);
518     assert(asmblock);
519     p->asmBlock = asmblock;
520
521     // do asm statements
522     for (int i=0; i<statements->dim; i++)
523     {
524         Statement* s = (Statement*)statements->data[i];
525         if (s) {
526             s->toIR(p);
527         }
528     }
529
530     // build forwarder for in-asm branches to external labels
531     // this additional asm code sets the __llvm_jump_target variable
532     // to a unique value that will identify the jump target in
533     // a post-asm switch
534
535     // maps each goto destination to its special value
536     std::map<Identifier*, int> gotoToVal;
537
538     // location of the special value determining the goto label
539     // will be set if post-asm dispatcher block is needed
540     llvm::AllocaInst* jump_target;
541
542     {
543         FuncDeclaration* fd = gIR->func()->decl;
544         char* fdmangle = fd->mangle();
545
546         // we use a simple static counter to make sure the new end labels are unique
547         static size_t uniqueLabelsId = 0;
548         std::ostringstream asmGotoEndLabel;
549         asmGotoEndLabel << "." << fdmangle << "__llvm_asm_end" << uniqueLabelsId++;
550
551         // initialize the setter statement we're going to build
552         IRAsmStmt* outSetterStmt = new IRAsmStmt;
553         std::string asmGotoEnd = "\n\tjmp "+asmGotoEndLabel.str()+"\n";
554         std::ostringstream code;
555         code << asmGotoEnd;
556
557         int n_goto = 1;
558
559         size_t n = asmblock->s.size();
560         for(size_t i=0; i<n; ++i)
561         {
562             IRAsmStmt* a = asmblock->s[i];
563
564             // skip non-branch statements
565             if(!a->isBranchToLabel)
566                 continue;
567
568             // if internal, no special handling is necessary, skip
569             std::vector<Identifier*>::const_iterator it, end;
570             end = asmblock->internalLabels.end();
571             bool skip = false;
572             for(it = asmblock->internalLabels.begin(); it != end; ++it)
573                 if((*it)->equals(a->isBranchToLabel))
574                     skip = true;
575             if(skip)
576                 continue;
577
578             // if we already set things up for this branch target, skip
579             if(gotoToVal.find(a->isBranchToLabel) != gotoToVal.end())
580                 continue;
581
582             // record that the jump needs to be handled in the post-asm dispatcher
583             gotoToVal[a->isBranchToLabel] = n_goto;
584
585             // provide an in-asm target for the branch and set value
586             Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->string);
587             code << fdmangle << '_' << a->isBranchToLabel->string << ":\n\t";
588             code << "movl $<<in" << n_goto << ">>, $<<out0>>\n";
589             //FIXME: Store the value -> label mapping somewhere, so it can be referenced later
590             outSetterStmt->in.push_back(DtoConstUint(n_goto));
591             outSetterStmt->in_c += "i,";
592             code << asmGotoEnd;
593
594             ++n_goto;
595         }
596         if(code.str() != asmGotoEnd)
597         {
598             // finalize code
599             outSetterStmt->code = code.str();
600             outSetterStmt->code += asmGotoEndLabel.str()+":\n";
601
602             // create storage for and initialize the temporary
603             jump_target = DtoAlloca(Type::tint32, "__llvm_jump_target");
604             gIR->ir->CreateStore(DtoConstUint(0), jump_target);
605             // setup variable for output from asm
606             outSetterStmt->out_c = "=*m,";
607             outSetterStmt->out.push_back(jump_target);
608
609             asmblock->s.push_back(outSetterStmt);
610         }
611         else
612             delete outSetterStmt;
613     }
614
615
616     // build a fall-off-end-properly asm statement
617
618     FuncDeclaration* thisfunc = p->func()->decl;
619     bool useabiret = false;
620     p->asmBlock->asmBlock->abiret = NULL;
621     if (thisfunc->fbody->endsWithAsm() == this && thisfunc->type->nextOf()->ty != Tvoid)
622     {
623         // there can't be goto forwarders in this case
624         assert(gotoToVal.empty());
625         emitABIReturnAsmStmt(asmblock, loc, thisfunc);
626         useabiret = true;
627     }
628
629
630     // build asm block
631     std::vector<LLValue*> outargs;
632     std::vector<LLValue*> inargs;
633     std::vector<const LLType*> outtypes;
634     std::vector<const LLType*> intypes;
635     std::string out_c;
636     std::string in_c;
637     std::string clobbers;
638     std::string code;
639     size_t asmIdx = asmblock->retn;
640
641     Logger::println("do outputs");
642     size_t n = asmblock->s.size();
643     for (size_t i=0; i<n; ++i)
644     {
645         IRAsmStmt* a = asmblock->s[i];
646         assert(a);
647         size_t onn = a->out.size();
648         for (size_t j=0; j<onn; ++j)
649         {
650             outargs.push_back(a->out[j]);
651             outtypes.push_back(a->out[j]->getType());
652         }
653         if (!a->out_c.empty())
654         {
655             out_c += a->out_c;
656         }
657         remap_outargs(a->code, onn+a->in.size(), asmIdx);
658         asmIdx += onn;
659     }
660
661     Logger::println("do inputs");
662     for (size_t i=0; i<n; ++i)
663     {
664         IRAsmStmt* a = asmblock->s[i];
665         assert(a);
666         size_t inn = a->in.size();
667         for (size_t j=0; j<inn; ++j)
668         {
669             inargs.push_back(a->in[j]);
670             intypes.push_back(a->in[j]->getType());
671         }
672         if (!a->in_c.empty())
673         {
674             in_c += a->in_c;
675         }
676         remap_inargs(a->code, inn+a->out.size(), asmIdx);
677         asmIdx += inn;
678         if (!code.empty())
679             code += "\n\t";
680         code += a->code;
681     }
682     asmblock->s.clear();
683
684     // append inputs
685     out_c += in_c;
686
687     // append clobbers
688     typedef std::set<std::string>::iterator clobs_it;
689     for (clobs_it i=asmblock->clobs.begin(); i!=asmblock->clobs.end(); ++i)
690     {
691         out_c += *i;
692     }
693
694     // remove excessive comma
695     if (!out_c.empty())
696         out_c.resize(out_c.size()-1);
697
698     Logger::println("code = \"%s\"", code.c_str());
699     Logger::println("constraints = \"%s\"", out_c.c_str());
700
701     // build return types
702     const LLType* retty;
703     if (asmblock->retn)
704         retty = asmblock->retty;
705     else
706         retty = llvm::Type::getVoidTy(gIR->context());
707
708     // build argument types
709     std::vector<const LLType*> types;
710     types.insert(types.end(), outtypes.begin(), outtypes.end());
711     types.insert(types.end(), intypes.begin(), intypes.end());
712     llvm::FunctionType* fty = llvm::FunctionType::get(retty, types, false);
713     if (Logger::enabled())
714         Logger::cout() << "function type = " << *fty << '\n';
715
716     std::vector<LLValue*> args;
717     args.insert(args.end(), outargs.begin(), outargs.end());
718     args.insert(args.end(), inargs.begin(), inargs.end());
719
720     if (Logger::enabled()) {
721         Logger::cout() << "Arguments:" << '\n';
722         Logger::indent();
723         for (std::vector<LLValue*>::iterator b = args.begin(), i = b, e = args.end(); i != e; ++i) {
724             Stream cout = Logger::cout();
725             cout << '$' << (i - b) << " ==> " << **i;
726             if (!llvm::isa<llvm::Instruction>(*i) && !llvm::isa<LLGlobalValue>(*i))
727                 cout << '\n';
728         }
729         Logger::undent();
730     }
731
732     llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true);
733
734     llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(),
735         retty == LLType::getVoidTy(gIR->context()) ? "" : "asm");
736
737     if (Logger::enabled())
738         Logger::cout() << "Complete asm statement: " << *call << '\n';
739
740     // capture abi return value
741     if (useabiret)
742     {
743         IRAsmBlock* block = p->asmBlock;
744         if (block->retfixup)
745             block->asmBlock->abiret = (*block->retfixup)(p->ir, call);
746         else if (p->asmBlock->retemu)
747             block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret);
748         else
749             block->asmBlock->abiret = call;
750     }
751
752     p->asmBlock = NULL;
753     Logger::println("END ASM");
754
755     // if asm contained external branches, emit goto forwarder code
756     if(!gotoToVal.empty())
757     {
758         assert(jump_target);
759
760         // make new blocks
761         llvm::BasicBlock* oldend = gIR->scopeend();
762         llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "afterasmgotoforwarder", p->topfunc(), oldend);
763
764         llvm::LoadInst* val = p->ir->CreateLoad(jump_target, "__llvm_jump_target_value");
765         llvm::SwitchInst* sw = p->ir->CreateSwitch(val, bb, gotoToVal.size());
766
767         // add all cases
768         std::map<Identifier*, int>::iterator it, end = gotoToVal.end();
769         for(it = gotoToVal.begin(); it != end; ++it)
770         {
771             llvm::BasicBlock* casebb = llvm::BasicBlock::Create(gIR->context(), "case", p->topfunc(), bb);
772             sw->addCase(LLConstantInt::get(llvm::IntegerType::get(gIR->context(), 32), it->second), casebb);
773
774             p->scope() = IRScope(casebb,bb);
775             DtoGoto(loc, it->first, enclosingFinally);
776         }
777
778         p->scope() = IRScope(bb,oldend);
779     }
780 }
781
782 // the whole idea of this statement is to avoid the flattening
783 Statements* AsmBlockStatement::flatten(Scope* sc)
784 {
785     return NULL;
786 }
787
788 Statement *AsmBlockStatement::syntaxCopy()
789 {
790     Statements *a = new Statements();
791     a->setDim(statements->dim);
792     for (size_t i = 0; i < statements->dim; i++)
793     {
794         Statement *s = (Statement *)statements->data[i];
795         if (s)
796             s = s->syntaxCopy();
797         a->data[i] = s;
798     }
799     AsmBlockStatement *cs = new AsmBlockStatement(loc, a);
800     return cs;
801 }
802
803 // necessary for in-asm branches
804 Statement *AsmBlockStatement::semantic(Scope *sc)
805 {
806     enclosingFinally = sc->enclosingFinally;
807     enclosingScopeExit = sc->enclosingScopeExit;
808
809     return CompoundStatement::semantic(sc);
810 }
811
812 //////////////////////////////////////////////////////////////////////////////
813
814 void AsmStatement::toNakedIR(IRState *p)
815 {
816     Logger::println("AsmStatement::toNakedIR(): %s", loc.toChars());
817     LOG_SCOPE;
818
819     // is there code?
820     if (!asmcode)
821         return;
822     AsmCode * code = (AsmCode *) asmcode;
823
824     // build asm stmt
825     p->nakedAsm << "\t" << code->insnTemplate << std::endl;
826 }
827
828 void AsmBlockStatement::toNakedIR(IRState *p)
829 {
830     Logger::println("AsmBlockStatement::toNakedIR(): %s", loc.toChars());
831     LOG_SCOPE;
832
833     // do asm statements
834     for (unsigned i=0; i<statements->dim; i++)
835     {
836         Statement* s = (Statement*)statements->data[i];
837         if (s) s->toNakedIR(p);
838     }
839 }
Note: See TracBrowser for help on using the browser.
Copyright © 2008, LDC Development Team.