-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package llvm | ||
|
||
/* | ||
#include "llvm-c/Transforms/PassBuilder.h" | ||
#include "llvm-c/Error.h" | ||
#include <stdlib.h> | ||
*/ | ||
import "C" | ||
import ( | ||
"errors" | ||
"unsafe" | ||
) | ||
|
||
// PassBuilderOptions allows specifying several options for the PassBuilder. | ||
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 conscious | ||
// 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. Useful for | ||
// debugging, but adds a significant amount of overhead. | ||
func (pbo PassBuilderOptions) SetVerifyEach(verifyEach bool) { | ||
C.LLVMPassBuilderOptionsSetVerifyEach(pbo.C, boolToLLVMBool(verifyEach)) | ||
} | ||
|
||
// SetDebugLogging toggles debug logging for the PassBuilder. | ||
func (pbo PassBuilderOptions) SetDebugLogging(debugLogging bool) { | ||
C.LLVMPassBuilderOptionsSetDebugLogging(pbo.C, boolToLLVMBool(debugLogging)) | ||
} | ||
|
||
// SetLoopInterleaving toggles loop interleaving, which is part of | ||
// loop vectorization. | ||
func (pbo PassBuilderOptions) SetLoopInterleaving(loopInterleaving bool) { | ||
C.LLVMPassBuilderOptionsSetLoopInterleaving(pbo.C, boolToLLVMBool(loopInterleaving)) | ||
} | ||
|
||
// SetLoopVectorization toggles loop vectorization. | ||
func (pbo PassBuilderOptions) SetLoopVectorization(loopVectorization bool) { | ||
C.LLVMPassBuilderOptionsSetLoopVectorization(pbo.C, boolToLLVMBool(loopVectorization)) | ||
} | ||
|
||
// SetSLPVectorization toggles Super-Word Level Parallelism vectorization, | ||
// whose goal is to combine multiple similar independent instructions into | ||
// a vector instruction. | ||
func (pbo PassBuilderOptions) SetSLPVectorization(slpVectorization bool) { | ||
C.LLVMPassBuilderOptionsSetSLPVectorization(pbo.C, boolToLLVMBool(slpVectorization)) | ||
} | ||
|
||
// SetLoopUnrolling toggles loop unrolling. | ||
func (pbo PassBuilderOptions) SetLoopUnrolling(loopUnrolling bool) { | ||
C.LLVMPassBuilderOptionsSetLoopUnrolling(pbo.C, boolToLLVMBool(loopUnrolling)) | ||
} | ||
|
||
// SetForgetAllSCEVInLoopUnroll toggles forgetting all SCEV (Scalar Evolution) | ||
// information in loop unrolling. Scalar Evolution is a pass that analyses | ||
// the how scalars evolve over iterations of a loop in order to optimize | ||
// the loop better. Forgetting this information can be useful in some cases. | ||
func (pbo PassBuilderOptions) SetForgetAllSCEVInLoopUnroll(forgetSCEV bool) { | ||
C.LLVMPassBuilderOptionsSetForgetAllSCEVInLoopUnroll(pbo.C, boolToLLVMBool(forgetSCEV)) | ||
} | ||
|
||
// SetLicmMssaOptCap sets a tuning option to cap the number of calls to | ||
// retrieve clobbering accesses in MemorySSA, in Loop Invariant Code Motion | ||
// optimization. | ||
// See [llvm::PipelineTuningOptions::LicmMssaOptCap]. | ||
func (pbo PassBuilderOptions) SetLicmMssaOptCap(optCap uint) { | ||
C.LLVMPassBuilderOptionsSetLicmMssaOptCap(pbo.C, C.unsigned(optCap)) | ||
} | ||
|
||
// SetLicmMssaNoAccForPromotionCap sets a tuning option to cap the number of | ||
// promotions to scalars in Loop Invariant Code Motion with MemorySSA, if | ||
// the number of accesses is too large. | ||
// See [llvm::PipelineTuningOptions::LicmMssaNoAccForPromotionCap]. | ||
func (pbo PassBuilderOptions) SetLicmMssaNoAccForPromotionCap(promotionCap uint) { | ||
C.LLVMPassBuilderOptionsSetLicmMssaNoAccForPromotionCap(pbo.C, C.unsigned(promotionCap)) | ||
} | ||
|
||
// SetCallGraphProfile toggles whether call graph profiling should be used. | ||
func (pbo PassBuilderOptions) SetCallGraphProfile(cgProfile bool) { | ||
C.LLVMPassBuilderOptionsSetCallGraphProfile(pbo.C, boolToLLVMBool(cgProfile)) | ||
} | ||
|
||
// SetMergeFunctions toggles finding functions which will generate identical | ||
// machine code by considering all pointer types to be equivalent. Once | ||
// identified, they will be folded by replacing a call to one with a call to a | ||
// bitcast of the other. | ||
func (pbo PassBuilderOptions) SetMergeFunctions(mergeFuncs bool) { | ||
C.LLVMPassBuilderOptionsSetMergeFunctions(pbo.C, boolToLLVMBool(mergeFuncs)) | ||
} | ||
|
||
// Dispose of the memory allocated for the PassBuilderOptions. | ||
func (pbo PassBuilderOptions) Dispose() { | ||
C.LLVMDisposePassBuilderOptions(pbo.C) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package llvm | ||
|
||
import "testing" | ||
|
||
func TestPasses(t *testing.T) { | ||
InitializeNativeTarget() | ||
InitializeNativeAsmPrinter() | ||
|
||
ctx := NewContext() | ||
|
||
mod := ctx.NewModule("fac_module") | ||
|
||
fac_args := []Type{ctx.Int32Type()} | ||
fac_type := FunctionType(ctx.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 := ctx.NewBuilder() | ||
defer builder.Dispose() | ||
|
||
builder.SetInsertPointAtEnd(entry) | ||
If := builder.CreateICmp(IntEQ, n, ConstInt(ctx.Int32Type(), 0, false), "cmptmp") | ||
builder.CreateCondBr(If, iftrue, iffalse) | ||
|
||
builder.SetInsertPointAtEnd(iftrue) | ||
res_iftrue := ConstInt(ctx.Int32Type(), 1, false) | ||
builder.CreateBr(end) | ||
|
||
builder.SetInsertPointAtEnd(iffalse) | ||
n_minus := builder.CreateSub(n, ConstInt(ctx.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(ctx.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) | ||
} | ||
}) | ||
} |