Skip to content

Commit

Permalink
Better SSA variable liveness analysis.
Browse files Browse the repository at this point in the history
  • Loading branch information
markkurossi committed Apr 13, 2020
1 parent d85706b commit 4ae25a5
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 50 deletions.
16 changes: 6 additions & 10 deletions apps/garbled/examples/bug.mpcl
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@
package main

import (
"crypto/rsa"
"math"
)

func main(b, e uint2) (uint, uint) {
var msg uint32 = 0x6d7472
var pubE uint32 = 0x10001
var pubN uint32 = 0xd60b2b09
var priv uint32 = 0x321af139

cipher := rsa.Encrypt(msg, pubE, pubN)
plain := rsa.Decrypt(cipher, priv, pubN)
type Arg struct {
a uint32
b uint32
}

return cipher, plain
func main(a, b Arg) uint {
return math.Exp(a.a, a.b, b.a)
}
7 changes: 0 additions & 7 deletions compiler/ssa/peephole.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,6 @@ var rules = []*Rule{
=>
btc V1 C1 V4`,
},
&Rule{
Name: "Slice-cast => slice",
Source: `slice V1 V2 V3 V4
mov V4 V5
=>
slice V1 V2 V3 V5`,
},
}

var reSpace = regexp.MustCompilePOSIX(`[[:space:]]+`)
Expand Down
91 changes: 61 additions & 30 deletions compiler/ssa/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Program struct {
OutputWires []*circuits.Wire
Constants map[string]ConstantInst
Steps []Step
wires map[string][]*circuits.Wire
wires map[string]*wireAlloc
freeWires map[int][][]*circuits.Wire
nextWireID uint32
zeroWire *circuits.Wire
Expand All @@ -36,6 +36,11 @@ type Program struct {
garbleDuration time.Duration
}

type wireAlloc struct {
Base uint32
Wires []*circuits.Wire
}

func NewProgram(params *utils.Params, in, out circuit.IO,
consts map[string]ConstantInst, steps []Step) (*Program, error) {

Expand All @@ -45,7 +50,7 @@ func NewProgram(params *utils.Params, in, out circuit.IO,
Outputs: out,
Constants: consts,
Steps: steps,
wires: make(map[string][]*circuits.Wire),
wires: make(map[string]*wireAlloc),
freeWires: make(map[int][][]*circuits.Wire),
}

Expand Down Expand Up @@ -74,65 +79,73 @@ func (prog *Program) Wires(v string, bits int) ([]*circuits.Wire, error) {
if bits <= 0 {
return nil, fmt.Errorf("size not set for variable %v", v)
}
wires, ok := prog.wires[v]
alloc, ok := prog.wires[v]
if !ok {
wires = prog.allocWires(bits, false)
prog.wires[v] = wires
alloc = prog.allocWires(bits, false)
prog.wires[v] = alloc
}
return wires, nil
return alloc.Wires, nil
}

func (prog *Program) AssignedWires(v string, bits int) (
[]*circuits.Wire, error) {
if bits <= 0 {
return nil, fmt.Errorf("size not set for variable %v", v)
}
wires, ok := prog.wires[v]
alloc, ok := prog.wires[v]
if !ok {
wires = prog.allocWires(bits, true)
prog.wires[v] = wires
alloc = prog.allocWires(bits, true)
prog.wires[v] = alloc
}
return wires, nil
return alloc.Wires, nil
}

func (prog *Program) allocWires(bits int, assign bool) (
result []*circuits.Wire) {
func (prog *Program) allocWires(bits int, assign bool) *wireAlloc {

result := &wireAlloc{
Base: circuits.UnassignedID,
}

fl, ok := prog.freeWires[bits]
if ok && len(fl) > 0 {
result = fl[0]
result.Wires = fl[0]
result.Base = result.Wires[0].ID
prog.freeWires[bits] = fl[1:]
return
} else {
result.Wires = circuits.MakeWires(bits)
}

result = circuits.MakeWires(bits)

if assign {
if assign && result.Base == circuits.UnassignedID {
// Assign wire IDs.
result.Base = prog.nextWireID
for i := 0; i < bits; i++ {
result[i].ID = prog.nextWireID + uint32(i)
result.Wires[i].ID = prog.nextWireID + uint32(i)
}
prog.nextWireID += uint32(bits)
}

return
return result
}

func (prog *Program) recycleWires(wires []*circuits.Wire) {
// Clear wires but keep their IDs.
for _, w := range wires {
w.Output = false
w.NumOutputs = 0
w.Input = nil
w.Outputs = nil
func (prog *Program) recycleWires(alloc *wireAlloc) {
if alloc.Base == circuits.UnassignedID {
alloc.Base = alloc.Wires[0].ID
}
// Clear wires and reassign their IDs.
bits := len(alloc.Wires)
for i := 0; i < bits; i++ {
alloc.Wires[i].ID = alloc.Base + uint32(i)
alloc.Wires[i].Output = false
alloc.Wires[i].NumOutputs = 0
alloc.Wires[i].Input = nil
alloc.Wires[i].Outputs = nil
}

bits := len(wires)
fl := prog.freeWires[bits]
fl = append(fl, wires)
fl = append(fl, alloc.Wires)
prog.freeWires[bits] = fl
if false {
fmt.Printf("FL: %d: ", len(wires))
fmt.Printf("FL: %d: ", bits)
for k, v := range prog.freeWires {
fmt.Printf(" %d:%d", k, len(v))
}
Expand All @@ -145,7 +158,10 @@ func (prog *Program) SetWires(v string, w []*circuits.Wire) error {
if ok {
return fmt.Errorf("wires already set for %v", v)
}
prog.wires[v] = w
prog.wires[v] = &wireAlloc{
Base: w[0].ID,
Wires: w,
}
return nil
}

Expand All @@ -160,6 +176,18 @@ func (prog *Program) liveness() {
}
live[in.String()] = true
}
switch step.Instr.Op {
case Slice, Mov:
// Now `out' is an alias for `in[0]' and we must make `in]
// live in all steps where `out' is live.
for j := i + 1; j < len(prog.Steps); j++ {
s := &prog.Steps[j]
if s.Live.Contains(step.Instr.Out.String()) {
s.Live.Add(step.Instr.In[0].String())
}
}
}

if step.Instr.Out != nil {
delete(live, step.Instr.Out.String())
}
Expand Down Expand Up @@ -251,5 +279,8 @@ func (prog *Program) PP(out io.Writer) {
fmt.Fprintf(out, "# %s:\n", step.Label)
}
step.Instr.PP(out)
for live, _ := range step.Live {
fmt.Fprintf(out, "#\t\t- %s\n", live)
}
}
}
5 changes: 5 additions & 0 deletions compiler/ssa/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ func NewSet() Set {
return make(map[string]bool)
}

func (set Set) Contains(val string) bool {
_, ok := set[val]
return ok
}

func (set Set) Add(val string) {
set[val] = true
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/ssa/streamer.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,11 @@ func (prog *Program) StreamCircuit(conn *p2p.Conn, params *utils.Params,
conn.Flush()

case GC:
if false {
wires, ok := prog.wires[instr.GC]
if true {
alloc, ok := prog.wires[instr.GC]
if ok {
delete(prog.wires, instr.GC)
prog.recycleWires(wires)
prog.recycleWires(alloc)
} else {
fmt.Printf("GC: %s not known\n", instr.GC)
}
Expand Down

0 comments on commit 4ae25a5

Please sign in to comment.