Skip to content

Commit f50a254

Browse files
committed
remove divideByZero and check it by generic rules; fast fail for copy
1 parent 211d014 commit f50a254

File tree

1 file changed

+30
-50
lines changed
  • src/cmd/compile/internal/ssa

1 file changed

+30
-50
lines changed

src/cmd/compile/internal/ssa/sccp.go

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,6 @@ func isConst(val *Value) bool {
156156
}
157157
}
158158

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-
173159
// buildDefUses builds def-use chain for some values early, because once the lattice of
174160
// a value is changed, we need to update lattices of use. But we don't need all uses of
175161
// 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) {
251237
t.latticeCells[val] = meet(argLattice)
252238
}
253239

254-
func computeConstValue(f *Func, val *Value, args ...*Value) (*Value, bool) {
240+
func computeLattice(f *Func, val *Value, args ...*Value) lattice {
255241
// In general, we need to perform constant evaluation based on two constant lattices:
256242
//
257243
// var res = lattice{constant, nil}
258244
// 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())
261247
// case OpAdd32:
262248
// 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+
// ...
264254
// }
265255
//
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.
273265
var constValue = f.newValue(val.Op, val.Type, f.Entry, val.Pos)
274266
constValue.AddArgs(args...)
275267
var matched = rewriteValuegeneric(constValue)
276268
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}
282271
}
283272
}
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}
285276
}
286277

287278
func (t *worklist) visitValue(val *Value) {
288-
if !possibleConst(val) {
279+
if !possibleConst(val) || (val.Op == OpCopy && !possibleConst(val.Args[0])) {
289280
// fast fail
290281
return
291282
}
@@ -335,13 +326,7 @@ func (t *worklist) visitValue(val *Value) {
335326
return
336327
}
337328

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)
345330
// fold 2-input operations
346331
case
347332
// add
@@ -382,18 +367,13 @@ func (t *worklist) visitValue(val *Value) {
382367
OpXor8, OpXor16, OpXor32, OpXor64:
383368
var lt1 = t.getLatticeCell(val.Args[0])
384369
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 {
386371
t.latticeCells[val] = worstLt
387372
return
388373
}
389374

390375
// 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)
397377
default:
398378
// Any other type of value cannot be a constant, they are always worst(Bottom)
399379
}
@@ -531,9 +511,9 @@ func sccp(f *Func) {
531511

532512
// apply optimizations based on discovered constants
533513
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)
538517
}
518+
// }
539519
}

0 commit comments

Comments
 (0)