func elimIf(f *Func, loadAddr *sparseSet, dom *Block) bool {
	// See if dom is an If with one arm that
	// is trivial and succeeded by the other
	// successor of dom.
	if dom.Kind != BlockIf || dom.Likely != BranchUnknown {
		return false
	}
	var simple, post *Block
	for i := range dom.Succs {
		bb, other := dom.Succs[i].Block(), dom.Succs[i^1].Block()
		if isLeafPlain(bb) && bb.Succs[0].Block() == other {
			simple = bb
			post = other
			break
		}
	}
	if simple == nil || len(post.Preds) != 2 || post == dom {
		return false
	}

	// We've found our diamond CFG of blocks.
	// Now decide if fusing 'simple' into dom+post
	// looks profitable.

	// Check that there are Phis, and that all of them
	// can be safely rewritten to CondSelect.
	hasphis := false
	for _, v := range post.Values {
		if v.Op == OpPhi {
			hasphis = true
			if !canCondSelect(v, f.Config.arch, loadAddr) {
				return false
			}
		}
	}
	if !hasphis {
		return false
	}

	// Pick some upper bound for the number of instructions
	// we'd be willing to execute just to generate a dead
	// argument to CondSelect. In the worst case, this is
	// the number of useless instructions executed.
	const maxfuseinsts = 2

	if len(simple.Values) > maxfuseinsts || !canSpeculativelyExecute(simple) {
		return false
	}

	// Replace Phi instructions in b with CondSelect instructions
	swap := (post.Preds[0].Block() == dom) != (dom.Succs[0].Block() == post)
	for _, v := range post.Values {
		if v.Op != OpPhi {
			continue
		}
		v.Op = OpCondSelect
		if swap {
			v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
		}
		v.AddArg(dom.Controls[0])
	}

	// Put all of the instructions into 'dom'
	// and update the CFG appropriately.
	dom.Kind = post.Kind
	dom.CopyControls(post)
	dom.Aux = post.Aux
	dom.Succs = append(dom.Succs[:0], post.Succs...)
	for i := range dom.Succs {
		e := dom.Succs[i]
		e.b.Preds[e.i].b = dom
	}

	// Try really hard to preserve statement marks attached to blocks.
	simplePos := simple.Pos
	postPos := post.Pos
	simpleStmt := simplePos.IsStmt() == src.PosIsStmt
	postStmt := postPos.IsStmt() == src.PosIsStmt

	for _, v := range simple.Values {
		v.Block = dom
	}
	for _, v := range post.Values {
		v.Block = dom
	}

	// findBlockPos determines if b contains a stmt-marked value
	// that has the same line number as the Pos for b itself.
	// (i.e. is the position on b actually redundant?)
	findBlockPos := func(b *Block) bool {
		pos := b.Pos
		for _, v := range b.Values {
			// See if there is a stmt-marked value already that matches simple.Pos (and perhaps post.Pos)
			if pos.SameFileAndLine(v.Pos) && v.Pos.IsStmt() == src.PosIsStmt {
				return true
			}
		}
		return false
	}
	if simpleStmt {
		simpleStmt = !findBlockPos(simple)
		if !simpleStmt && simplePos.SameFileAndLine(postPos) {
			postStmt = false
		}

	}
	if postStmt {
		postStmt = !findBlockPos(post)
	}

	// If simpleStmt and/or postStmt are still true, then try harder
	// to find the corresponding statement marks new homes.

	// setBlockPos determines if b contains a can-be-statement value
	// that has the same line number as the Pos for b itself, and
	// puts a statement mark on it, and returns whether it succeeded
	// in this operation.
	setBlockPos := func(b *Block) bool {
		pos := b.Pos
		for _, v := range b.Values {
			if pos.SameFileAndLine(v.Pos) && !isPoorStatementOp(v.Op) {
				v.Pos = v.Pos.WithIsStmt()
				return true
			}
		}
		return false
	}
	// If necessary and possible, add a mark to a value in simple
	if simpleStmt {
		if setBlockPos(simple) && simplePos.SameFileAndLine(postPos) {
			postStmt = false
		}
	}
	// If necessary and possible, add a mark to a value in post
	if postStmt {
		postStmt = !setBlockPos(post)
	}

	// Before giving up (this was added because it helps), try the end of "dom", and if that is not available,
	// try the values in the successor block if it is uncomplicated.
	if postStmt {
		if dom.Pos.IsStmt() != src.PosIsStmt {
			dom.Pos = postPos
		} else {
			// Try the successor block
			if len(dom.Succs) == 1 && len(dom.Succs[0].Block().Preds) == 1 {
				succ := dom.Succs[0].Block()
				for _, v := range succ.Values {
					if isPoorStatementOp(v.Op) {
						continue
					}
					if postPos.SameFileAndLine(v.Pos) {
						v.Pos = v.Pos.WithIsStmt()
					}
					postStmt = false
					break
				}
				// If postStmt still true, tag the block itself if possible
				if postStmt && succ.Pos.IsStmt() != src.PosIsStmt {
					succ.Pos = postPos
				}
			}
		}
	}

	dom.Values = append(dom.Values, simple.Values...)
	dom.Values = append(dom.Values, post.Values...)

	// Trash 'post' and 'simple'
	clobberBlock(post)
	clobberBlock(simple)

	f.invalidateCFG()
	return true
}
// elimIf converts the one-way branch starting at dom in f to a conditional move if possible.
// loadAddr is a set of values which are used to compute the address of a load.
// Those values are exempt from CMOV generation.
elimIf converts the one-way branch starting at dom in f to a conditional move if possible.
loadAddr is a set of values which are used to compute the address of a load.
Those values are exempt from CMOV generation.
// elimIf converts the one - way branch starting at dom in f to a conditional move if possible . // loadAddr is a set of values which are used to compute the address of a load . // Those values are exempt from CMOV generation .
func elimIf(f *Func, loadAddr *sparseSet, dom *Block) bool {
	if dom.Kind != BlockIf || dom.Likely != BranchUnknown {
		return false
	}
	var simple, post *Block
	for i := range dom.Succs {
		bb, other := dom.Succs[i].Block(), dom.Succs[i^1].Block()
		if isLeafPlain(bb) && bb.Succs[0].Block() == other {
			simple = bb
			post = other
			break
		}
	}
	if simple == nil || len(post.Preds) != 2 || post == dom {
		return false
	}
	hasphis := false
	for _, v := range post.Values {
		if v.Op == OpPhi {
			hasphis = true
			if !canCondSelect(v, f.Config.arch, loadAddr) {
				return false
			}
		}
	}
	if !hasphis {
		return false
	}
	const maxfuseinsts = 2
	if len(simple.Values) > maxfuseinsts || !canSpeculativelyExecute(simple) {
		return false
	}
	swap := (post.Preds[0].Block() == dom) != (dom.Succs[0].Block() == post)
	for _, v := range post.Values {
		if v.Op != OpPhi {
			continue
		}
		v.Op = OpCondSelect
		if swap {
			v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
		}
		v.AddArg(dom.Controls[0])
	}
	dom.Kind = post.Kind
	dom.CopyControls(post)
	dom.Aux = post.Aux
	dom.Succs = append(dom.Succs[:0], post.Succs...)
	for i := range dom.Succs {
		e := dom.Succs[i]
		e.b.Preds[e.i].b = dom
	}
	simplePos := simple.Pos
	postPos := post.Pos
	simpleStmt := simplePos.IsStmt() == src.PosIsStmt
	postStmt := postPos.IsStmt() == src.PosIsStmt
	for _, v := range simple.Values {
		v.Block = dom
	}
	for _, v := range post.Values {
		v.Block = dom
	}
	findBlockPos := func(b *Block) bool {
		pos := b.Pos
		for _, v := range b.Values {
			if pos.SameFileAndLine(v.Pos) && v.Pos.IsStmt() == src.PosIsStmt {
				return true
			}
		}
		return false
	}
	if simpleStmt {
		simpleStmt = !findBlockPos(simple)
		if !simpleStmt && simplePos.SameFileAndLine(postPos) {
			postStmt = false
		}
	}
	if postStmt {
		postStmt = !findBlockPos(post)
	}
	setBlockPos := func(b *Block) bool {
		pos := b.Pos
		for _, v := range b.Values {
			if pos.SameFileAndLine(v.Pos) && !isPoorStatementOp(v.Op) {
				v.Pos = v.Pos.WithIsStmt()
				return true
			}
		}
		return false
	}
	if simpleStmt {
		if setBlockPos(simple) && simplePos.SameFileAndLine(postPos) {
			postStmt = false
		}
	}
	if postStmt {
		postStmt = !setBlockPos(post)
	}
	if postStmt {
		if dom.Pos.IsStmt() != src.PosIsStmt {
			dom.Pos = postPos
		} else {
			if len(dom.Succs) == 1 && len(dom.Succs[0].Block().Preds) == 1 {
				succ := dom.Succs[0].Block()
				for _, v := range succ.Values {
					if isPoorStatementOp(v.Op) {
						continue
					}
					if postPos.SameFileAndLine(v.Pos) {
						v.Pos = v.Pos.WithIsStmt()
					}
					postStmt = false
					break
				}
				if postStmt && succ.Pos.IsStmt() != src.PosIsStmt {
					succ.Pos = postPos
				}
			}
		}
	}
	dom.Values = append(dom.Values, simple.Values...)
	dom.Values = append(dom.Values, post.Values...)
	clobberBlock(post)
	clobberBlock(simple)
	f.invalidateCFG()
	return true
}
func elimIf ( f * Func , loadAddr * sparseSet , dom * Block ) bool { if dom . Kind != BlockIf || dom . Likely != BranchUnknown { return false } var simple , post * Block for i := range dom . Succs { bb , other := dom . Succs [ i ] . Block ( ) , dom . Succs [ i ^ 1 ] . Block ( ) if isLeafPlain ( bb ) && bb . Succs [ 0 ] . Block ( ) == other { simple = bb post = other break } } if simple == nil || len ( post . Preds ) != 2 || post == dom { return false } hasphis := false for _ , v := range post . Values { if v . Op == OpPhi { hasphis = true if ! canCondSelect ( v , f . Config . arch , loadAddr ) { return false } } } if ! hasphis { return false } const maxfuseinsts = 2 if len ( simple . Values ) > maxfuseinsts || ! canSpeculativelyExecute ( simple ) { return false } swap := ( post . Preds [ 0 ] . Block ( ) == dom ) != ( dom . Succs [ 0 ] . Block ( ) == post ) for _ , v := range post . Values { if v . Op != OpPhi { continue } v . Op = OpCondSelect if swap { v . Args [ 0 ] , v . Args [ 1 ] = v . Args [ 1 ] , v . Args [ 0 ] } v . AddArg ( dom . Controls [ 0 ] ) } dom . Kind = post . Kind dom . CopyControls ( post ) dom . Aux = post . Aux dom . Succs = append ( dom . Succs [ : 0 ] , post . Succs ... ) for i := range dom . Succs { e := dom . Succs [ i ] e . b . Preds [ e . i ] . b = dom } simplePos := simple . Pos postPos := post . Pos simpleStmt := simplePos . IsStmt ( ) == src . PosIsStmt postStmt := postPos . IsStmt ( ) == src . PosIsStmt for _ , v := range simple . Values { v . Block = dom } for _ , v := range post . Values { v . Block = dom } findBlockPos := func ( b * Block ) bool { pos := b . Pos for _ , v := range b . Values { if pos . SameFileAndLine ( v . Pos ) && v . Pos . IsStmt ( ) == src . PosIsStmt { return true } } return false } if simpleStmt { simpleStmt = ! findBlockPos ( simple ) if ! simpleStmt && simplePos . SameFileAndLine ( postPos ) { postStmt = false } } if postStmt { postStmt = ! findBlockPos ( post ) } setBlockPos := func ( b * Block ) bool { pos := b . Pos for _ , v := range b . Values { if pos . SameFileAndLine ( v . Pos ) && ! isPoorStatementOp ( v . Op ) { v . Pos = v . Pos . WithIsStmt ( ) return true } } return false } if simpleStmt { if setBlockPos ( simple ) && simplePos . SameFileAndLine ( postPos ) { postStmt = false } } if postStmt { postStmt = ! setBlockPos ( post ) } if postStmt { if dom . Pos . IsStmt ( ) != src . PosIsStmt { dom . Pos = postPos } else { if len ( dom . Succs ) == 1 && len ( dom . Succs [ 0 ] . Block ( ) . Preds ) == 1 { succ := dom . Succs [ 0 ] . Block ( ) for _ , v := range succ . Values { if isPoorStatementOp ( v . Op ) { continue } if postPos . SameFileAndLine ( v . Pos ) { v . Pos = v . Pos . WithIsStmt ( ) } postStmt = false break } if postStmt && succ . Pos . IsStmt ( ) != src . PosIsStmt { succ . Pos = postPos } } } } dom . Values = append ( dom . Values , simple . Values ... ) dom . Values = append ( dom . Values , post . Values ... ) clobberBlock ( post ) clobberBlock ( simple ) f . invalidateCFG ( ) return true }
elimIf converts the one-way branch starting at dom in f to a conditional move if possible.
elimIf converts the one - way branch starting at dom in f to a conditional move if possible .
// See if dom is an If with one arm that // is trivial and succeeded by the other // successor of dom. // We've found our diamond CFG of blocks. // Now decide if fusing 'simple' into dom+post // looks profitable. // Check that there are Phis, and that all of them // can be safely rewritten to CondSelect. // Pick some upper bound for the number of instructions // we'd be willing to execute just to generate a dead // argument to CondSelect. In the worst case, this is // the number of useless instructions executed. // Replace Phi instructions in b with CondSelect instructions // Put all of the instructions into 'dom' // and update the CFG appropriately. // Try really hard to preserve statement marks attached to blocks. // findBlockPos determines if b contains a stmt-marked value // that has the same line number as the Pos for b itself. // (i.e. is the position on b actually redundant?) // See if there is a stmt-marked value already that matches simple.Pos (and perhaps post.Pos) // If simpleStmt and/or postStmt are still true, then try harder // to find the corresponding statement marks new homes. // setBlockPos determines if b contains a can-be-statement value // that has the same line number as the Pos for b itself, and // puts a statement mark on it, and returns whether it succeeded // in this operation. // If necessary and possible, add a mark to a value in simple // If necessary and possible, add a mark to a value in post // Before giving up (this was added because it helps), try the end of "dom", and if that is not available, // try the values in the successor block if it is uncomplicated. // Try the successor block // If postStmt still true, tag the block itself if possible // Trash 'post' and 'simple'