func elimIfElse(f *Func, loadAddr *sparseSet, b *Block) bool {
	// See if 'b' ends in an if/else: it should
	// have two successors, both of which are BlockPlain
	// and succeeded by the same block.
	if b.Kind != BlockIf || b.Likely != BranchUnknown {
		return false
	}
	yes, no := b.Succs[0].Block(), b.Succs[1].Block()
	if !isLeafPlain(yes) || len(yes.Values) > 1 || !canSpeculativelyExecute(yes) {
		return false
	}
	if !isLeafPlain(no) || len(no.Values) > 1 || !canSpeculativelyExecute(no) {
		return false
	}
	if b.Succs[0].Block().Succs[0].Block() != b.Succs[1].Block().Succs[0].Block() {
		return false
	}
	// block that postdominates the if/else
	post := b.Succs[0].Block().Succs[0].Block()
	if len(post.Preds) != 2 || post == b {
		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
	}

	// Don't generate CondSelects if branch is cheaper.
	if !shouldElimIfElse(no, yes, post, f.Config.arch) {
		return false
	}

	// now we're committed: rewrite each Phi as a CondSelect
	swap := post.Preds[0].Block() != b.Succs[0].Block()
	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(b.Controls[0])
	}

	// Move the contents of all of these
	// blocks into 'b' and update CFG edges accordingly
	b.Kind = post.Kind
	b.CopyControls(post)
	b.Aux = post.Aux
	b.Succs = append(b.Succs[:0], post.Succs...)
	for i := range b.Succs {
		e := b.Succs[i]
		e.b.Preds[e.i].b = b
	}
	for i := range post.Values {
		post.Values[i].Block = b
	}
	for i := range yes.Values {
		yes.Values[i].Block = b
	}
	for i := range no.Values {
		no.Values[i].Block = b
	}
	b.Values = append(b.Values, yes.Values...)
	b.Values = append(b.Values, no.Values...)
	b.Values = append(b.Values, post.Values...)

	// trash post, yes, and no
	clobberBlock(yes)
	clobberBlock(no)
	clobberBlock(post)

	f.invalidateCFG()
	return true
}
// elimIfElse converts the two-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.
elimIfElse converts the two-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.
// elimIfElse converts the two - 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 elimIfElse(f *Func, loadAddr *sparseSet, b *Block) bool {
	if b.Kind != BlockIf || b.Likely != BranchUnknown {
		return false
	}
	yes, no := b.Succs[0].Block(), b.Succs[1].Block()
	if !isLeafPlain(yes) || len(yes.Values) > 1 || !canSpeculativelyExecute(yes) {
		return false
	}
	if !isLeafPlain(no) || len(no.Values) > 1 || !canSpeculativelyExecute(no) {
		return false
	}
	if b.Succs[0].Block().Succs[0].Block() != b.Succs[1].Block().Succs[0].Block() {
		return false
	}
	post := b.Succs[0].Block().Succs[0].Block()
	if len(post.Preds) != 2 || post == b {
		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
	}
	if !shouldElimIfElse(no, yes, post, f.Config.arch) {
		return false
	}
	swap := post.Preds[0].Block() != b.Succs[0].Block()
	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(b.Controls[0])
	}
	b.Kind = post.Kind
	b.CopyControls(post)
	b.Aux = post.Aux
	b.Succs = append(b.Succs[:0], post.Succs...)
	for i := range b.Succs {
		e := b.Succs[i]
		e.b.Preds[e.i].b = b
	}
	for i := range post.Values {
		post.Values[i].Block = b
	}
	for i := range yes.Values {
		yes.Values[i].Block = b
	}
	for i := range no.Values {
		no.Values[i].Block = b
	}
	b.Values = append(b.Values, yes.Values...)
	b.Values = append(b.Values, no.Values...)
	b.Values = append(b.Values, post.Values...)
	clobberBlock(yes)
	clobberBlock(no)
	clobberBlock(post)
	f.invalidateCFG()
	return true
}
func elimIfElse ( f * Func , loadAddr * sparseSet , b * Block ) bool { if b . Kind != BlockIf || b . Likely != BranchUnknown { return false } yes , no := b . Succs [ 0 ] . Block ( ) , b . Succs [ 1 ] . Block ( ) if ! isLeafPlain ( yes ) || len ( yes . Values ) > 1 || ! canSpeculativelyExecute ( yes ) { return false } if ! isLeafPlain ( no ) || len ( no . Values ) > 1 || ! canSpeculativelyExecute ( no ) { return false } if b . Succs [ 0 ] . Block ( ) . Succs [ 0 ] . Block ( ) != b . Succs [ 1 ] . Block ( ) . Succs [ 0 ] . Block ( ) { return false } post := b . Succs [ 0 ] . Block ( ) . Succs [ 0 ] . Block ( ) if len ( post . Preds ) != 2 || post == b { 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 } if ! shouldElimIfElse ( no , yes , post , f . Config . arch ) { return false } swap := post . Preds [ 0 ] . Block ( ) != b . Succs [ 0 ] . Block ( ) 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 ( b . Controls [ 0 ] ) } b . Kind = post . Kind b . CopyControls ( post ) b . Aux = post . Aux b . Succs = append ( b . Succs [ : 0 ] , post . Succs ... ) for i := range b . Succs { e := b . Succs [ i ] e . b . Preds [ e . i ] . b = b } for i := range post . Values { post . Values [ i ] . Block = b } for i := range yes . Values { yes . Values [ i ] . Block = b } for i := range no . Values { no . Values [ i ] . Block = b } b . Values = append ( b . Values , yes . Values ... ) b . Values = append ( b . Values , no . Values ... ) b . Values = append ( b . Values , post . Values ... ) clobberBlock ( yes ) clobberBlock ( no ) clobberBlock ( post ) f . invalidateCFG ( ) return true }
elimIfElse converts the two-way branch starting at dom in f to a conditional move if possible.
elimIfElse converts the two - way branch starting at dom in f to a conditional move if possible .
// See if 'b' ends in an if/else: it should // have two successors, both of which are BlockPlain // and succeeded by the same block. // block that postdominates the if/else // Don't generate CondSelects if branch is cheaper. // now we're committed: rewrite each Phi as a CondSelect // Move the contents of all of these // blocks into 'b' and update CFG edges accordingly // trash post, yes, and no