Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 package ssa | 1 package ssa |
2 | 2 |
3 // An optional pass for sanity checking invariants of the SSA representation. | 3 // An optional pass for sanity checking invariants of the SSA representation. |
4 // Currently it checks CFG invariants but little at the instruction level. | 4 // Currently it checks CFG invariants but little at the instruction level. |
5 | 5 |
6 import ( | 6 import ( |
7 "bytes" | 7 "bytes" |
8 "fmt" | 8 "fmt" |
9 "io" | 9 "io" |
10 "os" | 10 "os" |
11 "reflect" | |
12 ) | 11 ) |
13 | 12 |
14 type sanity struct { | 13 type sanity struct { |
15 reporter io.Writer | 14 reporter io.Writer |
16 fn *Function | 15 fn *Function |
17 block *BasicBlock | 16 block *BasicBlock |
18 insane bool | 17 insane bool |
19 } | 18 } |
20 | 19 |
21 // SanityCheck performs integrity checking of the SSA representation | 20 // SanityCheck performs integrity checking of the SSA representation |
22 // of the function fn and returns true if it was valid. Diagnostics | 21 // of the function fn and returns true if it was valid. Diagnostics |
23 // are written to reporter if non-nil, os.Stderr otherwise . Some | 22 // are written to reporter if non-nil, os.Stderr otherwise. Some |
iant
2013/01/25 05:33:02
s/otherwise ./otherwise./
adonovan
2013/01/25 15:37:51
Done.
| |
24 // diagnostics are only warnings and do not imply a negative result. | 23 // diagnostics are only warnings and do not imply a negative result. |
25 // | 24 // |
26 // Sanity checking is intended to facilitate the debugging of code | 25 // Sanity checking is intended to facilitate the debugging of code |
27 // transformation passes. | 26 // transformation passes. |
28 // | 27 // |
29 func SanityCheck(fn *Function, reporter io.Writer) bool { | 28 func SanityCheck(fn *Function, reporter io.Writer) bool { |
30 if reporter == nil { | 29 if reporter == nil { |
31 reporter = os.Stderr | 30 reporter = os.Stderr |
32 } | 31 } |
33 return (&sanity{reporter: reporter}).checkFunction(fn) | 32 return (&sanity{reporter: reporter}).checkFunction(fn) |
(...skipping 16 matching lines...) Expand all Loading... | |
50 for i, b := range blocks { | 49 for i, b := range blocks { |
51 if i > 0 { | 50 if i > 0 { |
52 io.WriteString(&buf, ", ") | 51 io.WriteString(&buf, ", ") |
53 } | 52 } |
54 io.WriteString(&buf, b.Name) | 53 io.WriteString(&buf, b.Name) |
55 } | 54 } |
56 return buf.String() | 55 return buf.String() |
57 } | 56 } |
58 | 57 |
59 func (s *sanity) diagnostic(prefix, format string, args ...interface{}) { | 58 func (s *sanity) diagnostic(prefix, format string, args ...interface{}) { |
60 » var buf bytes.Buffer | 59 » fmt.Fprintf(s.reporter, "%s: function %s", prefix, s.fn.FullName()) |
iant
2013/01/25 05:33:02
Why do you use the bytes.Buffer here? Why not alw
adonovan
2013/01/25 15:37:51
It's a legacy of when reporter was a callback. Ch
iant
2013/01/25 16:40:49
A bit of both, I suppose. (In C stderr is unbuffe
| |
61 » fmt.Fprintf(&buf, "%s: function %s", prefix, s.fn.FullName()) | |
62 if s.block != nil { | 60 if s.block != nil { |
63 » » fmt.Fprintf(&buf, ", block %s", s.block.Name) | 61 » » fmt.Fprintf(s.reporter, ", block %s", s.block.Name) |
64 » } | 62 » } |
65 » io.WriteString(&buf, ": ") | 63 » io.WriteString(s.reporter, ": ") |
66 » fmt.Fprintf(&buf, format, args...) | 64 » fmt.Fprintf(s.reporter, format, args...) |
67 | |
68 » io.WriteString(s.reporter, buf.String()) | |
69 io.WriteString(s.reporter, "\n") | 65 io.WriteString(s.reporter, "\n") |
70 } | 66 } |
71 | 67 |
72 func (s *sanity) errorf(format string, args ...interface{}) { | 68 func (s *sanity) errorf(format string, args ...interface{}) { |
73 s.insane = true | 69 s.insane = true |
74 s.diagnostic("Error", format, args...) | 70 s.diagnostic("Error", format, args...) |
75 } | 71 } |
76 | 72 |
77 func (s *sanity) warnf(format string, args ...interface{}) { | 73 func (s *sanity) warnf(format string, args ...interface{}) { |
78 s.diagnostic("Warning", format, args...) | 74 s.diagnostic("Warning", format, args...) |
(...skipping 25 matching lines...) Expand all Loading... | |
104 s.errorf("control flow instruction not at end of block") | 100 s.errorf("control flow instruction not at end of block") |
105 case *Phi: | 101 case *Phi: |
106 if idx == 0 { | 102 if idx == 0 { |
107 // It suffices to apply this check to just the first phi node. | 103 // It suffices to apply this check to just the first phi node. |
108 if dup := findDuplicate(s.block.Preds); dup != nil { | 104 if dup := findDuplicate(s.block.Preds); dup != nil { |
109 s.errorf("phi node in block with duplicate prede cessor %s", dup.Name) | 105 s.errorf("phi node in block with duplicate prede cessor %s", dup.Name) |
110 } | 106 } |
111 } else { | 107 } else { |
112 prev := s.block.Instrs[idx-1] | 108 prev := s.block.Instrs[idx-1] |
113 if _, ok := prev.(*Phi); !ok { | 109 if _, ok := prev.(*Phi); !ok { |
114 » » » » s.errorf("Phi instruction follows a non-Phi: %s" , reflect.TypeOf(prev)) | 110 » » » » s.errorf("Phi instruction follows a non-Phi: %T" , prev) |
115 } | 111 } |
116 } | 112 } |
117 if ne, np := len(instr.Edges), len(s.block.Preds); ne != np { | 113 if ne, np := len(instr.Edges), len(s.block.Preds); ne != np { |
118 s.errorf("phi node has %d edges but %d predecessors", ne , np) | 114 s.errorf("phi node has %d edges but %d predecessors", ne , np) |
119 } | 115 } |
120 | 116 |
121 case *Alloc: | 117 case *Alloc: |
122 case *Call: | 118 case *Call: |
123 case *BinOp: | 119 case *BinOp: |
124 case *UnOp: | 120 case *UnOp: |
(...skipping 15 matching lines...) Expand all Loading... | |
140 case *Send: | 136 case *Send: |
141 case *Store: | 137 case *Store: |
142 case *MapUpdate: | 138 case *MapUpdate: |
143 case *Next: | 139 case *Next: |
144 case *Lookup: | 140 case *Lookup: |
145 case *Conv: | 141 case *Conv: |
146 case *ChangeInterface: | 142 case *ChangeInterface: |
147 case *MakeInterface: | 143 case *MakeInterface: |
148 // TODO(adonovan): implement checks. | 144 // TODO(adonovan): implement checks. |
149 default: | 145 default: |
150 » » panic("Unknown instruction type: " + reflect.TypeOf(instr).Strin g()) | 146 » » panic(fmt.Sprintf("Unknown instruction type: %T", instr)) |
151 } | 147 } |
152 } | 148 } |
153 | 149 |
154 func (s *sanity) checkFinalInstr(idx int, instr Instruction) { | 150 func (s *sanity) checkFinalInstr(idx int, instr Instruction) { |
155 switch instr.(type) { | 151 switch instr.(type) { |
156 case *If: | 152 case *If: |
157 if nsuccs := len(s.block.Succs); nsuccs != 2 { | 153 if nsuccs := len(s.block.Succs); nsuccs != 2 { |
158 s.errorf("If-terminated block has %d successors; expecte d 2", nsuccs) | 154 s.errorf("If-terminated block has %d successors; expecte d 2", nsuccs) |
159 return | 155 return |
160 } | 156 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 if b == nil { | 254 if b == nil { |
259 s.warnf("nil *BasicBlock at f.Blocks[%d]", i) | 255 s.warnf("nil *BasicBlock at f.Blocks[%d]", i) |
260 continue | 256 continue |
261 } | 257 } |
262 s.checkBlock(b, i == 0) | 258 s.checkBlock(b, i == 0) |
263 } | 259 } |
264 s.block = nil | 260 s.block = nil |
265 s.fn = nil | 261 s.fn = nil |
266 return !s.insane | 262 return !s.insane |
267 } | 263 } |
LEFT | RIGHT |