Library for interacting with LLVM IR in pure Go.

llvm

Build Status Coverage Status Go Report Card go.dev reference

Library for interacting with LLVM IR in pure Go.

Introduction

Installation

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

Versions

Map between llir/llvm tagged releases and LLVM release versions.

Users

Usage

Input example - Parse LLVM IR assembly

Example usage in GoDoc.

// This example parses an LLVM IR assembly file and pretty-prints the data types
// of the parsed module to standard output.
package main

import (
	"log"

	"github.com/kr/pretty"
	"github.com/llir/llvm/asm"
)

func main() {
	// Parse the LLVM IR assembly file `foo.ll`.
	m, err := asm.ParseFile("foo.ll")
	if err != nil {
		log.Fatalf("%+v", err)
	}
	// Pretty-print the data types of the parsed LLVM IR module.
	pretty.Println(m)
}

Output example - Produce 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);
//    }
package main

import (
	"fmt"

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

func main() {
	// Create convenience types and constants.
	i32 := types.I32
	zero := constant.NewInt(i32, 0)
	a := constant.NewInt(i32, 0x15A4E35) // multiplier of the PRNG.
	c := constant.NewInt(i32, 1)         // 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.NewFunc("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.NewFunc("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(i32, 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)
}

Analysis example - Process LLVM IR

Example usage in GoDoc.

// This example program analyses an LLVM IR module to produce a callgraph in
// Graphviz DOT format.
package main

import (
	"fmt"
	"strings"

	"github.com/llir/llvm/asm"
	"github.com/llir/llvm/ir"
)

func main() {
	// Parse LLVM IR assembly file.
	m, err := asm.ParseFile("foo.ll")
	if err != nil {
		panic(err)
	}
	// Produce callgraph of module.
	callgraph := genCallgraph(m)
	// Output callgraph in Graphviz DOT format.
	fmt.Println(callgraph)
}

// genCallgraph returns the callgraph in Graphviz DOT format of the given LLVM
// IR module.
func genCallgraph(m *ir.Module) string {
	buf := &strings.Builder{}
	buf.WriteString("digraph {\n")
	// For each function of the module.
	for _, f := range m.Funcs {
		// Add caller node.
		caller := f.Ident()
		fmt.Fprintf(buf, "\t%q\n", caller)
		// For each basic block of the function.
		for _, block := range f.Blocks {
			// For each non-branching instruction of the basic block.
			for _, inst := range block.Insts {
				// Type switch on instruction to find call instructions.
				switch inst := inst.(type) {
				case *ir.InstCall:
					callee := inst.Callee.Ident()
					// Add edges from caller to callee.
					fmt.Fprintf(buf, "\t%q -> %q\n", caller, callee)
				}
			}
			// Terminator of basic block.
			switch term := block.Term.(type) {
			case *ir.TermRet:
				// do something.
				_ = term
			}
		}
	}
	buf.WriteString("}")
	return buf.String()
}

License

The llir/llvm project is dual-licensed to the public domain and under a zero-clause BSD license. You may choose either license to govern your use of llir/llvm.

Owner
Unofficial libraries for interacting with LLVM IR.
null
Comments
  • NewFloat does not generate the expected output

    NewFloat does not generate the expected output

    Hello all,

    I would first like to say thanks for an amazing library and I appreciate the hard work and dedication to support LLVM through Go.

    However, using the library in a project of my own to generate LLVM instructions for different variables, I ran into a problem where using NewFloat did not produce the expected results. I will demonstrate using a C program as a comparison.

    Using clang -S -emit-llvm main.c on the following program:

    Input C Program:

    int main() {
      float j = 1.1;
    
      return 0;
    }
    

    Produces the following store instruction for the float variable:

    store float 0x3FF19999A0000000, float* %2, align 4
    

    This is a 64 bit float with the last 28 bits dropped and converted to hex. (According to: http://lists.llvm.org/pipermail/llvm-dev/2011-April/039811.html)

    However, attempting to generate the same instruction using this library:

    mainBlock.NewStore(constant.NewFloat(value, types.Float), mainBlock.NewAlloca(types.Float))
    

    where value is the float literal 1.1.

    I obtained the following instruction:

    store float 1.1, float* %1
    

    Putting this into LLVM to generate assembly using:

    llc -march=x86 -o main.expr.assembly main.expr.ll
    

    Generates an error of:

    llc: main.expr.ll:6:14: error: floating point constant invalid for type
            store float 1.1, float* %1
    

    I can provide more information if needed, but a few questions:

    1. Is this expected behavior?
    2. Should this be expected behavior?
    3. If yes, why does this produce code that doesn't work?

    I can get it to work using types.Double, and if that is the solution then so be it for now, but I'd like to investigate if this is actually the expected output.

    Again, Thanks for the work and dedication

  • Formal Grammar of LLVM IR

    Formal Grammar of LLVM IR

    I've been unable to locate an official formal grammar for LLVM IR. If anyone has information about work in this direction, please point it out to me.

    To address this issue a formal grammar of LLVM IR will be created, prior to the implementation of the LLVM IR Assembly Language parser. This work was taking place at mewlang/llvm/asm/grammar (old link superseded by https://github.com/llir/llvm/blob/master/asm/internal/ll.bnf).

    Edit: For anyone who happen to stumble upon this issue. The latest version of the grammar is located in the llir/grammar repository, more specifically see ll.tm for an EBNF grammar for LLVM IR assembly.

  • Rewrite Git history to prune large 'old files'?

    Rewrite Git history to prune large 'old files'?

    Update summary, 23/11/2018: This repository currently requires ~10MiB of download, which isn't ideal considering the source is only a few hundreds of kilobytes. @mewmew and I propose to shrink it to ~800kiB, to give a faster "Go install" experience for anyone using the repository.

    The reason for the blowup is that there were some large test cases (including sqlite) which measure in the 10's of MiBs, and various other bits relating to parsing were also quite large. Those have now moved into other repositories in the llir organization, so we don't need to download those anymore if you just want to import llir.


    Original issue text.

    I just saw @mewmew's comment in ec48d546f5c3761fa2e8d1c0bec1a49865083072 but thought it would be easier to have a separate issue for discussion - the commit itself is very long so if I commented on the commit the discussion would be way down at the bottom!

    First, can I clarify the question - are you asking how to remove lots of old large assets from the history of the repository?

    If that is the question, the answer is, yes you can do it, but anyone who cloned the repository needs to know about it otherwise they might get in a mess, since it requires rewriting history. At least, that's the best I know. See github's guidance on the issue.

  • Requirements

    Requirements

    This issue summarizes the requirements of the LLVM packages, as specified by its intended use cases.

    The requirements of llgo as stated by @axw (in this issue) are as follows:

    As for llgo's requirements:

    • [x] in terms of using the LLVM API for generating code, it's mostly write-only via the builder API. Bitcode and IR reading is not important (at the moment?), but writing is; one or the other is required, but preferably both.
    • [x] llgo uses the DIBuilder API for generating debug metadata (DWARF, et al.). This could be built outside of the core (it's just a matter of creating metadata nodes in a particular format), just be aware that it's pretty finicky and easy to break.
    • [x] llgo needs to be able to look up target data (arch word size, alignment, etc.) from triples

    For the decompilation pipeline the llvm packages should be able to:

    • [x] represent the LLVM IR using Control Flow Graphs, where each node represents a BasicBlock.
    • [x] insert new nodes and rearrange existing ones.
  • `module.NewTypeDef` has unexpected side effects

    `module.NewTypeDef` has unexpected side effects

    The following code has unexpected side effects on the convenience types:

    m.NewTypeDef("hello", types.I64)
    

    Because NewTypeDef sets the type's name. Which is okay, but next time if I use types.I64 it will have name hello since, the convenience type is a pointer. To be honest, I don't really have an idea how to solve this. But it took me about 3 hours of debugging till I figured out why my i64 types called hello in LLVM IR.

  • Upcoming release of the llir/llvm project

    Upcoming release of the llir/llvm project

    This notice is intended to give a heads up for those using the llir/llvm library. The next release will include complete support for all intrinsics of the LLVM IR language. The work is currently in a flux, and to experiment with different API designs and simplify the parser logic and reduce the code duplication in the project, a new repo has been created during the experimental phase.

    https://github.com/mewmew/l

    At the current stage, the grammar is capable of parsing the entirety of the LLVM IR language, including specialized metadata nodes (#26).

    While working on this we will also try to take into consideration previous issues that have been identified with the parser (such as the handling of quoted strings #24).

    The llir/llvm/ir package will be extended to support the entire LLVM IR language; thus resolving #23 as linkage information will be present in the in-memory intermediate representation form.

    With the upcoming release, read support for all of the LLVM IR language concepts will have been implemented; thus resolving #15.

    Similarly; we will now have a grammar covering the entire LLVM IR language; thus resolving #2.

    With the addition of support for specialized metadata nodes, the second requirement of llgo will also be fully supported (#3); llgo uses the DIBuilder API for generating debug metadata (DWARF, et al.). This could be built outside of the core (it's just a matter of creating metadata nodes in a particular format), just be aware that it's pretty finicky and easy to break..

    For IR construction, a similar approach will be used as has been done before. Personally, we feel this approach has worked out well and has been quite pleasant to use. If anyone has input on their own experience using the API of the llir/llvm/ir package to construct LLVM IR, please let us know as that could help shape the upcoming release. As for llgo, the first requirement in terms of using the LLVM API for generating code, it's mostly write-only via the builder API. Bitcode and IR reading is not important (at the moment?), but writing is; one or the other is required, but preferably both. is satisfied by this API, and has been for a while. Although, now the llir/llvm/ir package will contain the support for the entire LLVM IR language, and now just a subset; thus the requirement should be satisfied in full.

    Module top-level information such as target triple and data layout has been and will continue to be recorded and maintained by the IR API, thus supporting the third requirement of llgo; llgo needs to be able to look up target data (arch word size, alignment, etc.) from triples.

    Generating C-shared library bindings compatible with the official C library of the LLVM project is an ambitious goal that is left for a future release (#12). Anyone specifically interested in this topic, feel free to get in touch with us or continue the discussion in the dedicated issue.

    Similarly, interaction with the Go runtime is targeted for a future release, and those with knowledge in this domain are happily invited to the discussion on what is needed and how to bring this about (#18).

    As for use-tracking and data analysis support (#19), more thought will be required to get a clean API. This is therefore targeted for a future release.

    So, to summarize, the upcoming release of the llir/llvm project will include read and write support for the entire LLVM IR language. In other words, it will be possible to parse arbitrary LLVM IR assembly files into an in-memory representation, aka the one defined in package llir/llvm/ir. And the in-memory IR representation will have support for the entire LLVM IR language, and can be converted back to LLVM IR assembly for interaction with other tools, such as the LLVM optimizer.

    Any feedback is welcome, so we know we're heading in the right direction.

    Cheerful regards, /u & i

  • irgen: starter instructions

    irgen: starter instructions

    According to language reference: phi:

    There must be no non-phi instructions between the start of a basic block and the PHI instructions: i.e. PHI instructions must be first in a basic block.

    and the following code can be compiled by llc:

    Loop:       ; Infinite loop that counts from 0 on up...
      %indvar = phi i32 [ 0, %LoopHeader ], [ %nextindvar, %Loop ]
      %indvar2 = phi i32 [ 0, %LoopHeader ], [ %nextindvar, %Loop ]
      %nextindvar = add i32 %indvar, 1
      br label %Loop
    

    That means phi is kind of starter instruction, and we can have several starter instructions which always be put at the beginning of the basic block, then we can avoid this kind of code:

    firstAppear := loopCtx.NewPhi(ir.NewIncoming(loopCtx.compileExpr(s.InitExpr), ctx.Block))
    step := loopCtx.compileExpr(s.Step)
    firstAppear.Incs = append(firstAppear.Incs, ir.NewIncoming(step, loopCtx.Block))
    

    We can do like this:

    step := loopCtx.compileExpr(s.Step)
    firstAppear := loopCtx.NewPhi(
        ir.NewIncoming(loopCtx.compileExpr(s.InitExpr), ctx.Block),
        ir.NewIncoming(step, loopCtx.Block))
    

    but won't break order we expected, and we would have new BasicBlock definition.

    type Block struct {
        Starters []Starter
    }
    
  • proposal: remove cached type of instructions

    proposal: remove cached type of instructions

    The proposal of this issue is to remove the result type cache of instructions in the ir package. Or at least investigate the benefits and drawbacks of removing the type cache. First, lets start with a background of what the type cache is, before getting into discussing if we should remove or keep it.

    For most value instructions (i.e. ir.Instructions implementing the value.Value interface), the type of the resulting value computed by the instruction is currently cached.

    To give an example, lets consider the InstXor instruction.

    type InstXor struct {
        // Name of local variable associated with the result.
        LocalIdent
        // Operands.
        X, Y value.Value // integer scalars or vectors
    
        // Type of result produced by the instruction.
        Typ types.Type
        // (optional) Metadata.
        Metadata
    }
    

    The result type is cached in the Typ field of the InstXor struct, and the cached type is computed as follows:

    From: https://github.com/llir/llvm/blob/b85ca175725ff59102503c86be2934bd3b9a99d3/ir/inst_bitwise.go#L328

    func (inst *InstXor) Type() types.Type {
    	// Cache type if not present.
    	if inst.Typ == nil {
    		inst.Typ = inst.X.Type()
    	}
    	return inst.Typ
    }
    

    If we were to remove the result type cache of InstXor, the Type() method would look as follows:

    func (inst *InstXor) Type() types.Type {
    	return inst.X.Type()
    }
    

    The result type cache was introduced primarily as a (potentially premature) optimization to avoid memory allocation when invoking the Type method for instructions that need to compute their result type.

    The issue with caching the result type is that if you were to modify a given IR and change say the type of a function parameter from i32 to i64, then this change would propagate correctly for all uses of the function parameter, but if the parameter was used as the parameter of an instruction (say an xor instruction), then the result type of the xor instruction would have a cached i32 type, ever after updating the type of the function parameter to i64. To recompute the type, a user of the ir package would then have to reset the Typ field of InstXor to nil, so that the next invocation of Type() would recompute the cache.

    This approach is indeed doable, although fragile and perhaps unintuitive, at least to users not firmly aware of the internal details of result type caching.

    For now, I've added a ResetTypes convenience function to the irutil package which resets the type cache of value instructions. This function is analogous to the ResetNames function which is used to reset the IDs of unnamed local identifiers in functions.

    While introducing the ResetTypes function makes handling reset of type caches less painful, there are still subtle bugs that may exist for users who does not know of its existence and thus forget to call ResetTypes where appropriate.

    I propose that we investigate removing cached result types of value instructions altogether. Potentially keeping one edge case where we cache the result of the getelementptr instruction, as essentially all this function does is to compute a result type. With this rationale, we may also wish to keep the cached type of call instructions and the invoke and callbr terminators, since they record information about the callee/invokee which may otherwise be unavailable.

    The potential downside of removing the type cache is that we may get more memory allocations if the Type() method is invoked a lot. However, if that ever were to become an issue, then tight loops invoking Type could introduce a purpose specific type cache should the need arise.

    The benefit of removing the type cache is a less confusing and more intuitive ir API.

    Food for thought.

    Cheers, Robin

    cc: @pwaller

  • reject non-pointer type for global

    reject non-pointer type for global

    If we define a new global

    module.NewGlobal(name, types.I8)
    

    it would cause an error that global variable reference must have pointer type

    Thus, I think this check is acceptable.

  • update llir/llvm to support 11.0

    update llir/llvm to support 11.0

    Current Status

    11.0 already released, reference: https://releases.llvm.org/download.html#11.0.0

    Changes

    Below from https://releases.llvm.org/11.0.0/docs/ReleaseNotes.html#id4

    • [ ] The callsite attribute vector-function-abi-variant has been added to describe the mapping between scalar functions and vector functions, to enable vectorization of call sites. The information provided by the attribute is interfaced via the API provided by the VFDatabase class. When scanning through the set of vector functions associated with a scalar call, the loop vectorizer now relies on VFDatabase, instead of TargetLibraryInfo.

    • [x] dereferenceable attributes and metadata on pointers no longer imply anything about the alignment of the pointer in question. Previously, some optimizations would make assumptions based on the type of the pointer. This behavior was undocumented. To preserve optimizations, frontends may need to be updated to generate appropriate align attributes and metadata.

    • [x] The DIModule metadata is extended to contain file and line number information. This information is used to represent Fortran modules debug info at IR level.

    • [x] LLVM IR now supports two distinct llvm::FixedVectorType and llvm::ScalableVectorType vector types, both derived from the base class llvm::VectorType. A number of algorithms dealing with IR vector types have been updated to make sure they work for both scalable and fixed vector types. Where possible, the code has been made generic to cover both cases using the base class. Specifically, places that were using the type unsigned to count the number of lanes of a vector are now using llvm::ElementCount. In places where uint64_t was used to denote the size in bits of a IR type we have partially migrated the codebase to using llvm::TypeSize.

    • [x] Branching on undef/poison is undefined behavior. It is needed for correctly analyzing value ranges based on branch conditions. This is consistent with MSan’s behavior as well.

    • [x] memset/memcpy/memmove can take undef/poison pointer(s) if the size to fill is zero.

    • [x] Passing undef/poison to a standard I/O library function call (printf/fputc/…) is undefined behavior. The new noundef attribute is attached to the functions’ arguments. The full list is available at llvm::inferLibFuncAttributes.

  • update llir/llvm to support 12.0

    update llir/llvm to support 12.0

    • 2021/03/11 https://www.phoronix.com/scan.php?page=news_item&px=LLVM-12.0-RC3-Released
    • 2021/04/01 https://www.phoronix.com/scan.php?page=news_item&px=LLVM-12.0-rc4-Released

    NOTE: send pull requests to branch llvm12.

    Changes to LLVM IR

    • Added the byref attribute to better represent argument passing for the amdgpu_kernel calling convention.
    • Added type parameter to the sret attribute to continue work on removing pointer element types.
    • The llvm.experimental.vector.reduce family of intrinsics has been renamed to drop the “experimental” from the name, reflecting their now fully supported status in the IR.
  • update llir/llvm to support LLVM 15.0

    update llir/llvm to support LLVM 15.0

    ref: #220.

    LLVM 15.0 is yet to be released (release candidate at: https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.0-rc1)

    TODO: Once released, create a diff as follows:

    wget https://github.com/llvm/llvm-project/archive/llvmorg-14.0.6.tar.gz
    wget https://github.com/llvm/llvm-project/archive/llvmorg-15.0.0.tar.gz
    tar zxf llvmorg-14.0.6.tar.gz
    tar zxf llvmorg-15.0.0.tar.gz
    git diff -w llvm-project-llvmorg-14.0.6/llvm/lib/AsmParser llvm-project-llvmorg-15.0.0/llvm/lib/AsmParser > llvm14.diff
    git diff -w llvm-project-llvmorg-14.0.6/llvm/include/llvm/IR/Attributes.td llvm-project-llvmorg-15.0.0/llvm/include/llvm/IR/Attributes.td >> llvm15.diff
    
  • `sizeof`?

    `sizeof`?

    How do you call the sizeof function from LLVM? When C code using sizeof is generated, the code generated just has a constant. Is there a way to find the size of an object from LLVM?

  • irutil: add stdlib package for C standard library declarations

    irutil: add stdlib package for C standard library declarations

    As suggested in https://github.com/llir/llvm/pull/187#issuecomment-860148771:

    I would say the biggest difficulty was the C standard library - it would be super cool to have a stdlib package, with bindings to the standard library. In the compiler/builtins.go file I wrote out the function signatures for a bit of the stdlib, but it would be awesome to automatically have bindings to the whole C stdlib.

    Add a new irutil/stdlib package containing function (and global variable) declarations for interacting with the C standard library.

    We should consider automatically doing this, perhaps using the LLVM compiler to parse the C standard library headers and generating LLVM IR function (and global variable) declarations.

    Then, we could parse the LLVM IR output using llir/llvm/asm to get the llir/llvm/ir representation to interact with.

    Will require some experimentation to find what approach works well, and is easy to work with.

    Edit: related issues #22, #178, #180.

  • Ignore type-checking

    Ignore type-checking

    I don't know what type my function's return type will be until I have made all of the code up to the return statement. Most of the time this works, however, when I try to do recursion, I get errors due to mismatching types. In addition, these errors are panics, so I can't ignore them. Is there any way to ignore these types, and have it figure out the types when converting a module to a string (because, by then, the types will all be figured out)?

  • Precision loss during round-trip of `ppc_fp128` hexadecimal floating-point constants (double-double arithmetic)

    Precision loss during round-trip of `ppc_fp128` hexadecimal floating-point constants (double-double arithmetic)

    There is a known precision loss when parsing and printing LLVM IR assembly containing ppc_fp128 hexadecimal floating-point constants. This issue was identified by @dannypsnl, and the cause has been researched by @dannypsnl (see https://github.com/llir/llvm/issues/31#issuecomment-569254215) and @scottshotgg (see https://github.com/llir/llvm/issues/31#issuecomment-569358328).

    Below follows a proof of concept illustrating the precision loss for the ppc_fp128 constant 0xM400C0000000000300000000010000000. From https://github.com/llir/llvm/issues/31#issuecomment-569254215

    The problem happened, in this case, was because the sum of high and low is not exact, I create an example for it:

    package main
    
    import (
    	"fmt"
    	"math/big"
    	"math"
    )
    
    func main() {
    	precision := uint(106)
    	// Operate on numbers of different precision.
    	var z big.Float
    	x := big.NewFloat(math.Float64frombits(0x0000000010000000)).SetPrec(precision)
    	y := big.NewFloat(math.Float64frombits(0x400C000000000030)).SetPrec(precision)
    	z.SetPrec(precision)
    	z.Add(x, y)
    	fmt.Printf("x = %.10g (%s, prec = %d, acc = %s)\n", x, x.Text('p', 0), x.Prec(), x.Acc())
    	fmt.Printf("y = %.10g (%s, prec = %d, acc = %s)\n", y, y.Text('p', 0), y.Prec(), y.Acc())
    	fmt.Printf("z = %.10g (%s, prec = %d, acc = %s)\n", &z, z.Text('p', 0), z.Prec(), z.Acc())
    }
    // Result:
    // x = 1.326247369e-315 (0x.8p-1045, prec = 106, acc = Exact)
    // y = 3.5 (0x.e000000000018p+2, prec = 106, acc = Exact)
    // z = 3.5 (0x.e000000000018p+2, prec = 106, acc = Below)
    

    Link to failing test case: https://github.com/llir/llvm/blob/433f268c042117d5b3e4a0d12976e5fc35db8ba8/ir/constant/const_float_test.go#L16

    go test github.com/llir/llvm/ir/constant -run TestNewFloatFromStringForPPCFP128
    

    Changing the precision of the math/big.Float from 106 (which is the precision of double-double arithmetic) to 1048 fixes this issue and resolves the loss of precision (see https://github.com/llir/llvm/issues/31#issuecomment-569124567). However, simply changing the precision to 1048 does not seem like the right fix, since it will affect the results of future arithmetic on these constants and may result in more memory usage and loss of performance.

    Leaving this issue open in the hopes that someone has the expertise needed to figure out what is going wrong, and come up with a solution.

    ref to sister issue #31.

  • cloning functions

    cloning functions

    Is there a simple way how to clone functions?

    I'd like to duplicate a function like this:

    func duplicate(m *ir.Module, foo string) {
        for _, f := range m.Funcs {                                             
            if f.GlobalIdent.GlobalName == foo {                      
                DuplicateFunc(m, f, foo + "_v2")
            }                                              
        } 
    }
    

    And afterwards I'd do some minor changes in the function code.

ECMAScript/JavaScript engine in pure Go

goja ECMAScript 5.1(+) implementation in Go. Goja is an implementation of ECMAScript 5.1 in pure Go with emphasis on standard compliance and performan

Jan 1, 2023
A parser library for Go
A parser library for Go

A dead simple parser package for Go V2 Introduction Tutorial Tag syntax Overview Grammar syntax Capturing Capturing boolean value Streaming Lexing Sta

Dec 30, 2022
Mathematical expression parsing and calculation engine library. 数学表达式解析计算引擎库

Math-Engine 使用 Go 实现的数学表达式解析计算引擎库,它小巧,无任何依赖,具有扩展性(比如可以注册自己的函数到引擎中),比较完整的完成了数学表达式解析执行,包括词法分析、语法分析、构建AST、运行。 go get -u github.com/dengsgo/math-engine 能够

Jan 3, 2023
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io

The V Programming Language vlang.io | Docs | Changelog | Speed | Contributing & compiler design Key Features of V Simplicity: the language can be lear

Jan 4, 2023
Library for interacting with LLVM IR in pure Go.

llvm Library for interacting with LLVM IR in pure Go. Introduction Introductory blog post "LLVM IR and Go" Our Document Installation go get -u github.

Dec 24, 2022
Terminal interface to search the llvm C wrapper (llvm-c) API

Introduction This tool scrapes the LLVM-C API and (currently) prints all available API functions to stdout. It came to be from the lack of search opti

Dec 2, 2022
franz-go contains a high performance, pure Go library for interacting with Kafka from 0.8.0 through 2.7.0+. Producing, consuming, transacting, administrating, etc.

franz-go - Apache Kafka client written in Go Franz-go is an all-encompassing Apache Kafka client fully written Go. This library aims to provide every

Dec 29, 2022
Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM.

TinyGo - Go compiler for small places TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and comma

Dec 30, 2022
Live coding a basic Go compiler with LLVM in 20 minutes

go2ll-talk The code presented at Sheffield Go, 7th March. Slides link To run, just say make. To take a look at the output of the program, run go run .

Jul 2, 2022
Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM.

TinyGo - Go compiler for small places TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and comma

Jan 4, 2023
Golang client library for adding support for interacting and monitoring Celery workers, tasks and events.

Celeriac Golang client library for adding support for interacting and monitoring Celery workers and tasks. It provides functionality to place tasks on

Oct 28, 2022
Go library for interacting with CircleCI

go-circleci Go library for interacting with CircleCI's API. Supports all current API endpoints allowing you do do things like: Query for recent builds

Nov 26, 2022
Go client library for interacting with Coinpaprika's API

Coinpaprika API Go Client Usage This library provides convenient way to use coinpaprika.com API in Go. Coinpaprika delivers full market data to the wo

Dec 8, 2022
A Go library for interacting with Cloudflare's API v4.

Go library for the Cloudflare v4 API

Dec 29, 2022
A Go library for interacting with the Hypixel API.

gopixel gopixel is a Go library for interacting with the Hypixel API. This software is alpha software and is subject to change, including but not limi

Apr 1, 2022
Go library for interacting with the Discord API (work-in-progress)

zombiezen Go Client for Discord zombiezen.com/go/discord is a WIP Go library for interacting with the Discord API. It differs from DiscordGo by provid

Nov 9, 2022
It's client library written in Golang for interacting with Linkedin Cruise Control using its HTTP API.

go-cruise-control It's client library (written in Golang) for interacting with Linkedin Cruise Control using its HTTP API. Supported Cruise Control ve

Jan 10, 2022
Library for directly interacting and controlling an Elgato Stream Deck on Linux.

Stream Deck Library for directly interacting and controlling an Elgato Stream Deck on Linux. This library is designed to take exclusive control over a

Dec 17, 2022
A go library for interacting with Google Verified SMS

verifiedsms This is a go library for interacting with the Google Verified SMS service. You'll need to already be signed up as a Verified SMS Partner t

Aug 18, 2022
:money_with_wings: CLI app for interacting with paymail service providers
:money_with_wings: CLI app for interacting with paymail service providers

Paymail Inspector CLI application for interacting with paymail service providers Table of Contents Installation Commands Documentation Examples & Test

Dec 14, 2022