github.com/llir/llvm@v0.3.6/README.md (about) 1 # llvm 2 3 [![Build Status](https://github.com/llir/llvm/workflows/Go/badge.svg?branch=master)](https://github.com/llir/llvm/actions/workflows/go.yml) 4 [![Coverage Status](https://coveralls.io/repos/github/llir/llvm/badge.svg?branch=master)](https://coveralls.io/github/llir/llvm?branch=master) 5 [![Go Report Card](https://goreportcard.com/badge/github.com/llir/llvm)](https://goreportcard.com/report/github.com/llir/llvm) 6 [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/llir/llvm) 7 8 Library for interacting with [LLVM IR](http://llvm.org/docs/LangRef.html) in pure Go. 9 10 ## Introduction 11 12 * [Introductory blog post "LLVM IR and Go"](https://blog.gopheracademy.com/advent-2018/llvm-ir-and-go/) 13 * [Our Document](https://llir.github.io/document/) 14 15 ## Installation 16 17 ```bash 18 go get -u github.com/llir/llvm/... 19 ``` 20 21 ## Versions 22 23 Map between `llir/llvm` tagged releases and LLVM release versions. 24 25 * [llir/llvm v0.3.6](https://github.com/llir/llvm/tree/v0.3.6): LLVM 14.0 26 * [llir/llvm v0.3.5](https://github.com/llir/llvm/tree/v0.3.5): LLVM 13.0 27 * [llir/llvm v0.3.4](https://github.com/llir/llvm/tree/v0.3.4): LLVM 12.0 28 * [llir/llvm v0.3.3](https://github.com/llir/llvm/tree/v0.3.3): LLVM 11.0 29 * [llir/llvm v0.3.2](https://github.com/llir/llvm/tree/v0.3.2): LLVM 10.0 30 * [llir/llvm v0.3.0](https://github.com/llir/llvm/tree/v0.3.0): LLVM 9.0 31 32 ## Users 33 34 * [decomp](https://github.com/decomp/decomp): LLVM IR to Go decompiler by [@decomp](https://github.com/decomp). 35 * [geode](https://github.com/geode-lang/geode): Geode to LLVM IR compiler by [@nickwanninger](https://github.com/nickwanninger). 36 * [leaven](https://github.com/andybalholm/leaven): LLVM IR to Go decompiler by [@andybalholm](https://github.com/andybalholm). 37 * [slate](https://github.com/nektro/slate): Slate to LLVM IR compiler by [@nektro](https://github.com/nektro). 38 * [tre](https://github.com/zegl/tre): Go to LLVM IR compiler by [@zegl](https://github.com/zegl). 39 * [uc](https://github.com/mewmew/uc): µC to LLVM IR compiler by [@sangisos](https://github.com/sangisos) and [@mewmew](https://github.com/mewmew). 40 * [B++](https://github.com/Nv7-Github/Bpp): B++ to LLVM IR compiler by [@Nv7-Github](https://github.com/Nv7-Github). 41 42 ## Usage 43 44 ### Input example - Parse LLVM IR assembly 45 46 [Example usage in GoDoc](https://pkg.go.dev/github.com/llir/llvm/asm#example-package). 47 48 ```go 49 // This example parses an LLVM IR assembly file and pretty-prints the data types 50 // of the parsed module to standard output. 51 package main 52 53 import ( 54 "log" 55 56 "github.com/kr/pretty" 57 "github.com/llir/llvm/asm" 58 ) 59 60 func main() { 61 // Parse the LLVM IR assembly file `foo.ll`. 62 m, err := asm.ParseFile("foo.ll") 63 if err != nil { 64 log.Fatalf("%+v", err) 65 } 66 // Pretty-print the data types of the parsed LLVM IR module. 67 pretty.Println(m) 68 } 69 ``` 70 71 ### Output example - Produce LLVM IR assembly 72 73 [Example usage in GoDoc](https://pkg.go.dev/github.com/llir/llvm/ir#example-package). 74 75 ```go 76 // This example produces LLVM IR code equivalent to the following C code, which 77 // implements a pseudo-random number generator. 78 // 79 // int abs(int x); 80 // 81 // int seed = 0; 82 // 83 // // ref: https://en.wikipedia.org/wiki/Linear_congruential_generator 84 // // a = 0x15A4E35 85 // // c = 1 86 // int rand(void) { 87 // seed = seed*0x15A4E35 + 1; 88 // return abs(seed); 89 // } 90 package main 91 92 import ( 93 "fmt" 94 95 "github.com/llir/llvm/ir" 96 "github.com/llir/llvm/ir/constant" 97 "github.com/llir/llvm/ir/types" 98 ) 99 100 func main() { 101 // Create convenience types and constants. 102 i32 := types.I32 103 zero := constant.NewInt(i32, 0) 104 a := constant.NewInt(i32, 0x15A4E35) // multiplier of the PRNG. 105 c := constant.NewInt(i32, 1) // increment of the PRNG. 106 107 // Create a new LLVM IR module. 108 m := ir.NewModule() 109 110 // Create an external function declaration and append it to the module. 111 // 112 // int abs(int x); 113 abs := m.NewFunc("abs", i32, ir.NewParam("x", i32)) 114 115 // Create a global variable definition and append it to the module. 116 // 117 // int seed = 0; 118 seed := m.NewGlobalDef("seed", zero) 119 120 // Create a function definition and append it to the module. 121 // 122 // int rand(void) { ... } 123 rand := m.NewFunc("rand", i32) 124 125 // Create an unnamed entry basic block and append it to the `rand` function. 126 entry := rand.NewBlock("") 127 128 // Create instructions and append them to the entry basic block. 129 tmp1 := entry.NewLoad(i32, seed) 130 tmp2 := entry.NewMul(tmp1, a) 131 tmp3 := entry.NewAdd(tmp2, c) 132 entry.NewStore(tmp3, seed) 133 tmp4 := entry.NewCall(abs, tmp3) 134 entry.NewRet(tmp4) 135 136 // Print the LLVM IR assembly of the module. 137 fmt.Println(m) 138 } 139 ``` 140 141 ### Analysis example - Process LLVM IR 142 143 [Example usage in GoDoc](https://pkg.go.dev/github.com/llir/llvm/ir#example-package--Callgraph). 144 145 ```go 146 // This example program analyses an LLVM IR module to produce a callgraph in 147 // Graphviz DOT format. 148 package main 149 150 import ( 151 "fmt" 152 "strings" 153 154 "github.com/llir/llvm/asm" 155 "github.com/llir/llvm/ir" 156 ) 157 158 func main() { 159 // Parse LLVM IR assembly file. 160 m, err := asm.ParseFile("foo.ll") 161 if err != nil { 162 panic(err) 163 } 164 // Produce callgraph of module. 165 callgraph := genCallgraph(m) 166 // Output callgraph in Graphviz DOT format. 167 fmt.Println(callgraph) 168 } 169 170 // genCallgraph returns the callgraph in Graphviz DOT format of the given LLVM 171 // IR module. 172 func genCallgraph(m *ir.Module) string { 173 buf := &strings.Builder{} 174 buf.WriteString("digraph {\n") 175 // For each function of the module. 176 for _, f := range m.Funcs { 177 // Add caller node. 178 caller := f.Ident() 179 fmt.Fprintf(buf, "\t%q\n", caller) 180 // For each basic block of the function. 181 for _, block := range f.Blocks { 182 // For each non-branching instruction of the basic block. 183 for _, inst := range block.Insts { 184 // Type switch on instruction to find call instructions. 185 switch inst := inst.(type) { 186 case *ir.InstCall: 187 callee := inst.Callee.Ident() 188 // Add edges from caller to callee. 189 fmt.Fprintf(buf, "\t%q -> %q\n", caller, callee) 190 } 191 } 192 // Terminator of basic block. 193 switch term := block.Term.(type) { 194 case *ir.TermRet: 195 // do something. 196 _ = term 197 } 198 } 199 } 200 buf.WriteString("}") 201 return buf.String() 202 } 203 ``` 204 205 ## License 206 207 The `llir/llvm` project is dual-licensed to the [public domain](UNLICENSE) and under a [zero-clause BSD license](LICENSE). You may choose either license to govern your use of `llir/llvm`.