Giter VIP home page Giter VIP logo

llvm-legacy's Introduction

WIP

This project is a work in progress. The implementation is incomplete and subject to change. The documentation may be inaccurate.

llvm

Build Status Coverage Status GoDoc

The aim of this project is to provide a pure Go library for interacting with LLVM IR.

Installation

go get github.com/llir/llvm/...

Hacking

Anyone wishing to hack on the project may need to download the Gocc tool, which is used to generate the LLVM IR assembly lexer and parser from a BNF grammar.

go get github.com/goccmack/gocc
make -C $GOPATH/src/github.com/llir/llvm/asm/internal

Usage

Output LLVM IR assembly

Example usage in GoDoc.

// This example produces LLVM IR code equivalent to the following C code,
// which implements a pseudo-random number generator.
//
//    int abs(int x);
//
//    int seed = 0;
//
//    // ref: https://en.wikipedia.org/wiki/Linear_congruential_generator
//    //    a = 0x15A4E35
//    //    c = 1
//    int rand(void) {
//       seed = seed*0x15A4E35 + 1;
//       return abs(seed);
//    }

// Create convenience types and constants.
i32 := types.I32
zero := constant.NewInt(0, i32)
a := constant.NewInt(0x15A4E35, i32) // multiplier of the PRNG.
c := constant.NewInt(1, i32)         // increment of the PRNG.

// Create a new LLVM IR module.
m := ir.NewModule()

// Create an external function declaration and append it to the module.
//
//    int abs(int x);
abs := m.NewFunction("abs", i32, ir.NewParam("x", i32))

// Create a global variable definition and append it to the module.
//
//    int seed = 0;
seed := m.NewGlobalDef("seed", zero)

// Create a function definition and append it to the module.
//
//    int rand(void) { ... }
rand := m.NewFunction("rand", i32)

// Create an unnamed entry basic block and append it to the `rand` function.
entry := rand.NewBlock("")

// Create instructions and append them to the entry basic block.
tmp1 := entry.NewLoad(seed)
tmp2 := entry.NewMul(tmp1, a)
tmp3 := entry.NewAdd(tmp2, c)
entry.NewStore(tmp3, seed)
tmp4 := entry.NewCall(abs, tmp3)
entry.NewRet(tmp4)

// Print the LLVM IR assembly of the module.
fmt.Println(m)

Parse LLVM IR assembly

Example usage in GoDoc.

// Parse the LLVM IR assembly file `rand.ll`.
m, err := asm.ParseFile("testdata/rand.ll")
if err != nil {
    log.Fatal(err)
}
// Pretty-print the data types of the parsed LLVM IR module.
pretty.Println(m)

Process LLVM IR

Example usage in GoDoc.

The following example program parses eval.ll, evaluates the return value of the @main function and prints the result to standard output. The result should be 42.

package main

import (
    "fmt"
    "log"

    "github.com/llir/llvm/asm"
    "github.com/llir/llvm/ir"
    "github.com/llir/llvm/ir/constant"
    "github.com/llir/llvm/ir/types"
    "github.com/llir/llvm/ir/value"
)

func main() {
    // Parse the LLVM IR assembly file `eval.ll`.
    m, err := asm.ParseFile("testdata/eval.ll")
    if err != nil {
        log.Fatal(err)
    }
    // Evalute and print the return value of the `@main` function.
    for _, f := range m.Funcs {
        if f.Name == "main" {
            e := newEvaluator(f)
            fmt.Println("result:", e.eval())
            break
        }
    }
}

// evaluator is a function evaluator.
type evaluator struct {
    // Function.
    f *ir.Function
    // Function arguments.
    args []value.Value
}

// newEvaluator returns a new function evaluator, for evaluating the result of
// invoking f with args.
func newEvaluator(f *ir.Function, args ...value.Value) *evaluator {
    return &evaluator{f: f, args: args}
}

// eval evalutes f and returns the corresponding 32-bit integer.
func (e *evaluator) eval() uint32 {
    f := e.f
    if !types.Equal(f.Sig.Ret, types.I32) {
        panic(fmt.Errorf("support for function return type %v not yet implemented", f.Sig.Ret))
    }
    for _, block := range f.Blocks {
        switch term := block.Term.(type) {
        case *ir.TermRet:
            // NOTE: support for functions with more than one RET terminator not
            // yet implemented.
            if term.X != nil {
                // Evaluate the result of the first return value of a function is
                // evaluated.
                return e.evalValue(term.X)
            }
        }
    }
    panic(fmt.Errorf("unable to locate RET terminator in function %q", f.Name))
}

