ceremonyclient/bedlam/compiler/ssa/bindings.go
Cassandra Heart dbd95bd9e9
v2.1.0 (#439)
* 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
2025-09-30 02:48:15 -05:00

243 lines
4.9 KiB
Go

//
// Copyright (c) 2020-2023 Markku Rossi
//
// All rights reserved.
//
package ssa
import (
"fmt"
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
)
var (
_ BindingValue = &Value{}
_ BindingValue = &Select{}
)
// Bindings defines value bindings.
type Bindings struct {
shared bool
Values []Binding
}
// Debug prints the bindings.
func (bindings *Bindings) Debug() {
fmt.Printf("Bindings: shared=%v, Values=[\n", bindings.shared)
for _, value := range bindings.Values {
fmt.Printf("\t%s,\n", value)
}
fmt.Println("]")
}
// Count returns the number of variable bindings the Bindings
// contains.
func (bindings *Bindings) Count() int {
return len(bindings.Values)
}
// Clone makes a copy of the bindings.
func (bindings Bindings) Clone() *Bindings {
result := &Bindings{
shared: true,
Values: bindings.Values,
}
bindings.shared = true
return result
}
// Define defines name v in the bindings. The argument val specifies
// an optional value for the name. If val is nil, the value of the
// name will be v.
func (bindings *Bindings) Define(v Value, val *Value) {
bindings.set(v, v.Type, val)
}
// Set sets a new binding for the name. It is an error if the name is
// not defined.
func (bindings *Bindings) Set(v Value, val *Value) error {
b, ok := bindings.Get(v.Name)
if !ok {
return fmt.Errorf("name %s not defined", v.Name)
}
bindings.set(v, b.Type, val)
return nil
}
func (bindings *Bindings) set(v Value, t types.Info, val *Value) {
if bindings.shared {
// Make our own copy of the values.
values := make([]Binding, len(bindings.Values))
copy(values, bindings.Values)
bindings.Values = values
bindings.shared = false
}
for idx, b := range bindings.Values {
if b.Name == v.Name && b.Scope == v.Scope {
b.Type = t
if val != nil {
b.Bound = val
} else {
b.Bound = &v
}
bindings.Values[idx] = b
return
}
}
b := Binding{
Name: v.Name,
Scope: v.Scope,
Type: t,
}
if val != nil {
b.Bound = val
} else {
b.Bound = &v
}
bindings.Values = append(bindings.Values, b)
}
// Get gets the value binding.
func (bindings Bindings) Get(name string) (ret Binding, ok bool) {
for _, b := range bindings.Values {
if b.Name == name {
if len(ret.Name) == 0 || b.Scope > ret.Scope {
ret = b
}
}
}
if len(ret.Name) == 0 {
return ret, false
}
return ret, true
}
func contains(values []Binding, name string) bool {
for _, v := range values {
if v.Name == name {
return true
}
}
return false
}
// Merge merges the argument false-branch bindings into this bindings
// instance that represents the true-branch values.
func (bindings Bindings) Merge(cond Value, falseBindings *Bindings) *Bindings {
var result []Binding
for _, b := range bindings.Values {
name := b.Name
if contains(result, name) {
continue
}
bTrue, okTrue := bindings.Get(name)
bFalse, okFalse := falseBindings.Get(name)
if !okTrue && !okFalse {
continue
} else if !okTrue {
result = append(result, bFalse)
} else if !okFalse {
result = append(result, bTrue)
} else {
if bTrue.Bound.Equal(bFalse.Bound) {
result = append(result, bTrue)
} else {
var phiType types.Info
if bTrue.Type.Bits > bFalse.Type.Bits {
phiType = bTrue.Type
} else {
phiType = bFalse.Type
}
result = append(result, Binding{
Name: name,
Scope: bTrue.Scope,
Type: phiType,
Bound: &Select{
Cond: cond,
Type: phiType,
True: bTrue.Bound,
False: bFalse.Bound,
},
})
}
}
}
return &Bindings{
Values: result,
}
}
// Binding implements a value binding.
type Binding struct {
Name string
Scope Scope
Type types.Info
Bound BindingValue
}
func (b Binding) String() string {
return fmt.Sprintf("%s@%d/%s=%s", b.Name, b.Scope, b.Type, b.Bound)
}
// Value returns the binding value.
func (b Binding) Value(block *Block, gen *Generator) Value {
return b.Bound.Value(block, gen)
}
// BindingValue represents value binding.
type BindingValue interface {
Equal(o BindingValue) bool
Value(block *Block, gen *Generator) Value
}
// Select implements Phi-bindings for value.
type Select struct {
Cond Value
Type types.Info
True BindingValue
False BindingValue
Resolved Value
}
func (phi *Select) String() string {
return fmt.Sprintf("\u03D5(%s|%s|%s)/%s",
phi.Cond, phi.True, phi.False, phi.Type)
}
// Equal tests if this select binding is equal to the argument bindind
// value.
func (phi *Select) Equal(other BindingValue) bool {
o, ok := other.(*Select)
if !ok {
return false
}
if !phi.Cond.Equal(&o.Cond) {
return false
}
return phi.True.Equal(o.True) && phi.False.Equal(o.False)
}
// Value returns the binding value.
func (phi *Select) Value(block *Block, gen *Generator) Value {
if phi.Resolved.Type.Type != types.TUndefined {
return phi.Resolved
}
t := phi.True.Value(block, gen)
f := phi.False.Value(block, gen)
v := gen.AnonVal(phi.Type)
block.AddInstr(NewPhiInstr(phi.Cond, t, f, v))
phi.Resolved = v
return v
}