func NewGeInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Ige
	case types.TUint:
		op = Uge
	case types.TFloat:
		op = Fge
	default:
		return Instr{}, fmt.Errorf("invalid type %s for >= comparison", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
NewGeInstr creates a new greater-equal instruction based on the
type t.
package ssa
import (
	"fmt"
	"io"
	"math/big"
	"github.com/markkurossi/mpc/circuit"
	"github.com/markkurossi/mpc/compiler/circuits"
	"github.com/markkurossi/mpc/types"
)
type Operand uint8
const (
	Iadd Operand = iota
	Uadd
	Fadd
	Isub
	Usub
	Fsub
	Bor
	Bxor
	Band
	Bclr
	Bts
	Btc
	Imult
	Umult
	Fmult
	Idiv
	Udiv
	Fdiv
	Imod
	Umod
	Fmod
	Lshift
	Rshift
	Srshift
	Slice
	Ilt
	Ult
	Flt
	Ile
	Ule
	Fle
	Igt
	Ugt
	Fgt
	Ige
	Uge
	Fge
	Eq
	Neq
	And
	Or
	Mov
	Smov
	Amov
	Phi
	Ret
	Circ
	Builtin
	GC
)
var operands = map[Operand]string{
	Iadd:    "iadd",
	Uadd:    "uadd",
	Fadd:    "fadd",
	Isub:    "isub",
	Usub:    "usub",
	Fsub:    "fsub",
	Band:    "band",
	Bor:     "bor",
	Bxor:    "bxor",
	Bclr:    "bclr",
	Bts:     "bts",
	Btc:     "btc",
	Imult:   "imult",
	Umult:   "umult",
	Fmult:   "fmult",
	Idiv:    "idiv",
	Udiv:    "udiv",
	Fdiv:    "fdiv",
	Imod:    "imod",
	Umod:    "umod",
	Fmod:    "fmod",
	Lshift:  "lshift",
	Rshift:  "rshift",
	Srshift: "srshift",
	Slice:   "slice",
	Ilt:     "ilt",
	Ult:     "ult",
	Flt:     "flt",
	Ile:     "ile",
	Ule:     "ule",
	Fle:     "fle",
	Igt:     "igt",
	Ugt:     "ugt",
	Fgt:     "fgt",
	Ige:     "ige",
	Uge:     "uge",
	Fge:     "fge",
	Eq:      "eq",
	Neq:     "neq",
	And:     "and",
	Or:      "or",
	Mov:     "mov",
	Smov:    "smov",
	Amov:    "amov",
	Phi:     "phi",
	Ret:     "ret",
	Circ:    "circ",
	Builtin: "builtin",
	GC:      "gc",
}
var maxOperandLength int
func init() {
	for _, v := range operands {
		if len(v) > maxOperandLength {
			maxOperandLength = len(v)
		}
	}
}
func (op Operand) String() string {
	name, ok := operands[op]
	if ok {
		return name
	}
	return fmt.Sprintf("{Operand %d}", op)
}
type Instr struct {
	Op      Operand
	In      []Value
	Out     *Value
	Label   *Block
	Circ    *circuit.Circuit
	Builtin circuits.Builtin
	GC      string
	Ret     []Value
}
func (i Instr) Check() {
	for _, in := range i.In {
		in.Check()
	}
}
func NewAddInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Iadd
	case types.TUint:
		op = Uadd
	case types.TFloat:
		op = Fadd
	default:
		fmt.Printf("%v + %v (%v)\n", l, r, t)
		return Instr{}, fmt.Errorf("invalid type %s for addition", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewSubInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Isub
	case types.TUint:
		op = Usub
	case types.TFloat:
		op = Fsub
	default:
		return Instr{}, fmt.Errorf("invalid type %s for subtraction", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewMultInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Imult
	case types.TUint:
		op = Umult
	case types.TFloat:
		op = Fmult
	default:
		return Instr{}, fmt.Errorf("invalid type %s for multiplication", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewDivInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Idiv
	case types.TUint:
		op = Udiv
	case types.TFloat:
		op = Fdiv
	default:
		return Instr{}, fmt.Errorf("invalid type %s for division", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewModInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Imod
	case types.TUint:
		op = Umod
	case types.TFloat:
		op = Fmod
	default:
		return Instr{}, fmt.Errorf("invalid type %s for modulo", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewLshiftInstr(l, r, o Value) Instr {
	return Instr{
		Op:  Lshift,
		In:  []Value{l, r},
		Out: &o,
	}
}
func NewRshiftInstr(l, r, o Value) Instr {
	return Instr{
		Op:  Rshift,
		In:  []Value{l, r},
		Out: &o,
	}
}
func NewSrshiftInstr(l, r, o Value) Instr {
	return Instr{
		Op:  Srshift,
		In:  []Value{l, r},
		Out: &o,
	}
}
func NewSliceInstr(v, from, to, o Value) Instr {
	return Instr{
		Op:  Slice,
		In:  []Value{v, from, to},
		Out: &o,
	}
}
func NewLtInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Ilt
	case types.TUint:
		op = Ult
	case types.TFloat:
		op = Flt
	default:
		return Instr{}, fmt.Errorf("invalid type %s for < comparison", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewLeInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Ile
	case types.TUint:
		op = Ule
	case types.TFloat:
		op = Fle
	default:
		return Instr{}, fmt.Errorf("invalid type %s for <= comparison", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}
func NewGtInstr(t types.Info, l, r, o Value) (Instr, error) {
	var op Operand
	switch t.Type {
	case types.TInt:
		op = Igt
	case types.TUint:
		op = Ugt
	case types.TFloat:
		op = Fgt
	default:
		return Instr{}, fmt.Errorf("invalid type %s for > comparison", t)
	}
	return Instr{
		Op:  op,
		In:  []Value{l, r},
		Out: &o,
	}, nil
}