@@ -156,20 +156,6 @@ func isConst(val *Value) bool {
156
156
}
157
157
}
158
158
159
- func isDivByZero (op Op , divisor * Value ) bool {
160
- switch op {
161
- case OpDiv32F , OpDiv64F ,
162
- OpDiv8 , OpDiv16 , OpDiv32 , OpDiv64 ,
163
- OpMod8 , OpMod16 , OpMod32 , OpMod64 ,
164
- OpDiv8u , OpDiv16u , OpDiv32u , OpDiv64u ,
165
- OpMod8u , OpMod16u , OpMod32u , OpMod64u :
166
- if divisor .AuxInt == 0 {
167
- return true
168
- }
169
- }
170
- return false
171
- }
172
-
173
159
// buildDefUses builds def-use chain for some values early, because once the lattice of
174
160
// a value is changed, we need to update lattices of use. But we don't need all uses of
175
161
// it, only uses that can become constants would be added into re-visit worklist since
@@ -251,41 +237,46 @@ func (t *worklist) visitPhi(val *Value) {
251
237
t .latticeCells [val ] = meet (argLattice )
252
238
}
253
239
254
- func computeConstValue (f * Func , val * Value , args ... * Value ) ( * Value , bool ) {
240
+ func computeLattice (f * Func , val * Value , args ... * Value ) lattice {
255
241
// In general, we need to perform constant evaluation based on two constant lattices:
256
242
//
257
243
// var res = lattice{constant, nil}
258
244
// switch op {
259
- // case OpAdd16 :
260
- // res.val = newConst(argLt1.val.AuxInt16() + argLt2.val.AuxInt16())
245
+ // case OpAdd16:
246
+ // res.val = newConst(argLt1.val.AuxInt16() + argLt2.val.AuxInt16())
261
247
// case OpAdd32:
262
248
// res.val = newConst(argLt1.val.AuxInt32() + argLt2.val.AuxInt32())
263
- // ...
249
+ // case OpDiv8:
250
+ // if !isDivideByZero(argLt2.val.AuxInt8()) {
251
+ // res.val = newConst(argLt1.val.AuxInt8() / argLt2.val.AuxInt8())
252
+ // }
253
+ // ...
264
254
// }
265
255
//
266
- // However, this wouold create a huge switch for all opcodes that can be evaluted during
267
- // compile time, it's fragile and error prone. We did a trick by reusing the existing rules
268
- // in generic rules for compile-time evaluation. But generic rules rewrite original value,
269
- // this behavior is undesired, because the lattice of values may change multiple times, once
270
- // it was rewritten, we lose the opportunity to change it permanently, which can lead to
271
- // errors. For example, We cannot change its value immediately after visiting Phi, because
272
- // some of its input edges may still not be visited at this moment.
256
+ // However, this would create a huge switch for all opcodes that can be evaluted during
257
+ // compile time. Moreover, some operations can be evaluated only if its arguments
258
+ // satisfy additional conditions(e.g. divide by zero). It's fragile and error prone. We
259
+ // did a trick by reusing the existing rules in generic rules for compile-time evaluation.
260
+ // But generic rules rewrite original value, this behavior is undesired, because the lattice
261
+ // of values may change multiple times, once it was rewritten, we lose the opportunity to
262
+ // change it permanently, which can lead to errors. For example, We cannot change its value
263
+ // immediately after visiting Phi, because some of its input edges may still not be visited
264
+ // at this moment.
273
265
var constValue = f .newValue (val .Op , val .Type , f .Entry , val .Pos )
274
266
constValue .AddArgs (args ... )
275
267
var matched = rewriteValuegeneric (constValue )
276
268
if matched {
277
- if ! isConst (constValue ) {
278
- // If we are able to match the above selected opcodes in generic rules
279
- // the rewrited value must be a constant value
280
- f .Fatalf ("%v must be a constant value, missing or matched unexpected generic rule?" ,
281
- val .LongString ())
269
+ if isConst (constValue ) {
270
+ return lattice {constant , constValue }
282
271
}
283
272
}
284
- return constValue , matched
273
+ // Either we can not match generic rules for given value or it does not satisfy additional
274
+ // constraints(e.g. divide by zero)
275
+ return lattice {bottom , nil }
285
276
}
286
277
287
278
func (t * worklist ) visitValue (val * Value ) {
288
- if ! possibleConst (val ) {
279
+ if ! possibleConst (val ) || ( val . Op == OpCopy && ! possibleConst ( val . Args [ 0 ])) {
289
280
// fast fail
290
281
return
291
282
}
@@ -335,13 +326,7 @@ func (t *worklist) visitValue(val *Value) {
335
326
return
336
327
}
337
328
338
- // here we take a shortcut by reusing generic rules to fold constants
339
- var constValue , matched = computeConstValue (t .f , val , lt1 .val )
340
- if matched {
341
- t .latticeCells [val ] = lattice {constant , constValue }
342
- } else {
343
- t .latticeCells [val ] = worstLt
344
- }
329
+ t .latticeCells [val ] = computeLattice (t .f , val , lt1 .val )
345
330
// fold 2-input operations
346
331
case
347
332
// add
@@ -382,18 +367,13 @@ func (t *worklist) visitValue(val *Value) {
382
367
OpXor8 , OpXor16 , OpXor32 , OpXor64 :
383
368
var lt1 = t .getLatticeCell (val .Args [0 ])
384
369
var lt2 = t .getLatticeCell (val .Args [1 ])
385
- if lt1 .tag != constant || lt2 .tag != constant || isDivByZero ( val . Op , lt2 . val ) {
370
+ if lt1 .tag != constant || lt2 .tag != constant {
386
371
t .latticeCells [val ] = worstLt
387
372
return
388
373
}
389
374
390
375
// here we take a shortcut by reusing generic rules to fold constants
391
- var constValue , matched = computeConstValue (t .f , val , lt1 .val , lt2 .val )
392
- if matched {
393
- t .latticeCells [val ] = lattice {constant , constValue }
394
- } else {
395
- t .latticeCells [val ] = worstLt
396
- }
376
+ t .latticeCells [val ] = computeLattice (t .f , val , lt1 .val , lt2 .val )
397
377
default :
398
378
// Any other type of value cannot be a constant, they are always worst(Bottom)
399
379
}
@@ -531,9 +511,9 @@ func sccp(f *Func) {
531
511
532
512
// apply optimizations based on discovered constants
533
513
var constCnt , rewireCnt = t .replaceConst ()
534
- if f .pass .debug > 0 {
535
- if constCnt > 0 || rewireCnt > 0 {
536
- fmt .Printf ("Phase SCCP for %v : %v constants, %v dce\n " , f .Name , constCnt , rewireCnt )
537
- }
514
+ // if f.pass.debug > 0 {
515
+ if constCnt > 0 || rewireCnt > 0 {
516
+ fmt .Printf ("Phase SCCP for %v : %v constants, %v dce\n " , f .Name , constCnt , rewireCnt )
538
517
}
518
+ // }
539
519
}
0 commit comments