1MODULE OOC:X86:Debug;
2
3IMPORT
4  Object, Object:Boxed, ADT:Dictionary, IO:TextRider, IO:StdChannels, Out,
5  L := Log, OOC:C:Naming, S := OOC:X86:SSA, M := OOC:X86:Machine;
6
7TYPE
8  Output = POINTER TO OutputDesc;
9  OutputDesc = RECORD
10    b: S.Block;
11    name: STRING;
12    codeDict: Dictionary.Dictionary(S.Instr, STRING);
13    codeCount: LONGINT;
14  END;
15
16TYPE
17  State = POINTER TO StateDesc;
18  StateDesc = RECORD
19    (Object.ObjectDesc)
20    block: S.Block;
21    instr: S.Instr;
22    controlCP: S.Instr;
23    reg: ARRAY S.lastRegister+1 OF S.Result;
24
25    mergeCount: LONGINT;
26    undef: S.Instr;
27    next: State;
28  END;
29
30VAR
31  out: Output;
32
33CONST
34  writeAllInstructions = FALSE;
35  writeDesignator = TRUE;
36  resultPrefix = "(";
37  resultSuffix = ")";
38  instrPrefix = "{";
39  instrSuffix = "}";
40  depPrefix = "   [";
41  depSuffix = "]";
42
43PROCEDURE (out: Output) INIT*(b: S.Block; name: STRING);
44  BEGIN
45    out.b := b;
46    out.name := name;
47    out.codeDict := NEW(Dictionary.Dictionary(S.Instr, STRING));
48    out.codeCount := 0;
49  END INIT;
50
51PROCEDURE (s: State) INIT*(block: S.Block);
52  BEGIN
53    s.block := block;
54    s.instr := block.instrList;
55    s.controlCP := block;
56    s.mergeCount := -1;
57    s.undef := NIL;
58    s.next := NIL;
59  END INIT;
60
61PROCEDURE (s: State) Copy*(): State;
62  VAR
63    t: State;
64  BEGIN
65    NEW(t);
66    t^ := s^;
67    RETURN t;
68  END Copy;
69
70PROCEDURE Type(type: S.Type): STRING;
71  BEGIN
72    CASE type OF
73    | S.noType: RETURN "";
74    | S.signed8: RETURN "i8";
75    | S.signed16: RETURN "i16";
76    | S.signed32: RETURN "i32";
77    | S.signed64: RETURN "i64";
78    | S.unsigned8: RETURN "u8";
79    | S.unsigned16: RETURN "u16";
80    | S.unsigned32: RETURN "u32";
81    | S.unsigned64: RETURN "u64";
82    | S.address: RETURN "adr";
83    | S.real32: RETURN "r32";
84    | S.real64: RETURN "r64";
85    END;
86  END Type;
87
88PROCEDURE Opcode*(instr: S.Instr): STRING;
89  VAR
90    str, type: STRING;
91  BEGIN
92    CASE instr.opcode OF
93      (* arithmetic *)
94    | S.const: str := "const";
95    | S.add: str := "add";
96    | S.sub: str := "sub";
97    | S.mul: str := "mul";
98    | S.div: str := "div";
99    | S.neg: str := "neg";
100    | S.asr: str := "asr";
101    | S.asl: str := "asl";
102    | S.lsr: str := "lsr";
103    | S.lsl: str := "lsl";
104    | S.rr: str := "rr";
105    | S.rl: str := "rl";
106    | S.indexed: str := "indexed";
107    | S.eql: str := "eql";
108    | S.neq: str := "neq";
109    | S.lss: str := "lss";
110    | S.leq: str := "leq";
111    | S.gtr: str := "gtr";
112    | S.geq: str := "geq";
113    | S.setBool: str := "setBool";
114    | S.bitTestAndSet: str := "bitTestAndSet";
115    | S.bitTestAndClear: str := "bitTestAndClear";
116    | S.typeConv: str := "typeConv";
117    | S.fpLoad: str := "fpLoad";
118    | S.fpStorePop: str := "fpStorePop";
119
120      (* function framing *)
121    | S.enter: str := "enter";
122    | S.exit: str := "exit";
123    | S.return: str := "return";
124    | S.call: str := "call";
125    | S.bounceResult: str := "bounceResult";
126    | S.function: str := "function";
127    | S.allocateStack: str := "allocateStack";
128    | S.standin: str := "standin";
129
130      (* memory *)
131    | S.get: str := "get";
132    | S.set: str := "set";
133    | S.copy: str := "copy";
134    | S.typeCast: str := "typeCast";
135    | S.loadRegister: str := "loadRegister";
136    | S.push: str := "push";
137    | S.pop: str := "pop";
138    | S.leave: str := "leave";
139    | S.getLengthHeap: str := "getLengthHeap";
140    | S.setStack: str := "setStack";
141    | S.typeTag: str := "typeTag";
142
143      (* control flow *)
144    | S.branch: str := "branch";
145    | S.guard:
146      IF (instr(S.MergeInstr).jumps # NIL) THEN
147        str := "guard-or-merge";
148      ELSE
149        str := "guard";
150      END;
151    | S.merge: str := "merge";
152    | S.jump: str := "jump";
153    | S.gate: str := "gate";
154    | S.designatorGate: str := "designatorGate";
155    | S.loopStart: str := "loopStart";
156    | S.loopEnd: str := "loopEnd";
157    | S.loopExit: str := "loopExit";
158    | S.loopBackedge:  str := "loopBackedge";
159    END;
160    IF (instr.resultList # NIL) & (instr.resultList.type # S.noType) THEN
161      type := Type(instr.resultList.type);
162      IF (instr.opcode = S.const) THEN
163        RETURN type;
164      ELSE
165        RETURN str+"-"+type;
166      END;
167    ELSE
168      RETURN str;
169    END;
170  END Opcode;
171
172PROCEDURE Register*(reg: S.Register): STRING;
173  BEGIN
174    CASE reg OF
175    | S.sp: RETURN "sp";
176    | S.fp: RETURN "fp";
177    | S.cc: RETURN "cc";
178    | S.gp0: RETURN "gp0";
179    | S.gp1: RETURN "gp1";
180    | S.gp2: RETURN "gp2";
181    | S.gp3: RETURN "gp3";
182    | S.gp4: RETURN "gp4";
183    | S.gp5: RETURN "gp5";
184    | S.st0: RETURN "st0";
185    | S.fp0: RETURN "fp0";
186    | S.fp1: RETURN "fp1";
187    | S.fp2: RETURN "fp2";
188    | S.fp3: RETURN "fp3";
189    | S.fp4: RETURN "fp4";
190    | S.fp5: RETURN "fp5";
191    | S.fp6: RETURN "fp6";
192    | S.fp7: RETURN "fp7";
193    ELSE
194      RETURN "???";
195    END;
196  END Register;
197
198PROCEDURE (out: Output) GetInstrCode(instr: S.Instr): STRING;
199  VAR
200    str: STRING;
201  BEGIN
202    IF out.codeDict.HasKey(instr) THEN
203      RETURN out.codeDict.Get(instr);
204    ELSE
205      INC(out.codeCount);
206      str := Boxed.IntToString(out.codeCount);
207      out.codeDict.Set(instr, str);
208      RETURN str;
209    END;
210  END GetInstrCode;
211
212PROCEDURE (out: Output) Label(node: S.Node): STRING;
213  VAR
214    i: LONGINT;
215    res: S.Result;
216    str: STRING;
217
218  PROCEDURE Location(res: S.Result): STRING;
219    BEGIN
220      CASE res.adrMode OF
221      | S.register:
222        RETURN ":"+Register(res.register);
223      | S.indirect:
224        RETURN ":Indirect";
225      | S.noLocation:
226        RETURN "";
227      END;
228    END Location;
229
230  BEGIN
231    IF (node = NIL) THEN
232      RETURN "NIL";
233    ELSE
234      WITH node: S.Instr DO
235        RETURN instrPrefix+out.GetInstrCode(node)+instrSuffix;
236      | node: S.Result DO
237        IF (node.instr.resultList.nextResult = NIL) THEN
238          (* single result: use short version *)
239          str := resultPrefix+out.GetInstrCode(node.instr)+resultSuffix ;
240        ELSE
241          i := 1;
242          res := node.instr.resultList;
243          WHILE (res # node) DO
244            INC(i);
245            res := res.nextResult;
246          END;
247          str := resultPrefix+out.GetInstrCode(node.instr)+"."+Boxed.IntToString(i)+resultSuffix ;
248        END;
249        RETURN str+Location(node);
250      | node: S.Opnd DO
251        RETURN out.GetInstrCode(node.instr)+"/"+
252            Boxed.IntToString(node.OpndIndex())+"="+out.Label(node.arg);
253      END;
254    END;
255  END Label;
256
257PROCEDURE (out: Output) Result*(msg: STRING; res: S.Result);
258  BEGIN
259    Out.Object(msg);
260    Out.String(": ");
261    Out.Object(out.Label(res));
262    Out.Ln;
263  END Result;
264
265PROCEDURE (out: Output) Instr*(msg: STRING; instr: S.Instr);
266  BEGIN
267    Out.Object(msg);
268    Out.String(": ");
269    Out.Object(out.Label(instr));
270    Out.String(": ");
271    Out.Object(Opcode(instr));
272    Out.Ln;
273  END Instr;
274
275PROCEDURE (out: Output) WriteFunction*();
276  VAR
277    w: TextRider.Writer;
278
279  PROCEDURE WriteConst(selector: S.Selector);
280    BEGIN
281      WITH selector: S.Const DO
282        w.WriteObject(selector.value);
283      | selector: S.Var DO
284        IF (selector.decl = NIL) THEN
285          w.WriteObject("offset(.)");
286        ELSIF selector.IsGlobalVar() THEN
287          w.WriteObject("adr("+Naming.NameOfDeclaration(selector.decl)+")");
288        ELSE
289          w.WriteObject("offset("+selector.decl.Name());
290          IF (selector.dim >= 0) THEN
291            w.WriteChar(".");
292            w.WriteLInt(selector.dim, 0);
293          END;
294          w.WriteObject(")");
295        END;
296      | selector: S.Proc DO
297        w.WriteObject("adr("+selector.decl.Name()+")");
298      | selector: S.ProcName DO
299        w.WriteObject('adr("'+selector.name+'")');
300      | selector: S.TypeDescr DO
301        w.WriteObject('adr("'+Naming.NameOfTypeDescriptor(selector.type, NIL)+'")');
302      | selector: S.ModuleDescr DO
303        w.WriteObject('_mid');
304      END;
305    END WriteConst;
306
307  PROCEDURE Expr(instr: S.Instr);
308    VAR
309      opnd: S.Opnd;
310      s: S.Selector;
311      i: LONGINT;
312      jump: S.Instr;
313    BEGIN
314      w.WriteString("(");
315      IF writeDesignator & (instr.designator # NIL) THEN
316        w.WriteString("<");
317        FOR s IN instr.designator^ DO
318          WITH s: S.Var DO
319            IF (s.decl = NIL) THEN
320              w.WriteString("offset(.)");
321            ELSE
322              w.WriteString(s.decl.name.str^);
323            END;
324          | s: S.Const DO
325            w.WriteString("const");
326          | s: S.Proc DO
327            w.WriteString(s.decl.name.str^);
328          | s: S.Index DO
329            w.WriteString("[");
330            w.WriteObject(out.Label(s.indexStandin.opndList));
331            w.WriteString("]");
332          | s: S.Field DO
333            w.WriteString(".");
334            w.WriteString(s.field.name.str^);
335          | s: S.ProcName DO
336            w.WriteObject('"'+s.name+'"');
337          | s: S.TypeDescr DO
338            w.WriteObject(Naming.NameOfTypeDescriptor(s.type, NIL));
339          | s: S.ModuleDescr DO
340            w.WriteString("_mid");
341          | s: S.HeapObj DO
342            w.WriteObject("heap");
343          END;
344        END;
345        w.WriteString("> ");
346      END;
347
348      w.WriteObject(Opcode(instr));
349      FOR opnd IN instr.Operands() DO
350        w.WriteChar(" ");
351        IF opnd.immediate THEN
352          Expr(opnd.arg.instr);
353        ELSE
354          w.WriteObject(out.Label(opnd.arg));
355        END;
356      END;
357
358      CASE instr.opcode OF
359      | S.const:
360        w.WriteChar(" ");
361        FOR i := 0 TO LEN(instr.designator^)-1 DO
362          IF (i # 0) THEN
363            w.WriteChar("+");
364          END;
365          WriteConst(instr.designator[i]);
366        END;
367      ELSE
368        (* nothing *)
369      END;
370
371      WITH instr: S.MergeInstr DO
372        IF (instr.jumps = NIL) THEN
373            w.WriteString(" [no incoming jumps]");
374        ELSE
375          FOR jump IN instr.jumps^ DO
376            w.WriteString(" [");
377            w.WriteObject(out.Label(jump));
378            w.WriteChar("]");
379          END;
380        END;
381      ELSE
382        (* nothing *)
383      END;
384      w.WriteString(")");
385    END Expr;
386
387  PROCEDURE WriteBlock(b: S.Block; indent: LONGINT);
388    VAR
389      instr: S.Instr;
390      dep: S.Dep;
391      i: LONGINT;
392    BEGIN
393      FOR instr IN b.Instructions() DO
394        IF writeAllInstructions OR
395           (instr.beforeList # NIL) OR (instr.afterList # NIL) OR
396           instr.IsLive() THEN
397          w.WriteLn;
398          FOR i := 1 TO indent DO
399            w.WriteString("  ");
400          END;
401
402          IF (instr.resultList = NIL) THEN
403            w.WriteObject(out.Label(instr));
404            w.WriteChar(" ");
405          ELSE
406            w.WriteObject(out.Label(instr.resultList));
407            w.WriteChar(" ");
408            IF (instr.resultList.nextResult # NIL) THEN
409              w.WriteObject(out.Label(instr.resultList.nextResult));
410              w.WriteChar(" ");
411              IF (instr.resultList.nextResult.nextResult # NIL) THEN
412                w.WriteString("... ");
413              END;
414            END;
415            w.WriteString("<- ");
416          END;
417          Expr(instr);
418
419          IF (instr.beforeList # NIL) THEN
420            w.WriteString(depPrefix);
421            FOR dep IN instr.BeforeList(S.depAny) DO
422              IF (dep # instr.beforeList) THEN
423                w.WriteChar(" ");
424              END;
425              CASE dep.type OF
426              | S.depControl: w.WriteString("c:");
427              | S.depMemory: w.WriteString("m:");
428              | S.depRegion: w.WriteString("r:");
429              END;
430              w.WriteObject(out.Label(dep.before));
431            END;
432            w.WriteString(depSuffix);
433          END;
434        END;
435
436        IF (instr IS S.Block) THEN
437          WriteBlock(instr(S.Block), indent+1);
438        END;
439      END;
440    END WriteBlock;
441
442  BEGIN
443    w := TextRider.ConnectWriter(StdChannels.stderr);
444    w.WriteLn;
445    w.WriteObject("PROCEDURE "+out.name);
446    WriteBlock(out.b, 0);
447    w.WriteLn;
448  END WriteFunction;
449
450
451PROCEDURE UndefState(s: State);
452  VAR
453    i: LONGINT;
454  BEGIN
455    s.undef := NEW(S.Instr, -1);
456    FOR i := 0 TO S.lastRegister DO
457      s.reg[i] := s.undef.AddResult(S.signed32);
458    END;
459  END UndefState;
460
461PROCEDURE WriteFunctionAgain*();
462  BEGIN
463    out.WriteFunction();
464  END WriteFunctionAgain;
465
466PROCEDURE WriteFunction*(b: S.FunctionBlock);
467  VAR
468    name: STRING;
469  BEGIN
470    IF (b.procDecl.procAST = NIL) THEN
471      name := "MODULE_BODY";
472    ELSE
473      name := Naming.NameOfDeclaration(b.procDecl);
474    END;
475    out := NEW(Output, b, name);
476    out.WriteFunction();
477  END WriteFunction;
478
479PROCEDURE Label*(node: S.Node): STRING;
480  BEGIN
481    RETURN out.Label(node);
482  END Label;
483
484PROCEDURE Log*(msg: ARRAY OF CHAR; node: S.Node);
485  BEGIN
486    L.Object(msg, Label(node));
487  END Log;
488
489PROCEDURE Log2*(msg1: ARRAY OF CHAR; node1: S.Node;
490                msg2: ARRAY OF CHAR; node2: S.Node);
491  BEGIN
492    L.Object(msg1, Label(node1)+", "+Object.NewLatin1(msg2)+": "+Label(node2));
493  END Log2;
494
495PROCEDURE ValidateAllocation*(b: S.FunctionBlock);
496(**Checks that every read operation on a register, parameter, local variable,
497   or spill variable indeed retrieves the value it expects to get.  This is one
498   way to check that the register allocator did not produce an invalid register
499   assignment.  *)
500  VAR
501    s, ready: State;
502    block: S.Block;
503    dep: S.Dep;
504    waiting: Dictionary.Dictionary(S.Instr, State);
505    keys: Object.ObjectArrayPtr(S.Instr);
506    instr: S.Instr;
507    loopStart: S.LoopStartInstr;
508
509  PROCEDURE ValidateBlock(s: State);
510   (**Track changes to the state @oparam{s} performed by the sequence of
511      instructions in the block @ofield{s.block}, beginning with instruction
512      @ofield{s.instr}.  Tracking ends either if control flow branches, or if
513      the end of the block is reached.  In the former case, @ofield{s.instr}
514      indicates the branching instruction, in the latter case it is @code{NIL}.  *)
515    VAR
516      instr: S.Instr;
517      res: S.Result;
518      inOutOpnd: S.Opnd;
519
520    PROCEDURE ValidateOpnds(instr: S.Instr);
521      VAR
522        opnd: S.Opnd;
523        arg: S.Result;
524        iter: S.IterOperands;
525      BEGIN
526        CASE instr.opcode OF
527        | S.jump:                        (* fold gate opnds into jump *)
528          iter := instr.GateOperands();
529        | S.gate:                        (* opnds folded into jump *)
530          RETURN;
531        ELSE                             (* normal instruction *)
532          iter := instr.Operands();
533        END;
534        FOR opnd IN iter DO
535          IF opnd.immediate THEN
536            ValidateOpnds(opnd.arg.instr);
537          ELSE
538            arg := opnd.arg;
539            ASSERT(arg.adrMode = S.register);
540            IF (arg # s.reg[arg.register]) THEN
541              L.Object("arg not in register", Label(opnd));
542              L.Object("instead the register holds",
543                       Label(s.reg[arg.register]));
544              L.Ptr("ptr", Label(s.reg[arg.register]));
545              L.Ptr("opcode", Opcode(s.reg[arg.register].instr));
546              ASSERT(arg = s.reg[arg.register]);
547            END;
548          END;
549        END;
550      END ValidateOpnds;
551
552    PROCEDURE HasControlDep(instr: S.Instr): BOOLEAN;
553      VAR
554        dep: S.Dep;
555        iter: S.IterInstrAfterList;
556      BEGIN
557        iter := instr.AfterList(S.depControl);
558        RETURN iter.Next(dep);
559      END HasControlDep;
560
561    BEGIN
562      instr := s.instr;
563      WHILE (instr # NIL) DO
564        CASE instr.opcode OF
565        | S.branch, S.loopStart, S.loopExit:
566          s.instr := instr;
567          RETURN;
568        ELSE
569          IF instr.IsLive()THEN
570            IF HasControlDep(instr) THEN
571              s.controlCP := instr;
572            END;
573
574            ValidateOpnds(instr);
575
576            FOR res IN instr.Results() DO
577              IF (res.adrMode # S.register) THEN
578                Log("not in register", res);
579                ASSERT(res.adrMode = S.register);
580              END;
581              IF (s.reg[res.register] # NIL) THEN
582                ASSERT(s.reg[res.register].instr # instr);
583              END;
584              s.reg[res.register] := res;
585            END;
586
587            inOutOpnd := M.InOutOpnd(instr);
588            IF (inOutOpnd # NIL) THEN
589              IF (inOutOpnd.arg.register # instr.resultList.register) THEN
590                Log("in/out opnd mismatch", inOutOpnd);
591                ASSERT(inOutOpnd.arg.register = instr.resultList.register);
592              END;
593            END;
594          END;
595        END;
596
597        instr := instr.nextInstr;
598      END;
599      s.instr := NIL;
600    END ValidateBlock;
601
602  PROCEDURE PushState(s: State);
603    BEGIN
604      s.next := ready;
605      ready := s;
606    END PushState;
607
608  PROCEDURE PushBlock(s: State; block: S.Block);
609    VAR
610      t: State;
611    BEGIN
612      t := s.Copy();
613      t.block := block;
614      t.instr := block.instrList;
615      t.controlCP := block;
616      PushState(t);
617    END PushBlock;
618
619  PROCEDURE PopState(): State;
620    VAR
621      s: State;
622    BEGIN
623      s := ready;
624      ready := ready.next;
625      RETURN s;
626    END PopState;
627
628  PROCEDURE MergedBlocks(merge: S.Instr): LONGINT;
629    VAR
630      c: LONGINT;
631      dep: S.Dep;
632    BEGIN
633      c := 0;
634      FOR dep IN merge.BeforeList(S.depControl) DO
635        INC(c);
636      END;
637      IF (merge.opcode = S.loopEnd) THEN
638        (* uncount dep loopEnd -> loopStart *)
639        DEC(c);
640      END;
641      RETURN c;
642    END MergedBlocks;
643
644  PROCEDURE MergeState(merge: S.MergeInstr; s: State);
645    VAR
646      i: LONGINT;
647      t: State;
648    BEGIN
649      IF waiting.HasKey(merge) THEN
650        t := waiting.Get(merge);
651        FOR i := 0 TO S.lastRegister DO
652          IF (t.reg[i] # s.reg[i]) THEN
653            t.reg[i] := NIL;
654          END;
655        END;
656        DEC(t.mergeCount);
657        IF (t.mergeCount = 0) THEN
658          PushState(t);
659          waiting.Delete(merge);
660        END;
661      ELSE
662        t := s.Copy();
663        t.block := merge;
664        t.instr := merge.instrList;
665        t.controlCP := merge;
666        t.mergeCount := MergedBlocks(merge)-1;
667        IF (t.mergeCount = 0) THEN
668          PushState(t);
669        ELSE
670          waiting.Set(merge, t);
671        END;
672      END;
673    END MergeState;
674
675  BEGIN
676    waiting := NEW(Dictionary.Dictionary(S.Instr, State));
677    s := NEW(State, b);
678    UndefState(s);
679    ready := NIL;
680    PushState(s);
681
682    WHILE (ready # NIL) DO
683      s := PopState();
684      ValidateBlock(s);
685
686      IF (s.instr # NIL) THEN
687        CASE s.instr.opcode OF
688        | S.branch:
689          FOR block IN s.instr(S.BranchInstr).paths^ DO
690            MergeState(block(S.MergeInstr), s);
691          END;
692        | S.loopStart:
693          loopStart := s.instr(S.LoopStartInstr);
694          PushBlock(s, loopStart);
695          IF (MergedBlocks(loopStart.end) = 0) THEN
696            (* special case: if the loop has no exit, then the end of the
697               loop is never reached by normal means *)
698            PushBlock(s, loopStart.end);
699          END;
700        | S.loopExit:
701          (* add state to loopEnd *)
702          block := s.instr.MergingTarget();
703          MergeState(block(S.MergeInstr), s);
704          (* and push instruction after the loopExit *)
705          s.instr := s.instr.nextInstr;
706          PushState(s);
707        END;
708      ELSIF (s.block.opcode = S.merge) THEN
709        (* continue after the branch in the block that contains the
710           merge's branch instruction  *)
711        ASSERT(s.block.block.opcode = S.branch);
712        s.instr := s.block.block.nextInstr;
713        s.block := s.block.block.block;
714        s.controlCP := s.instr;
715        PushState(s);
716      ELSIF (s.block.opcode = S.loopEnd) THEN
717        (* continue after the loopEnd block *)
718        s.instr := s.block.nextInstr;
719        s.block := s.block.block;
720        s.controlCP := s.instr;
721        PushState(s);
722      ELSE
723        FOR dep IN s.controlCP.AfterList(S.depControl) DO
724          IF (dep.instr IS S.MergeInstr) & (dep.instr.opcode # S.loopEnd) THEN
725            MergeState(dep.instr(S.MergeInstr), s);
726          END;
727        END;
728      END;
729    END;
730    IF (waiting.Size() # 0) THEN
731      keys := waiting.Keys();
732      FOR instr IN keys^ DO
733        Log("waiting", instr);
734      END;
735      ASSERT(waiting.Size() = 0);
736    END;
737  END ValidateAllocation;
738
739END OOC:X86:Debug.
740