1
2
3
4
5 package ssa
6
7 import (
8 "fmt"
9 )
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 const (
44 top int8 = iota
45 constant
46 bottom
47 )
48
49 type lattice struct {
50 tag int8
51 val *Value
52 }
53
54 type worklist struct {
55 f *Func
56 edges []Edge
57 uses []*Value
58 visited map[Edge]bool
59 latticeCells map[*Value]lattice
60 defUse map[*Value][]*Value
61 defBlock map[*Value][]*Block
62 visitedBlock []bool
63 }
64
65
66
67
68 func sccp(f *Func) {
69 var t worklist
70 t.f = f
71 t.edges = make([]Edge, 0)
72 t.visited = make(map[Edge]bool)
73 t.edges = append(t.edges, Edge{f.Entry, 0})
74 t.defUse = make(map[*Value][]*Value)
75 t.defBlock = make(map[*Value][]*Block)
76 t.latticeCells = make(map[*Value]lattice)
77 t.visitedBlock = f.Cache.allocBoolSlice(f.NumBlocks())
78 defer f.Cache.freeBoolSlice(t.visitedBlock)
79
80
81 t.buildDefUses()
82
83
84 for {
85 if len(t.edges) > 0 {
86 edge := t.edges[0]
87 t.edges = t.edges[1:]
88 if _, exist := t.visited[edge]; !exist {
89 dest := edge.b
90 destVisited := t.visitedBlock[dest.ID]
91
92
93 t.visited[edge] = true
94 t.visitedBlock[dest.ID] = true
95 for _, val := range dest.Values {
96 if val.Op == OpPhi || !destVisited {
97 t.visitValue(val)
98 }
99 }
100
101
102 if !destVisited {
103 t.propagate(dest)
104 }
105 }
106 continue
107 }
108 if len(t.uses) > 0 {
109 use := t.uses[0]
110 t.uses = t.uses[1:]
111 t.visitValue(use)
112 continue
113 }
114 break
115 }
116
117
118 constCnt, rewireCnt := t.replaceConst()
119 if f.pass.debug > 0 {
120 if constCnt > 0 || rewireCnt > 0 {
121 fmt.Printf("Phase SCCP for %v : %v constants, %v dce\n", f.Name, constCnt, rewireCnt)
122 }
123 }
124 }
125
126 func equals(a, b lattice) bool {
127 if a == b {
128
129 return true
130 }
131 if a.tag != b.tag {
132 return false
133 }
134 if a.tag == constant {
135
136
137 v1 := a.val
138 v2 := b.val
139 if v1.Op == v2.Op && v1.AuxInt == v2.AuxInt {
140 return true
141 } else {
142 return false
143 }
144 }
145 return true
146 }
147
148
149
150 func possibleConst(val *Value) bool {
151 if isConst(val) {
152 return true
153 }
154 switch val.Op {
155 case OpCopy:
156 return true
157 case OpPhi:
158 return true
159 case
160
161 OpNeg8, OpNeg16, OpNeg32, OpNeg64, OpNeg32F, OpNeg64F,
162 OpCom8, OpCom16, OpCom32, OpCom64,
163
164 OpFloor, OpCeil, OpTrunc, OpRoundToEven, OpSqrt,
165
166 OpTrunc16to8, OpTrunc32to8, OpTrunc32to16, OpTrunc64to8,
167 OpTrunc64to16, OpTrunc64to32, OpCvt32to32F, OpCvt32to64F,
168 OpCvt64to32F, OpCvt64to64F, OpCvt32Fto32, OpCvt32Fto64,
169 OpCvt64Fto32, OpCvt64Fto64, OpCvt32Fto64F, OpCvt64Fto32F,
170 OpCvtBoolToUint8,
171 OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64, OpZeroExt16to32,
172 OpZeroExt16to64, OpZeroExt32to64, OpSignExt8to16, OpSignExt8to32,
173 OpSignExt8to64, OpSignExt16to32, OpSignExt16to64, OpSignExt32to64,
174
175 OpCtz8, OpCtz16, OpCtz32, OpCtz64,
176
177 OpSlicemask,
178
179 OpIsNonNil,
180
181 OpNot:
182 return true
183 case
184
185 OpAdd64, OpAdd32, OpAdd16, OpAdd8,
186 OpAdd32F, OpAdd64F,
187
188 OpSub64, OpSub32, OpSub16, OpSub8,
189 OpSub32F, OpSub64F,
190
191 OpMul64, OpMul32, OpMul16, OpMul8,
192 OpMul32F, OpMul64F,
193
194 OpDiv32F, OpDiv64F,
195 OpDiv8, OpDiv16, OpDiv32, OpDiv64,
196 OpDiv8u, OpDiv16u, OpDiv32u, OpDiv64u,
197 OpMod8, OpMod16, OpMod32, OpMod64,
198 OpMod8u, OpMod16u, OpMod32u, OpMod64u,
199
200 OpEq64, OpEq32, OpEq16, OpEq8,
201 OpEq32F, OpEq64F,
202 OpLess64, OpLess32, OpLess16, OpLess8,
203 OpLess64U, OpLess32U, OpLess16U, OpLess8U,
204 OpLess32F, OpLess64F,
205 OpLeq64, OpLeq32, OpLeq16, OpLeq8,
206 OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U,
207 OpLeq32F, OpLeq64F,
208 OpEqB, OpNeqB,
209
210 OpLsh64x64, OpRsh64x64, OpRsh64Ux64, OpLsh32x64,
211 OpRsh32x64, OpRsh32Ux64, OpLsh16x64, OpRsh16x64,
212 OpRsh16Ux64, OpLsh8x64, OpRsh8x64, OpRsh8Ux64,
213
214 OpIsInBounds, OpIsSliceInBounds,
215
216 OpAnd8, OpAnd16, OpAnd32, OpAnd64,
217 OpOr8, OpOr16, OpOr32, OpOr64,
218 OpXor8, OpXor16, OpXor32, OpXor64:
219 return true
220 default:
221 return false
222 }
223 }
224
225 func (t *worklist) getLatticeCell(val *Value) lattice {
226 if !possibleConst(val) {
227
228 return lattice{bottom, nil}
229 }
230 lt, exist := t.latticeCells[val]
231 if !exist {
232 return lattice{top, nil}
233 }
234 return lt
235 }
236
237 func isConst(val *Value) bool {
238 switch val.Op {
239 case OpConst64, OpConst32, OpConst16, OpConst8,
240 OpConstBool, OpConst32F, OpConst64F:
241 return true
242 default:
243 return false
244 }
245 }
246
247
248
249
250
251
252 func (t *worklist) buildDefUses() {
253 for _, block := range t.f.Blocks {
254 for _, val := range block.Values {
255 for _, arg := range val.Args {
256
257 if possibleConst(arg) && possibleConst(val) {
258 if _, exist := t.defUse[arg]; !exist {
259 t.defUse[arg] = make([]*Value, 0, arg.Uses)
260 }
261 t.defUse[arg] = append(t.defUse[arg], val)
262 }
263 }
264 }
265 for _, ctl := range block.ControlValues() {
266
267 if possibleConst(ctl) {
268 t.defBlock[ctl] = append(t.defBlock[ctl], block)
269 }
270 }
271 }
272 }
273
274
275 func (t *worklist) addUses(val *Value) {
276 for _, use := range t.defUse[val] {
277 if val == use {
278
279
280 continue
281 }
282 t.uses = append(t.uses, use)
283 }
284 for _, block := range t.defBlock[val] {
285 if t.visitedBlock[block.ID] {
286 t.propagate(block)
287 }
288 }
289 }
290
291
292 func (t *worklist) meet(val *Value) lattice {
293 optimisticLt := lattice{top, nil}
294 for i := 0; i < len(val.Args); i++ {
295 edge := Edge{val.Block, i}
296
297
298
299
300
301 if _, exist := t.visited[edge]; exist {
302 lt := t.getLatticeCell(val.Args[i])
303 if lt.tag == constant {
304 if optimisticLt.tag == top {
305 optimisticLt = lt
306 } else {
307 if !equals(optimisticLt, lt) {
308
309 return lattice{bottom, nil}
310 }
311 }
312 } else if lt.tag == bottom {
313
314 return lattice{bottom, nil}
315 } else {
316
317 }
318 } else {
319
320 }
321 }
322
323
324 return optimisticLt
325 }
326
327 func computeLattice(f *Func, val *Value, args ...*Value) lattice {
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353 constValue := f.newValue(val.Op, val.Type, f.Entry, val.Pos)
354 constValue.AddArgs(args...)
355 matched := rewriteValuegeneric(constValue)
356 if matched {
357 if isConst(constValue) {
358 return lattice{constant, constValue}
359 }
360 }
361
362
363
364 constValue.reset(OpInvalid)
365 return lattice{bottom, nil}
366 }
367
368 func (t *worklist) visitValue(val *Value) {
369 if !possibleConst(val) {
370
371
372 return
373 }
374
375 oldLt := t.getLatticeCell(val)
376 defer func() {
377
378 newLt := t.getLatticeCell(val)
379 if !equals(newLt, oldLt) {
380 if int8(oldLt.tag) > int8(newLt.tag) {
381 t.f.Fatalf("Must lower lattice\n")
382 }
383 t.addUses(val)
384 }
385 }()
386
387 switch val.Op {
388
389 case OpConst64, OpConst32, OpConst16, OpConst8,
390 OpConstBool, OpConst32F, OpConst64F:
391 t.latticeCells[val] = lattice{constant, val}
392
393 case OpCopy:
394 t.latticeCells[val] = t.getLatticeCell(val.Args[0])
395
396 case OpPhi:
397 t.latticeCells[val] = t.meet(val)
398
399 case
400
401 OpNeg8, OpNeg16, OpNeg32, OpNeg64, OpNeg32F, OpNeg64F,
402 OpCom8, OpCom16, OpCom32, OpCom64,
403
404 OpFloor, OpCeil, OpTrunc, OpRoundToEven, OpSqrt,
405
406 OpTrunc16to8, OpTrunc32to8, OpTrunc32to16, OpTrunc64to8,
407 OpTrunc64to16, OpTrunc64to32, OpCvt32to32F, OpCvt32to64F,
408 OpCvt64to32F, OpCvt64to64F, OpCvt32Fto32, OpCvt32Fto64,
409 OpCvt64Fto32, OpCvt64Fto64, OpCvt32Fto64F, OpCvt64Fto32F,
410 OpCvtBoolToUint8,
411 OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64, OpZeroExt16to32,
412 OpZeroExt16to64, OpZeroExt32to64, OpSignExt8to16, OpSignExt8to32,
413 OpSignExt8to64, OpSignExt16to32, OpSignExt16to64, OpSignExt32to64,
414
415 OpCtz8, OpCtz16, OpCtz32, OpCtz64,
416
417 OpSlicemask,
418
419 OpIsNonNil,
420
421 OpNot:
422 lt1 := t.getLatticeCell(val.Args[0])
423
424 if lt1.tag == constant {
425
426 t.latticeCells[val] = computeLattice(t.f, val, lt1.val)
427 } else {
428 t.latticeCells[val] = lattice{lt1.tag, nil}
429 }
430
431 case
432
433 OpAdd64, OpAdd32, OpAdd16, OpAdd8,
434 OpAdd32F, OpAdd64F,
435
436 OpSub64, OpSub32, OpSub16, OpSub8,
437 OpSub32F, OpSub64F,
438
439 OpMul64, OpMul32, OpMul16, OpMul8,
440 OpMul32F, OpMul64F,
441
442 OpDiv32F, OpDiv64F,
443 OpDiv8, OpDiv16, OpDiv32, OpDiv64,
444 OpDiv8u, OpDiv16u, OpDiv32u, OpDiv64u,
445
446 OpMod8, OpMod16, OpMod32, OpMod64,
447 OpMod8u, OpMod16u, OpMod32u, OpMod64u,
448
449 OpEq64, OpEq32, OpEq16, OpEq8,
450 OpEq32F, OpEq64F,
451 OpLess64, OpLess32, OpLess16, OpLess8,
452 OpLess64U, OpLess32U, OpLess16U, OpLess8U,
453 OpLess32F, OpLess64F,
454 OpLeq64, OpLeq32, OpLeq16, OpLeq8,
455 OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U,
456 OpLeq32F, OpLeq64F,
457 OpEqB, OpNeqB,
458
459 OpLsh64x64, OpRsh64x64, OpRsh64Ux64, OpLsh32x64,
460 OpRsh32x64, OpRsh32Ux64, OpLsh16x64, OpRsh16x64,
461 OpRsh16Ux64, OpLsh8x64, OpRsh8x64, OpRsh8Ux64,
462
463 OpIsInBounds, OpIsSliceInBounds,
464
465 OpAnd8, OpAnd16, OpAnd32, OpAnd64,
466 OpOr8, OpOr16, OpOr32, OpOr64,
467 OpXor8, OpXor16, OpXor32, OpXor64:
468 lt1 := t.getLatticeCell(val.Args[0])
469 lt2 := t.getLatticeCell(val.Args[1])
470
471 if lt1.tag == constant && lt2.tag == constant {
472
473 t.latticeCells[val] = computeLattice(t.f, val, lt1.val, lt2.val)
474 } else {
475 if lt1.tag == bottom || lt2.tag == bottom {
476 t.latticeCells[val] = lattice{bottom, nil}
477 } else {
478 t.latticeCells[val] = lattice{top, nil}
479 }
480 }
481 default:
482
483 }
484 }
485
486
487
488
489 func (t *worklist) propagate(block *Block) {
490 switch block.Kind {
491 case BlockExit, BlockRet, BlockRetJmp, BlockInvalid:
492
493 break
494 case BlockDefer:
495
496 t.edges = append(t.edges, block.Succs...)
497 case BlockFirst:
498 fallthrough
499 case BlockPlain:
500 t.edges = append(t.edges, block.Succs[0])
501 case BlockIf, BlockJumpTable:
502 cond := block.ControlValues()[0]
503 condLattice := t.getLatticeCell(cond)
504 if condLattice.tag == bottom {
505
506 t.edges = append(t.edges, block.Succs...)
507 } else if condLattice.tag == constant {
508
509 var branchIdx int64
510 if block.Kind == BlockIf {
511 branchIdx = 1 - condLattice.val.AuxInt
512 } else {
513 branchIdx = condLattice.val.AuxInt
514 if branchIdx < 0 || branchIdx >= int64(len(block.Succs)) {
515
516 break
517 }
518 }
519 t.edges = append(t.edges, block.Succs[branchIdx])
520 } else {
521
522 }
523 default:
524 t.f.Fatalf("All kind of block should be processed above.")
525 }
526 }
527
528
529
530
531 func rewireSuccessor(block *Block, constVal *Value) bool {
532 switch block.Kind {
533 case BlockIf:
534 block.removeEdge(int(constVal.AuxInt))
535 block.Kind = BlockPlain
536 block.Likely = BranchUnknown
537 block.ResetControls()
538 return true
539 case BlockJumpTable:
540
541 idx := int(constVal.AuxInt)
542 if idx < 0 || idx >= len(block.Succs) {
543
544
545
546
547 return false
548 }
549 block.swapSuccessorsByIdx(0, idx)
550 for len(block.Succs) > 1 {
551 block.removeEdge(1)
552 }
553 block.Kind = BlockPlain
554 block.Likely = BranchUnknown
555 block.ResetControls()
556 return true
557 default:
558 return false
559 }
560 }
561
562
563
564 func (t *worklist) replaceConst() (int, int) {
565 constCnt, rewireCnt := 0, 0
566 for val, lt := range t.latticeCells {
567 if lt.tag == constant {
568 if !isConst(val) {
569 if t.f.pass.debug > 0 {
570 fmt.Printf("Replace %v with %v\n", val.LongString(), lt.val.LongString())
571 }
572 val.reset(lt.val.Op)
573 val.AuxInt = lt.val.AuxInt
574 constCnt++
575 }
576
577 ctrlBlock := t.defBlock[val]
578 for _, block := range ctrlBlock {
579 if rewireSuccessor(block, lt.val) {
580 rewireCnt++
581 if t.f.pass.debug > 0 {
582 fmt.Printf("Rewire %v %v successors\n", block.Kind, block)
583 }
584 }
585 }
586 }
587 }
588 return constCnt, rewireCnt
589 }
590
View as plain text