// evalInst evaluates inst and returns the corresponding 32-bit integer.
func (e *evaluator) evalInst(inst ir.Instruction) uint32 {
    switch inst := inst.(type) {
    // Binary instructions.
    case *ir.InstAdd:
        return e.evalValue(inst.X) + e.evalValue(inst.Y)
    case *ir.InstSub:
        return e.evalValue(inst.X) - e.evalValue(inst.Y)
    case *ir.InstMul:
        return e.evalValue(inst.X) * e.evalValue(inst.Y)
    case *ir.InstUDiv:
        return e.evalValue(inst.X) / e.evalValue(inst.Y)
    case *ir.InstSDiv:
        return e.evalValue(inst.X) / e.evalValue(inst.Y)
    case *ir.InstURem:
        return e.evalValue(inst.X) % e.evalValue(inst.Y)
    case *ir.InstSRem:
        return e.evalValue(inst.X) % e.evalValue(inst.Y)
    // Bitwise instructions.
    case *ir.InstShl:
        return e.evalValue(inst.X) << e.evalValue(inst.Y)
    case *ir.InstLShr:
        return e.evalValue(inst.X) >> e.evalValue(inst.Y)
    case *ir.InstAShr:
        x, y := e.evalValue(inst.X), e.evalValue(inst.Y)
        result := x >> y
        if x&0x80000000 != 0 {
            for i := uint32(31); i >= 0; i-- {
                mask := uint32(1 << i)
                if result&mask != 0 {
                    break
                }
                result |= mask
            }
        }
        return result
    case *ir.InstAnd:
        return e.evalValue(inst.X) & e.evalValue(inst.Y)
    case *ir.InstOr:
        return e.evalValue(inst.X) | e.evalValue(inst.Y)
    case *ir.InstXor:
        return e.evalValue(inst.X) ^ e.evalValue(inst.Y)
    // Other instructions.
    case *ir.InstCall:
        callee, ok := inst.Callee.(*ir.Function)
        if !ok {
            panic(fmt.Errorf("support for callee of type %T not yet implemented", inst.Callee))
        }
        ee := newEvaluator(callee, inst.Args...)
        return ee.eval()
    default:
        panic(fmt.Errorf("support for instruction type %T not yet implemented", inst))
    }
}

// evalValue evalutes v and returns the corresponding 32-bit integer.
func (e *evaluator) evalValue(v value.Value) uint32 {
    switch v := v.(type) {
    case ir.Instruction:
        return e.evalInst(v)
    case *constant.Int:
        return uint32(v.X.Int64())
    case *types.Param:
        if len(v.Name) == 0 {
            panic("support for unnamed parameters not yet implemented")
        }
        f := e.f
        for i, param := range f.Sig.Params {
            if v.Name == param.Name {
                return e.evalValue(e.args[i])
            }
        }
        panic(fmt.Errorf("unable to locate paramater %q of function %q", v.Name, f.Name))
    default:
        panic(fmt.Errorf("support for value type %T not yet implemented", v))
    }
}

Release history

Version 0.2 (2017-06-24)

Primary focus of version 0.2: read and write support of LLVM IR assembly.

Lexers and parsers for LLVM IR assembly are automatically generated from a BNF grammar using Gocc.

A high-level API for parsing LLVM IR assembly is provided by llvm/asm.

The llvm/ir package supports all instructions of LLVM IR, except the instructions used for concurrency and exception handling.

The llir/llvm packages are now go-getable, as the Gocc generated source code has been added to the source tree.

Version 0.1 (2015-04-19)

Initial release.

Preliminary work on the llvm/ir package which provides an in-memory representation of LLVM IR in pure Go.

Hand-written lexer and preliminary work on a recursive descent parser for LLVM IR assembly.

Roadmap

Version 0.3 (to be released)

Primary focus of version 0.3: grammar covering the entire LLVM IR language.

The grammar for LLVM IR is now complete and covers the entire LLVM IR language, based on the source code of the official LLVM project as of 2018-02-19 (rev llvm-mirror/llvm@db070bb).

Version 0.4 (to be released)

Primary focus of version 0.4: data flow analysis.

Introduce API for use-def chains.

License

The llir/llvm project is released into the public domain. Documentation and comments directly copied from the official LLVM project are licensed under a BSD-style license.

llvm-legacy's People

Contributors

7i avatar mcaldwelva avatar mewmew avatar quarnster avatar sangisos avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.