Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 package ssa | 1 package ssa |
2 | 2 |
3 // This file implements the Function and BasicBlock types. | 3 // This file implements the Function and BasicBlock types. |
4 | 4 |
5 import ( | 5 import ( |
6 "fmt" | 6 "fmt" |
7 "go/ast" | 7 "go/ast" |
8 "go/types" | 8 "go/types" |
9 "io" | 9 "io" |
10 "os" | 10 "os" |
(...skipping 23 matching lines...) Expand all Loading... | |
34 } | 34 } |
35 | 35 |
36 // predIndex returns the i such that b.Preds[i] == c or panics if | 36 // predIndex returns the i such that b.Preds[i] == c or panics if |
37 // there is none. | 37 // there is none. |
38 func (b *BasicBlock) predIndex(c *BasicBlock) int { | 38 func (b *BasicBlock) predIndex(c *BasicBlock) int { |
39 for i, pred := range b.Preds { | 39 for i, pred := range b.Preds { |
40 if pred == c { | 40 if pred == c { |
41 return i | 41 return i |
42 } | 42 } |
43 } | 43 } |
44 panic(fmt.Sprintf("no edge %s -> %s", c, b)) | 44 panic(fmt.Sprintf("no edge %s -> %s", c, b)) |
gri
2013/02/21 06:35:05
if you have more of these (seems useful), consider
adonovan
2013/02/21 16:03:59
panic has different control flow implications than
| |
45 } | 45 } |
46 | 46 |
47 // hasPhi returns true if b.Instrs contains φ-nodes. | 47 // hasPhi returns true if b.Instrs contains φ-nodes. |
48 func (b *BasicBlock) hasPhi() bool { | 48 func (b *BasicBlock) hasPhi() bool { |
49 _, ok := b.Instrs[0].(*Phi) | 49 _, ok := b.Instrs[0].(*Phi) |
50 return ok | 50 return ok |
51 } | 51 } |
52 | 52 |
53 // phis returns the prefix of b.Instrs containing all the block's φ-nodes. | 53 // phis returns the prefix of b.Instrs containing all the block's φ-nodes. |
54 func (b *BasicBlock) phis() []Instruction { | 54 func (b *BasicBlock) phis() []Instruction { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 for _, field := range f.syntax.resultFields.List { | 231 for _, field := range f.syntax.resultFields.List { |
232 // Implicit "var" decl of locals for named results. | 232 // Implicit "var" decl of locals for named results. |
233 for _, n := range field.Names { | 233 for _, n := range field.Names { |
234 f.results = append(f.results, f.addNamedLocal(id ents[n])) | 234 f.results = append(f.results, f.addNamedLocal(id ents[n])) |
235 } | 235 } |
236 } | 236 } |
237 } | 237 } |
238 } | 238 } |
239 | 239 |
240 // numberRegisters assigns numbers to all SSA registers | 240 // numberRegisters assigns numbers to all SSA registers |
241 // (value-defining Instructions) in f, to aid deubgging. | 241 // (value-defining Instructions) in f, to aid debugging. |
gri
2013/02/21 06:35:05
debugging
adonovan
2013/02/21 16:03:59
Done.
| |
242 // (Non-Instruction Values are named at construction.) | 242 // (Non-Instruction Values are named at construction.) |
243 // NB: named Allocs retain their existing name. | 243 // NB: named Allocs retain their existing name. |
244 // TODO(adonovan): when we have source position info, | 244 // TODO(adonovan): when we have source position info, |
245 // preserve names only for source locals. | 245 // preserve names only for source locals. |
246 // | 246 // |
247 func numberRegisters(f *Function) { | 247 func numberRegisters(f *Function) { |
248 a, v := 0, 0 | 248 a, v := 0, 0 |
249 for _, b := range f.Blocks { | 249 for _, b := range f.Blocks { |
250 for _, instr := range b.Instrs { | 250 for _, instr := range b.Instrs { |
251 switch instr := instr.(type) { | 251 switch instr := instr.(type) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 if f.Prog.mode&LogFunctions != 0 { | 317 if f.Prog.mode&LogFunctions != 0 { |
318 f.DumpTo(os.Stderr) | 318 f.DumpTo(os.Stderr) |
319 } | 319 } |
320 | 320 |
321 if f.Prog.mode&SanityCheckFunctions != 0 { | 321 if f.Prog.mode&SanityCheckFunctions != 0 { |
322 MustSanityCheck(f, nil) | 322 MustSanityCheck(f, nil) |
323 } | 323 } |
324 if f.Prog.mode&LogSource != 0 { | 324 if f.Prog.mode&LogSource != 0 { |
325 fmt.Fprintf(os.Stderr, "build function %s done\n", f.FullName()) | 325 fmt.Fprintf(os.Stderr, "build function %s done\n", f.FullName()) |
326 } | 326 } |
327 } | |
328 | |
329 // removeNilBlocks eliminates nils from f.Blocks and updates each | |
330 // BasicBlock.Index. Use this after any pass that may delete blocks. | |
331 // | |
332 func (f *Function) removeNilBlocks() { | |
333 j := 0 | |
334 for _, b := range f.Blocks { | |
335 if b != nil { | |
336 b.Index = j | |
337 f.Blocks[j] = b | |
338 j++ | |
339 } | |
340 } | |
341 // Nil out f.Blocks[j:] to aid GC. | |
342 for i := j; i < len(f.Blocks); i++ { | |
343 f.Blocks[i] = nil | |
344 } | |
345 f.Blocks = f.Blocks[:j] | |
327 } | 346 } |
328 | 347 |
329 // addNamedLocal creates a local variable, adds it to function f and | 348 // addNamedLocal creates a local variable, adds it to function f and |
330 // returns it. Its name and type are taken from obj. Subsequent | 349 // returns it. Its name and type are taken from obj. Subsequent |
331 // calls to f.lookup(obj) will return the same local. | 350 // calls to f.lookup(obj) will return the same local. |
332 // | 351 // |
333 // Precondition: f.syntax != nil (i.e. a Go source function). | 352 // Precondition: f.syntax != nil (i.e. a Go source function). |
334 // | 353 // |
335 func (f *Function) addNamedLocal(obj types.Object) *Alloc { | 354 func (f *Function) addNamedLocal(obj types.Object) *Alloc { |
336 l := f.addLocal(obj.GetType()) | 355 l := f.addLocal(obj.GetType()) |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
535 default: | 554 default: |
536 io.WriteString(w, instr.String()) | 555 io.WriteString(w, instr.String()) |
537 } | 556 } |
538 io.WriteString(w, "\n") | 557 io.WriteString(w, "\n") |
539 } | 558 } |
540 } | 559 } |
541 fmt.Fprintf(w, "\n") | 560 fmt.Fprintf(w, "\n") |
542 } | 561 } |
543 | 562 |
544 // newBasicBlock adds to f a new basic block and returns it. It does | 563 // newBasicBlock adds to f a new basic block and returns it. It does |
545 // not automatically become the current block for subsequent calls to | 564 // not automatically become the current block for subsequent calls to emit. |
546 // emit. comment is an optional string to improve readability. | 565 // comment is an optional string for more readable debugging output. |
gri
2013/02/21 06:35:05
s/to improve readability/for more readable debuggi
adonovan
2013/02/21 16:03:59
Done.
| |
547 // | 566 // |
548 func (f *Function) newBasicBlock(comment string) *BasicBlock { | 567 func (f *Function) newBasicBlock(comment string) *BasicBlock { |
549 b := &BasicBlock{ | 568 b := &BasicBlock{ |
550 Index: len(f.Blocks), | 569 Index: len(f.Blocks), |
551 Comment: comment, | 570 Comment: comment, |
552 Func: f, | 571 Func: f, |
553 } | 572 } |
554 b.Succs = b.succs2[:0] | 573 b.Succs = b.succs2[:0] |
555 f.Blocks = append(f.Blocks, b) | 574 f.Blocks = append(f.Blocks, b) |
556 return b | 575 return b |
557 } | 576 } |
LEFT | RIGHT |