mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
342 lines
6.7 KiB
Go
342 lines
6.7 KiB
Go
//
|
|
// Copyright (c) 2020-2024 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/mpa"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
|
|
)
|
|
|
|
const (
|
|
anon = "%_"
|
|
)
|
|
|
|
// Generator implements code generator.
|
|
type Generator struct {
|
|
Params *utils.Params
|
|
versions map[string]Value
|
|
blockID BlockID
|
|
constants map[string]ConstantInst
|
|
nextValID ValueID
|
|
}
|
|
|
|
// ConstantInst defines a constant value instance.
|
|
type ConstantInst struct {
|
|
Count int
|
|
Const Value
|
|
}
|
|
|
|
// NewGenerator creates a new code generator.
|
|
func NewGenerator(params *utils.Params) *Generator {
|
|
return &Generator{
|
|
Params: params,
|
|
versions: make(map[string]Value),
|
|
constants: make(map[string]ConstantInst),
|
|
nextValID: 1,
|
|
}
|
|
}
|
|
|
|
// Constants returns the constants.
|
|
func (gen *Generator) Constants() map[string]ConstantInst {
|
|
return gen.constants
|
|
}
|
|
|
|
func (gen *Generator) nextValueID() ValueID {
|
|
ret := gen.nextValID
|
|
gen.nextValID++
|
|
return ret
|
|
}
|
|
|
|
// UndefVal creates a new undefined value.
|
|
func (gen *Generator) UndefVal() Value {
|
|
v, ok := gen.versions[anon]
|
|
if !ok {
|
|
v = Value{
|
|
Name: anon,
|
|
}
|
|
} else {
|
|
v.Version = v.Version + 1
|
|
}
|
|
v.Type = types.Undefined
|
|
v.ID = gen.nextValueID()
|
|
gen.versions[anon] = v
|
|
return v
|
|
}
|
|
|
|
// AnonVal creates a new anonymous value.
|
|
func (gen *Generator) AnonVal(t types.Info) Value {
|
|
|
|
if t.Type == types.TPtr && t.ElementType == nil {
|
|
panic("pointer with nil element type")
|
|
}
|
|
|
|
v, ok := gen.versions[anon]
|
|
if !ok {
|
|
v = Value{
|
|
Name: anon,
|
|
}
|
|
} else {
|
|
v.Version = v.Version + 1
|
|
}
|
|
v.Type = t
|
|
v.ID = gen.nextValueID()
|
|
gen.versions[anon] = v
|
|
|
|
return v
|
|
}
|
|
|
|
// NewVal creates a new value with the name, type, and scope.
|
|
func (gen *Generator) NewVal(name string, t types.Info, scope Scope) Value {
|
|
|
|
key := fmtKey(name, scope)
|
|
v, ok := gen.versions[key]
|
|
if !ok {
|
|
v = Value{
|
|
Name: name,
|
|
Scope: scope,
|
|
Type: t,
|
|
}
|
|
} else {
|
|
v.Version = v.Version + 1
|
|
v.Type = t
|
|
}
|
|
v.ID = gen.nextValueID()
|
|
gen.versions[key] = v
|
|
|
|
return v
|
|
}
|
|
|
|
// AddConstant adds a reference to the constant.
|
|
func (gen *Generator) AddConstant(c Value) {
|
|
// Add only values which have the ConstValue set.
|
|
if c.ConstValue == nil {
|
|
return
|
|
}
|
|
inst, ok := gen.constants[c.Name]
|
|
if !ok {
|
|
inst = ConstantInst{
|
|
Count: 1,
|
|
Const: c,
|
|
}
|
|
} else {
|
|
inst.Count++
|
|
}
|
|
gen.constants[c.Name] = inst
|
|
}
|
|
|
|
// RemoveConstant drops a reference from the constant.
|
|
func (gen *Generator) RemoveConstant(c Value) {
|
|
inst, ok := gen.constants[c.Name]
|
|
if !ok {
|
|
return
|
|
}
|
|
inst.Count--
|
|
if inst.Count == 0 {
|
|
delete(gen.constants, c.Name)
|
|
} else {
|
|
gen.constants[c.Name] = inst
|
|
}
|
|
}
|
|
|
|
func fmtKey(name string, scope Scope) string {
|
|
return fmt.Sprintf("%s@%d", name, scope)
|
|
}
|
|
|
|
// Block creates a new basic block.
|
|
func (gen *Generator) Block() *Block {
|
|
block := &Block{
|
|
ID: gen.blockID,
|
|
Bindings: new(Bindings),
|
|
}
|
|
gen.blockID++
|
|
|
|
return block
|
|
}
|
|
|
|
// NextBlock adds the next basic block to the argument block.
|
|
func (gen *Generator) NextBlock(b *Block) *Block {
|
|
n := gen.Block()
|
|
n.Bindings = b.Bindings.Clone()
|
|
b.SetNext(n)
|
|
return n
|
|
}
|
|
|
|
// BranchBlock creates a new branch basic block.
|
|
func (gen *Generator) BranchBlock(b *Block) *Block {
|
|
n := gen.Block()
|
|
n.Bindings = b.Bindings.Clone()
|
|
b.SetBranch(n)
|
|
return n
|
|
}
|
|
|
|
// Constant creates a constant value for the argument value. Type info
|
|
// is optional. If it is undefined, the type info will be resolved
|
|
// from the constant value.
|
|
func (gen *Generator) Constant(value interface{}, ti types.Info) Value {
|
|
|
|
var minBits types.Size
|
|
var bits types.Size
|
|
|
|
v := Value{
|
|
Const: true,
|
|
ConstValue: value,
|
|
Type: ti,
|
|
}
|
|
switch val := value.(type) {
|
|
case int64:
|
|
v.Name = fmt.Sprintf("$%d", val)
|
|
if v.Type.Undefined() {
|
|
v.Type = types.Info{
|
|
Type: types.TInt,
|
|
}
|
|
}
|
|
for minBits = 1; minBits < 64; minBits++ {
|
|
if (0xffffffffffffffff<<minBits)&uint64(val) == 0 {
|
|
break
|
|
}
|
|
}
|
|
if minBits > 32 {
|
|
bits = 64
|
|
} else {
|
|
bits = 32
|
|
}
|
|
if v.Type.Bits < bits {
|
|
v.Type.Bits = bits
|
|
}
|
|
v.Type.MinBits = minBits
|
|
v.ConstValue = mpa.NewInt(val, v.Type.Bits)
|
|
|
|
case *mpa.Int:
|
|
v.Name = fmt.Sprintf("$%s", val.String())
|
|
if v.Type.Undefined() {
|
|
v.Type = types.Info{
|
|
Type: types.TInt,
|
|
}
|
|
}
|
|
minBits = types.Size(val.BitLen())
|
|
if minBits > 64 {
|
|
bits = minBits
|
|
} else if minBits > 32 {
|
|
bits = 64
|
|
} else {
|
|
bits = 32
|
|
}
|
|
if v.Type.Bits < bits {
|
|
v.Type.Bits = bits
|
|
}
|
|
v.Type.MinBits = minBits
|
|
if v.Type.MinBits > v.Type.Bits {
|
|
panic(fmt.Sprintf("Constant(%v): Bits=%v, MinBits=%v",
|
|
value, v.Type.Bits, v.Type.MinBits))
|
|
}
|
|
val.SetTypeSize(bits)
|
|
v.ConstValue = val
|
|
|
|
case bool:
|
|
v.Name = fmt.Sprintf("$%v", val)
|
|
v.Type = types.Bool
|
|
|
|
case nil:
|
|
v.Name = "nil"
|
|
v.Type = types.Nil
|
|
|
|
case string:
|
|
v.Name = fmt.Sprintf("$%q", val)
|
|
bits = types.Size(len([]byte(val)) * types.ByteBits)
|
|
|
|
v.Type = types.Info{
|
|
Type: types.TString,
|
|
Bits: bits,
|
|
MinBits: bits,
|
|
}
|
|
|
|
case []interface{}:
|
|
var length string
|
|
var name string
|
|
var elementType types.Info
|
|
|
|
if len(val) > 0 {
|
|
if ti.Type.Array() {
|
|
elementType = *ti.ElementType
|
|
} else {
|
|
ev := gen.Constant(val[0], types.Undefined)
|
|
elementType = ev.Type
|
|
}
|
|
bits = elementType.Bits * types.Size(len(val))
|
|
name = elementType.String()
|
|
length = fmt.Sprintf("%d", len(val))
|
|
} else {
|
|
name = "interface{}"
|
|
}
|
|
if !ti.Undefined() && ti.Type == types.TStruct {
|
|
v.Name = "$" + ti.String()
|
|
ti.Bits = bits
|
|
ti.MinBits = bits
|
|
v.Type = ti
|
|
return v
|
|
}
|
|
|
|
v.Name = fmt.Sprintf("$[%s]%s%s", length, name, arrayString(val))
|
|
if ti.Undefined() {
|
|
v.Type = types.Info{
|
|
Type: types.TArray,
|
|
Bits: bits,
|
|
MinBits: bits,
|
|
ElementType: &elementType,
|
|
ArraySize: types.Size(len(val)),
|
|
}
|
|
} else {
|
|
v.Type = ti
|
|
v.Type.Bits = ti.ArraySize * ti.ElementType.Bits
|
|
v.Type.MinBits = v.Type.Bits
|
|
}
|
|
|
|
case types.Info:
|
|
v.Name = fmt.Sprintf("$%s", val)
|
|
v.Type = val
|
|
v.TypeRef = true
|
|
|
|
case Value:
|
|
if !val.Const {
|
|
panic(fmt.Sprintf("value %v (%T) is not constant", val, val))
|
|
}
|
|
if !ti.Undefined() {
|
|
return gen.Constant(val.ConstValue, ti)
|
|
}
|
|
v = val
|
|
|
|
default:
|
|
panic(fmt.Sprintf("Generator.Constant: %v (%T) not implemented yet",
|
|
val, val))
|
|
}
|
|
v.Type.SetConcrete(true)
|
|
v.ID = gen.nextValueID()
|
|
|
|
return v
|
|
}
|
|
|
|
func arrayString(arr []interface{}) string {
|
|
var parts []string
|
|
|
|
for _, part := range arr {
|
|
value, ok := part.(Value)
|
|
if ok && value.Const {
|
|
arr, ok := value.ConstValue.([]interface{})
|
|
if ok {
|
|
parts = append(parts, arrayString(arr))
|
|
continue
|
|
}
|
|
}
|
|
parts = append(parts, fmt.Sprintf("%v", part))
|
|
}
|
|
return "{" + strings.Join(parts, ",") + "}"
|
|
}
|