Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package irutil_test

import (
"fmt"
"log"

"github.com/llir/irutil"
"github.com/llir/llvm/asm"
"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/value"
"github.com/pkg/errors"
)

func Example() {
// Parse LLVM IR module.
const module = `
define void @g() {
; potential side effects
ret void
}

define i32 @f(i32 %x, i32 %y) {
; <label>:0
%1 = add i32 %x, %y
%2 = xor i32 %1, 10
%3 = sub i32 %x, %y
call void @g()
%4 = mul i32 3, 5
ret i32 %3
}`
m, err := asm.ParseString("foo.ll", module)
if err != nil {
log.Fatalf("%+v", err)
}
// Perform dead code elimination (dce).
for _, f := range m.Funcs {
if err := dce(f); err != nil {
log.Fatalf("%+v", err)
}
}
// Print LLVM IR module after dce.
fmt.Println(m)

// Output:
//
// define void @g() {
// ; <label>:0
// ret void
// }
//
// define i32 @f(i32 %x, i32 %y) {
// ; <label>:0
// %1 = sub i32 %x, %y
// call void @g()
// ret i32 %1
// }
}

// dce performs dead code elimination on f, pruning value instructions with
// unused results in f. Call instructions are never pruned as they may have side
// effects.
func dce(f *ir.Func) error {
// Prune until we reach fixed-point. If we prune an unused value instruction,
// this may result in another local variable becoming unused.
for {
// Get names of local variables used in f.
usedIdents, err := getUsedIdents(f)
if err != nil {
return errors.WithStack(err)
}
// Prune value instructions with unused results in f.
if !pruneUnusedInsts(f, usedIdents) {
// Fix-point reached, no more pruning possible.
break
}
}
return nil
}

// pruneUnusedInsts prunes value instructions with unused results in f. Call
// instructions are never pruned as they may have side effects. The boolean
// return value indicates whether an instruction was pruned.
func pruneUnusedInsts(f *ir.Func, usedIdents map[string]bool) bool {
pruned := false
// Prune value instructions with unused results in f.
for _, block := range f.Blocks {
insts := block.Insts[:0] // filter instructions in-place.
for _, inst := range block.Insts {
if isUnused(inst, usedIdents) {
// Prune unused value instruction, skip append to insts.
pruned = true
continue
}
insts = append(insts, inst)
}
block.Insts = insts
}
if pruned {
// Reset IDs of unnamed local variables (as one or more instructions have
// been pruned).
irutil.ResetNames(f)
}
return pruned
}

// ValueInstruction is an instruction producing a local variable result.
//
// Note: call instructions are value instructions, but only produce a result if
// the return type of their callee is non-void.
type ValueInstruction interface {
ir.Instruction
value.Named
}

// isUnused reports whether the given instruction is a value instruction with
// unused results. Call instructions are never considered unused, as they may
// have side effects.
func isUnused(inst ir.Instruction, usedIdents map[string]bool) bool {
valueInst, ok := inst.(ValueInstruction)
if !ok {
// Non-value instructions are never considered unused.
return false
}
if _, ok := inst.(*ir.InstCall); ok {
// Call instructions are never considered unused as they may have side
// effects.
return false
}
return !usedIdents[valueInst.Name()]
}

// getUsedIdents returns the names of local variables used in f.
func getUsedIdents(f *ir.Func) (map[string]bool, error) {
// Assign IDs to unnamed local variables (as we need to record the names of
// local variables used in f).
if err := f.AssignIDs(); err != nil {
return nil, errors.WithStack(err)
}
// Pre-allocate backing array on stack for uses slice.
var backing [100]irutil.Use
// Record names of local variables used used in f.
uses := irutil.FuncUses(backing[:0], f) // the backing array is optional, pass nil if not needed.
usedIdents := make(map[string]bool)
for _, use := range uses {
valueInst, ok := (*use.Val).(ValueInstruction)
if !ok {
// Only record the names of local variables produced by value
// instructions.
continue
}
usedIdents[valueInst.Name()] = true
}
return usedIdents, nil
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/llir/irutil

go 1.12

require github.com/llir/llvm v0.3.0-pre7.0.20191220191840-fc6d0e8d9bc6
require (
github.com/llir/llvm v0.3.0
github.com/pkg/errors v0.8.1
)
30 changes: 15 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b h1:02XNVBBC2x90C1IKnZ0iyrIxL1pdIRsusn0lqSEIOD0=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/llir/ll v0.0.0-20191205054844-50f4b743547b h1:Hc7BLGoz4hbN+8mb+JhZeYS+5mE8l+L+KWp7cJVeNrY=
github.com/llir/ll v0.0.0-20191205054844-50f4b743547b/go.mod h1:8W5HJz80PitAyPZUpOcljQxTu6LD5YKW1URTo+OjVoc=
github.com/llir/llvm v0.3.0-pre7.0.20191220191840-fc6d0e8d9bc6 h1:bwZWin1Q/mernGFKoNOKRysPU10+rgylUxLeJR5AOJg=
github.com/llir/llvm v0.3.0-pre7.0.20191220191840-fc6d0e8d9bc6/go.mod h1:w6wEy+jHlAsmT+yQGYOvL1TO+JEDlzt+NnsYegCunuo=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 h1:EyTNMdePWaoWsRSGQnXiSoQu0r6RS1eA557AwJhlzHU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
github.com/mewmew/float v0.0.0-20191218075745-e26b3d092977 h1:6+YqyNydbRNcd0azoFfSM36F1O5nbc0M3OzKqsT8YCA=
github.com/mewmew/float v0.0.0-20191218075745-e26b3d092977/go.mod h1:O+xb+8ycBNHzJicFVs7GRWtruD4tVZI0huVnw5TM01E=
github.com/llir/ll v0.0.0-20191229032745-05be70ade156 h1:tQ3EaDUy4rHvIyvuI2Yf1X2xPMVi4orBwX3H1NSWp74=
github.com/llir/ll v0.0.0-20191229032745-05be70ade156/go.mod h1:8W5HJz80PitAyPZUpOcljQxTu6LD5YKW1URTo+OjVoc=
github.com/llir/llvm v0.3.0 h1:A4lHTPerMXrHYWJZF80XsnerraV8PKEqhBG+4wedSHg=
github.com/llir/llvm v0.3.0/go.mod h1:yjHRZjO9xc1uLUS69qO2qYjS95XFdfd2odSdSnufS10=
github.com/mewmew/float v0.0.0-20191226120903-16bbe2fdd85e h1:KCD7E/8LKwDsC5ymlEWJ3xCiSPaCywrS/psToBMOBH4=
github.com/mewmew/float v0.0.0-20191226120903-16bbe2fdd85e/go.mod h1:O+xb+8ycBNHzJicFVs7GRWtruD4tVZI0huVnw5TM01E=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191028143239-8715e36070db h1:xzcb0oYS6YlLAFxFJtuJ5GS6TVcVi3zQsh5Pf6LtASA=
golang.org/x/tools v0.0.0-20191028143239-8715e36070db/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9OzqyNfMUhUNjz3sL0NMk=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Loading