mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
634 lines
11 KiB
Go
634 lines
11 KiB
Go
//
|
|
// Copyright (c) 2020-2024 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/circuits"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
|
|
)
|
|
|
|
// Operand specifies SSA assembly operand
|
|
type Operand uint8
|
|
|
|
// SSA assembly operands.
|
|
const (
|
|
Iadd Operand = iota
|
|
Uadd
|
|
Fadd
|
|
Isub
|
|
Usub
|
|
Fsub
|
|
Bor
|
|
Bxor
|
|
Band
|
|
Bclr
|
|
Bts
|
|
Btc
|
|
Imult
|
|
Umult
|
|
Fmult
|
|
Idiv
|
|
Udiv
|
|
Fdiv
|
|
Imod
|
|
Umod
|
|
Fmod
|
|
Concat
|
|
Lshift
|
|
Rshift
|
|
Srshift
|
|
Slice
|
|
Index
|
|
Ilt
|
|
Ult
|
|
Flt
|
|
Ile
|
|
Ule
|
|
Fle
|
|
Igt
|
|
Ugt
|
|
Fgt
|
|
Ige
|
|
Uge
|
|
Fge
|
|
Eq
|
|
Neq
|
|
And
|
|
Or
|
|
Not
|
|
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",
|
|
Concat: "concat",
|
|
Lshift: "lshift",
|
|
Rshift: "rshift",
|
|
Srshift: "srshift",
|
|
Slice: "slice",
|
|
Index: "index",
|
|
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",
|
|
Not: "not",
|
|
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)
|
|
}
|
|
|
|
// Instr implements SSA assembly instruction.
|
|
type Instr struct {
|
|
Op Operand
|
|
In []Value
|
|
Out *Value
|
|
Label *Block
|
|
Circ *circuit.Circuit
|
|
Builtin circuits.Builtin
|
|
GC *Value
|
|
Ret []Value
|
|
}
|
|
|
|
// Check verifies that the instruction values are properly set. If any
|
|
// unspecified values are found, the Check function panics.
|
|
func (i Instr) Check() {
|
|
for _, in := range i.In {
|
|
in.Check()
|
|
}
|
|
}
|
|
|
|
// NewAddInstr creates a new addition instruction based on the type t.
|
|
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
|
|
case types.TString, types.TArray, types.TSlice:
|
|
op = Concat
|
|
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
|
|
}
|
|
|
|
// NewSubInstr creates a new subtraction instruction based on the type
|
|
// t.
|
|
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
|
|
}
|
|
|
|
// NewMultInstr creates a new multiplication instruction based on the
|
|
// type t.
|
|
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
|
|
}
|
|
|
|
// NewDivInstr creates a new division instruction based on the type t.
|
|
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
|
|
}
|
|
|
|
// NewModInstr creates a new modulo instruction based on the type t.
|
|
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
|
|
}
|
|
|
|
// NewLshiftInstr creates a new Lshift instruction.
|
|
func NewLshiftInstr(l, r, o Value) Instr {
|
|
return Instr{
|
|
Op: Lshift,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewRshiftInstr creates a new Rshift instruction.
|
|
func NewRshiftInstr(l, r, o Value) Instr {
|
|
return Instr{
|
|
Op: Rshift,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewSrshiftInstr creates a new Srshift instruction.
|
|
func NewSrshiftInstr(l, r, o Value) Instr {
|
|
return Instr{
|
|
Op: Srshift,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewSliceInstr creates a new Slice instruction.
|
|
func NewSliceInstr(v, from, to, o Value) Instr {
|
|
f, err := from.ConstInt()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
t, err := from.ConstInt()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if f > t {
|
|
panic(fmt.Sprintf("slice: %v:%v", f, t))
|
|
}
|
|
return Instr{
|
|
Op: Slice,
|
|
In: []Value{v, from, to},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewIndexInstr creates a new Index instruction.
|
|
func NewIndexInstr(v, offset, index, o Value) Instr {
|
|
return Instr{
|
|
Op: Index,
|
|
In: []Value{v, offset, index},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewLtInstr creates a new less-than instruction based on the type t.
|
|
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
|
|
}
|
|
|
|
// NewLeInstr creates a new less-equal instruction based on the type
|
|
// t.
|
|
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
|
|
}
|
|
|
|
// NewGtInstr creates a new greater-than instruction based on the type
|
|
// t.
|
|
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
|
|
}
|
|
|
|
// NewGeInstr creates a new greater-equal instruction based on the
|
|
// type t.
|
|
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
|
|
}
|
|
|
|
// NewEqInstr creates a new Eq instruction.
|
|
func NewEqInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Eq,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewNeqInstr creates a new Neq instruction.
|
|
func NewNeqInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Neq,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewAndInstr creates a new And instruction.
|
|
func NewAndInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: And,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewOrInstr creates a new Or instruction.
|
|
func NewOrInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Or,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewNotInstr creates a new Not instruction.
|
|
func NewNotInstr(i, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Not,
|
|
In: []Value{i},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewBandInstr creates a new Band instruction.
|
|
func NewBandInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Band,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewBclrInstr creates a new Bclr instruction.
|
|
func NewBclrInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Bclr,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewBtsInstr creates a new Bts instruction.
|
|
func NewBtsInstr(l, r, o Value) Instr {
|
|
return Instr{
|
|
Op: Bts,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewBorInstr creates a new Bor instruction.
|
|
func NewBorInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Bor,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewBxorInstr creates a new Bxor instruction.
|
|
func NewBxorInstr(l, r, o Value) (Instr, error) {
|
|
return Instr{
|
|
Op: Bxor,
|
|
In: []Value{l, r},
|
|
Out: &o,
|
|
}, nil
|
|
}
|
|
|
|
// NewMovInstr creates a new Mov instruction.
|
|
func NewMovInstr(from, to Value) Instr {
|
|
return Instr{
|
|
Op: Mov,
|
|
In: []Value{from},
|
|
Out: &to,
|
|
}
|
|
}
|
|
|
|
// NewSmovInstr creates a new Mov instruction.
|
|
func NewSmovInstr(from, to Value) Instr {
|
|
return Instr{
|
|
Op: Smov,
|
|
In: []Value{from},
|
|
Out: &to,
|
|
}
|
|
}
|
|
|
|
// NewAmovInstr creates a new Amov instruction.
|
|
func NewAmovInstr(v, arr, from, to, o Value) Instr {
|
|
return Instr{
|
|
Op: Amov,
|
|
In: []Value{v, arr, from, to},
|
|
Out: &o,
|
|
}
|
|
}
|
|
|
|
// NewPhiInstr creates a new Phi instruction.
|
|
func NewPhiInstr(cond, t, f, v Value) Instr {
|
|
return Instr{
|
|
Op: Phi,
|
|
In: []Value{cond, t, f},
|
|
Out: &v,
|
|
}
|
|
}
|
|
|
|
// NewRetInstr creates a new Ret instruction.
|
|
func NewRetInstr(ret []Value) Instr {
|
|
return Instr{
|
|
Op: Ret,
|
|
In: ret,
|
|
}
|
|
}
|
|
|
|
// NewCircInstr creates a new Circ instruction.
|
|
func NewCircInstr(args []Value, circ *circuit.Circuit,
|
|
ret []Value) Instr {
|
|
return Instr{
|
|
Op: Circ,
|
|
In: args,
|
|
Circ: circ,
|
|
Ret: ret,
|
|
}
|
|
}
|
|
|
|
// NewBuiltinInstr creates a new Builtin instruction.
|
|
func NewBuiltinInstr(builtin circuits.Builtin, a, b, r Value) Instr {
|
|
return Instr{
|
|
Op: Builtin,
|
|
In: []Value{a, b},
|
|
Out: &r,
|
|
Builtin: builtin,
|
|
}
|
|
}
|
|
|
|
// NewGCInstr creates a new GC instruction.
|
|
func NewGCInstr(v Value) Instr {
|
|
return Instr{
|
|
Op: GC,
|
|
GC: &v,
|
|
}
|
|
}
|
|
|
|
func (i Instr) String() string {
|
|
return i.string(maxOperandLength, false)
|
|
}
|
|
|
|
// StringTyped returns a typed string representation of the instruction.
|
|
func (i Instr) StringTyped() string {
|
|
return i.string(0, true)
|
|
}
|
|
|
|
func (i Instr) string(maxLen int, typesOnly bool) string {
|
|
result := i.Op.String()
|
|
|
|
if len(i.In) == 0 && i.Out == nil && i.Label == nil && i.GC == nil {
|
|
return result
|
|
}
|
|
|
|
for len(result) < maxLen {
|
|
result += " "
|
|
}
|
|
for _, i := range i.In {
|
|
result += " "
|
|
if typesOnly {
|
|
result += i.Type.String()
|
|
} else {
|
|
result += i.String()
|
|
}
|
|
}
|
|
if i.Out != nil {
|
|
result += " "
|
|
if typesOnly {
|
|
result += i.Out.Type.String()
|
|
} else {
|
|
result += i.Out.String()
|
|
}
|
|
}
|
|
if i.Label != nil {
|
|
result += " "
|
|
result += i.Label.String()
|
|
}
|
|
if i.Circ != nil {
|
|
result += fmt.Sprintf(" {G=%d, W=%d}", i.Circ.NumGates, i.Circ.NumWires)
|
|
}
|
|
if i.GC != nil {
|
|
result += " "
|
|
result += i.GC.String()
|
|
}
|
|
for _, r := range i.Ret {
|
|
result += " "
|
|
result += r.String()
|
|
}
|
|
return result
|
|
}
|
|
|
|
// PP pretty-prints instruction to the specified io.Writer.
|
|
func (i Instr) PP(out io.Writer) {
|
|
fmt.Fprintf(out, "\t%s\n", i)
|
|
}
|