Skip to content

Commit

Permalink
Add new pass builder AP
Browse files Browse the repository at this point in the history
  • Loading branch information
rj45 committed Aug 25, 2023
1 parent 8e7ec80 commit cb7b895
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
101 changes: 101 additions & 0 deletions passes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package llvm

/*
#include "llvm-c/Transforms/PassBuilder.h"
#include "llvm-c/Error.h"
#include <stdlib.h>
*/
import "C"
import (
"errors"
"unsafe"
)

type PassBuilderOptions struct {
C C.LLVMPassBuilderOptionsRef
}

// NewPassBuilderOptions creates a PassBuilderOptions which can be used
// to specify pass options for RunPasses.
func NewPassBuilderOptions() (pbo PassBuilderOptions) {
pbo.C = C.LLVMCreatePassBuilderOptions()
return
}

// RunPasses runs the specified optimization passes on the functions in the module.
// `passes` is a comma separated list of pass names in the same format as llvm's
// `opt -passes=...` command. Running `opt -print-passes` can list the available
// passes.
//
// Some notable passes include:
//
// default<O0> -- run the default -O0 passes
// default<O1> -- run the default -O1 passes
// default<O2> -- run the default -O2 passes
// default<O3> -- run the default -O3 passes
// default<Os> -- run the default -Os passes, like -O2 but size concious
// default<Oz> -- run the default -Oz passes, optimizing for size above all else
func (mod Module) RunPasses(passes string, tm TargetMachine, options PassBuilderOptions) error {
cpasses := C.CString(passes)
defer C.free(unsafe.Pointer(cpasses))

err := C.LLVMRunPasses(mod.C, cpasses, tm.C, options.C)
if err != nil {
cstr := C.LLVMGetErrorMessage(err)
gstr := C.GoString(cstr)
C.LLVMDisposeErrorMessage(cstr)

return errors.New(gstr)
}
return nil
}

// SetVerifyEach toggles adding a VerifierPass to the PassBuilder,
// ensuring all functions inside the module are valid.
func (pbo PassBuilderOptions) SetVerifyEach(verifyEach bool) {
C.LLVMPassBuilderOptionsSetVerifyEach(pbo.C, boolToLLVMBool(verifyEach))
}

func (pbo PassBuilderOptions) SetDebugLogging(debugLogging bool) {
C.LLVMPassBuilderOptionsSetDebugLogging(pbo.C, boolToLLVMBool(debugLogging))
}

func (pbo PassBuilderOptions) SetLoopInterleaving(loopInterleaving bool) {
C.LLVMPassBuilderOptionsSetLoopInterleaving(pbo.C, boolToLLVMBool(loopInterleaving))
}

func (pbo PassBuilderOptions) SetLoopVectorization(loopVectorization bool) {
C.LLVMPassBuilderOptionsSetLoopVectorization(pbo.C, boolToLLVMBool(loopVectorization))
}

func (pbo PassBuilderOptions) SetSLPVectorization(slpVectorization bool) {
C.LLVMPassBuilderOptionsSetSLPVectorization(pbo.C, boolToLLVMBool(slpVectorization))
}

func (pbo PassBuilderOptions) SetLoopUnrolling(loopUnrolling bool) {
C.LLVMPassBuilderOptionsSetLoopUnrolling(pbo.C, boolToLLVMBool(loopUnrolling))
}

func (pbo PassBuilderOptions) SetForgetAllSCEVInLoopUnroll(forgetSCEV bool) {
C.LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll(pbo.C, boolToLLVMBool(forgetSCEV))
}

func (pbo PassBuilderOptions) SetLicmMssaOptCap(optCap uint) {
C.LLVMPassBuilderOptionsSetLicmMssaOptCap(pbo.C, C.unsigned(optCap))
}

func (pbo PassBuilderOptions) SetLicmMssaNoAccForPromotionCap(promotionCap uint) {
C.LLVMPassBuilderOptionsSetLicmMssaNoAccForPromotionCap(pbo.C, C.unsigned(promotionCap))
}

func (pbo PassBuilderOptions) SetCallGraphProfile(cgProfile bool) {
C.LLVMPassBuilderOptionsSetCallGraphProfile(pbo.C, boolToLLVMBool(cgProfile))
}

func (pbo PassBuilderOptions) SetMergeFunctions(mergeFuncs bool) {
C.LLVMPassBuilderOptionsSetMergeFunctions(pbo.C, boolToLLVMBool(mergeFuncs))
}

func (pbo PassBuilderOptions) Dispose() {
C.LLVMDisposePassBuilderOptions(pbo.C)
}
80 changes: 80 additions & 0 deletions passes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package llvm

import "testing"

func TestPasses(t *testing.T) {
InitializeNativeTarget()
InitializeNativeAsmPrinter()

mod := NewModule("fac_module")

fac_args := []Type{Int32Type()}
fac_type := FunctionType(Int32Type(), fac_args, false)
fac := AddFunction(mod, "fac", fac_type)
fac.SetFunctionCallConv(CCallConv)
n := fac.Param(0)

entry := AddBasicBlock(fac, "entry")
iftrue := AddBasicBlock(fac, "iftrue")
iffalse := AddBasicBlock(fac, "iffalse")
end := AddBasicBlock(fac, "end")

builder := NewBuilder()
defer builder.Dispose()

builder.SetInsertPointAtEnd(entry)
If := builder.CreateICmp(IntEQ, n, ConstInt(Int32Type(), 0, false), "cmptmp")
builder.CreateCondBr(If, iftrue, iffalse)

builder.SetInsertPointAtEnd(iftrue)
res_iftrue := ConstInt(Int32Type(), 1, false)
builder.CreateBr(end)

builder.SetInsertPointAtEnd(iffalse)
n_minus := builder.CreateSub(n, ConstInt(Int32Type(), 1, false), "subtmp")
call_fac_args := []Value{n_minus}
call_fac := builder.CreateCall(fac_type, fac, call_fac_args, "calltmp")
res_iffalse := builder.CreateMul(n, call_fac, "multmp")
builder.CreateBr(end)

builder.SetInsertPointAtEnd(end)
res := builder.CreatePHI(Int32Type(), "result")
phi_vals := []Value{res_iftrue, res_iffalse}
phi_blocks := []BasicBlock{iftrue, iffalse}
res.AddIncoming(phi_vals, phi_blocks)
builder.CreateRet(res)

err := VerifyModule(mod, ReturnStatusAction)
if err != nil {
t.Errorf("Error verifying module: %s", err)
return
}

targ, err := GetTargetFromTriple(DefaultTargetTriple())
if err != nil {
t.Error(err)
}

mt := targ.CreateTargetMachine(DefaultTargetTriple(), "", "", CodeGenLevelDefault, RelocDefault, CodeModelDefault)

pbo := NewPassBuilderOptions()
defer pbo.Dispose()

t.Run("no error running default pass", func(t *testing.T) {
err := mod.RunPasses("default<Os>", mt, pbo)
if err != nil {
t.Error(err)
}
})

t.Run("errors on unknown pass name", func(t *testing.T) {
err := mod.RunPasses("badpassnamedoesnotexist", mt, pbo)
if err == nil {
t.Error("expecting error but got none")
}

if err.Error() != "unknown pass name 'badpassnamedoesnotexist'" {
t.Errorf("expected error about unknow pass name, instead got %s", err)
}
})
}

0 comments on commit cb7b895

Please sign in to comment.