ruby-llvm 16.0.1 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,688 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLVM
4
+ class PassBuilder # rubocop:disable Metrics/ClassLength
5
+ extend FFI::Library
6
+ ffi_lib ["libLLVM-17.so.1", "libLLVM.so.17", "LLVM-17"]
7
+
8
+ attr_reader :passes
9
+ attr_accessor :inliner_threshold
10
+
11
+ # rubocop:disable Layout/LineLength
12
+ OPT_PASSES = {
13
+ '0' => 'always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),function(annotation-remarks),verify',
14
+ '1' => 'annotation2metadata,forceattrs,inferattrs,coro-early,function<eager-inv>(lower-expect,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,sroa<modify-cfg>,early-cse<>),openmp-opt,ipsccp,called-value-propagation,globalopt,function<eager-inv>(mem2reg,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),require<globals-aa>,function(invalidate<aa>),require<profile-summary>,cgscc(devirt<4>(inline<only-mandatory>,inline,function-attrs<skip-non-recursive>,function<eager-inv;no-rerun>(sroa<modify-cfg>,early-cse<memssa>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,libcalls-shrinkwrap,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,reassociate,loop-mssa(loop-instsimplify,loop-simplifycfg,licm<no-allowspeculation>,loop-rotate<header-duplication;no-prepare-for-lto>,licm<allowspeculation>,simple-loop-unswitch<no-nontrivial;trivial>),simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,loop(loop-idiom,indvars,loop-deletion,loop-unroll-full),sroa<modify-cfg>,memcpyopt,sccp,bdce,instcombine<max-iterations=1000;no-use-loop-info>,coro-elide,adce,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>),function-attrs,function(require<should-not-run-function-passes>),coro-split)),deadargelim,coro-cleanup,globalopt,globaldce,elim-avail-extern,rpo-function-attrs,recompute-globalsaa,function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;vectorize-forced-only;>,loop-load-elim,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,vector-combine,instcombine<max-iterations=1000;no-use-loop-info>,loop-unroll<O1>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1000;no-use-loop-info>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),globaldce,constmerge,cg-profile,rel-lookup-table-converter,function(annotation-remarks),verify',
15
+ '2' => 'annotation2metadata,forceattrs,inferattrs,coro-early,function<eager-inv>(lower-expect,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,sroa<modify-cfg>,early-cse<>),openmp-opt,ipsccp,called-value-propagation,globalopt,function<eager-inv>(mem2reg,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),require<globals-aa>,function(invalidate<aa>),require<profile-summary>,cgscc(devirt<4>(inline<only-mandatory>,inline,function-attrs<skip-non-recursive>,openmp-opt-cgscc,function<eager-inv;no-rerun>(sroa<modify-cfg>,early-cse<memssa>,speculative-execution,jump-threading,correlated-propagation,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,aggressive-instcombine,constraint-elimination,libcalls-shrinkwrap,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,reassociate,loop-mssa(loop-instsimplify,loop-simplifycfg,licm<no-allowspeculation>,loop-rotate<header-duplication;no-prepare-for-lto>,licm<allowspeculation>,simple-loop-unswitch<no-nontrivial;trivial>),simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,loop(loop-idiom,indvars,loop-deletion,loop-unroll-full),sroa<modify-cfg>,vector-combine,mldst-motion<no-split-footer-bb>,gvn<>,sccp,bdce,instcombine<max-iterations=1000;no-use-loop-info>,jump-threading,correlated-propagation,adce,memcpyopt,dse,move-auto-init,loop-mssa(licm<allowspeculation>),coro-elide,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>),function-attrs,function(require<should-not-run-function-passes>),coro-split)),deadargelim,coro-cleanup,globalopt,globaldce,elim-avail-extern,rpo-function-attrs,recompute-globalsaa,function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,loop-load-elim,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,slp-vectorizer,vector-combine,instcombine<max-iterations=1000;no-use-loop-info>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1000;no-use-loop-info>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),globaldce,constmerge,cg-profile,rel-lookup-table-converter,function(annotation-remarks),verify',
16
+ '3' => 'annotation2metadata,forceattrs,inferattrs,coro-early,function<eager-inv>(lower-expect,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,sroa<modify-cfg>,early-cse<>,callsite-splitting),openmp-opt,ipsccp,called-value-propagation,globalopt,function<eager-inv>(mem2reg,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),require<globals-aa>,function(invalidate<aa>),require<profile-summary>,cgscc(devirt<4>(inline<only-mandatory>,inline,function-attrs<skip-non-recursive>,argpromotion,openmp-opt-cgscc,function<eager-inv;no-rerun>(sroa<modify-cfg>,early-cse<memssa>,speculative-execution,jump-threading,correlated-propagation,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,aggressive-instcombine,constraint-elimination,libcalls-shrinkwrap,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,reassociate,loop-mssa(loop-instsimplify,loop-simplifycfg,licm<no-allowspeculation>,loop-rotate<header-duplication;no-prepare-for-lto>,licm<allowspeculation>,simple-loop-unswitch<nontrivial;trivial>),simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,loop(loop-idiom,indvars,loop-deletion,loop-unroll-full),sroa<modify-cfg>,vector-combine,mldst-motion<no-split-footer-bb>,gvn<>,sccp,bdce,instcombine<max-iterations=1000;no-use-loop-info>,jump-threading,correlated-propagation,adce,memcpyopt,dse,move-auto-init,loop-mssa(licm<allowspeculation>),coro-elide,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>),function-attrs,function(require<should-not-run-function-passes>),coro-split)),deadargelim,coro-cleanup,globalopt,globaldce,elim-avail-extern,rpo-function-attrs,recompute-globalsaa,function<eager-inv>(float2int,lower-constant-intrinsics,chr,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,loop-load-elim,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,slp-vectorizer,vector-combine,instcombine<max-iterations=1000;no-use-loop-info>,loop-unroll<O3>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1000;no-use-loop-info>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),globaldce,constmerge,cg-profile,rel-lookup-table-converter,function(annotation-remarks),verify',
17
+ 's' => 'annotation2metadata,forceattrs,inferattrs,coro-early,function<eager-inv>(lower-expect,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,sroa<modify-cfg>,early-cse<>),openmp-opt,ipsccp,called-value-propagation,globalopt,function<eager-inv>(mem2reg,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),require<globals-aa>,function(invalidate<aa>),require<profile-summary>,cgscc(devirt<4>(inline<only-mandatory>,inline,function-attrs<skip-non-recursive>,function<eager-inv;no-rerun>(sroa<modify-cfg>,early-cse<memssa>,speculative-execution,jump-threading,correlated-propagation,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,aggressive-instcombine,constraint-elimination,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,reassociate,loop-mssa(loop-instsimplify,loop-simplifycfg,licm<no-allowspeculation>,loop-rotate<header-duplication;no-prepare-for-lto>,licm<allowspeculation>,simple-loop-unswitch<no-nontrivial;trivial>),simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,loop(loop-idiom,indvars,loop-deletion,loop-unroll-full),sroa<modify-cfg>,vector-combine,mldst-motion<no-split-footer-bb>,gvn<>,sccp,bdce,instcombine<max-iterations=1000;no-use-loop-info>,jump-threading,correlated-propagation,adce,memcpyopt,dse,move-auto-init,loop-mssa(licm<allowspeculation>),coro-elide,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>),function-attrs,function(require<should-not-run-function-passes>),coro-split)),deadargelim,coro-cleanup,globalopt,globaldce,elim-avail-extern,rpo-function-attrs,recompute-globalsaa,function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,loop-load-elim,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,slp-vectorizer,vector-combine,instcombine<max-iterations=1000;no-use-loop-info>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1000;no-use-loop-info>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),globaldce,constmerge,cg-profile,rel-lookup-table-converter,function(annotation-remarks),verify',
18
+ 'z' => 'annotation2metadata,forceattrs,inferattrs,coro-early,function<eager-inv>(lower-expect,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,sroa<modify-cfg>,early-cse<>),openmp-opt,ipsccp,called-value-propagation,globalopt,function<eager-inv>(mem2reg,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),require<globals-aa>,function(invalidate<aa>),require<profile-summary>,cgscc(devirt<4>(inline<only-mandatory>,inline,function-attrs<skip-non-recursive>,function<eager-inv;no-rerun>(sroa<modify-cfg>,early-cse<memssa>,speculative-execution,jump-threading,correlated-propagation,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,aggressive-instcombine,constraint-elimination,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,reassociate,loop-mssa(loop-instsimplify,loop-simplifycfg,licm<no-allowspeculation>,loop-rotate<no-header-duplication;no-prepare-for-lto>,licm<allowspeculation>,simple-loop-unswitch<no-nontrivial;trivial>),simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>,loop(loop-idiom,indvars,loop-deletion,loop-unroll-full),sroa<modify-cfg>,vector-combine,mldst-motion<no-split-footer-bb>,gvn<>,sccp,bdce,instcombine<max-iterations=1000;no-use-loop-info>,jump-threading,correlated-propagation,adce,memcpyopt,dse,move-auto-init,loop-mssa(licm<allowspeculation>),coro-elide,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,instcombine<max-iterations=1000;no-use-loop-info>),function-attrs,function(require<should-not-run-function-passes>),coro-split)),deadargelim,coro-cleanup,globalopt,globaldce,elim-avail-extern,rpo-function-attrs,recompute-globalsaa,function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<no-header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;vectorize-forced-only;>,loop-load-elim,instcombine<max-iterations=1000;no-use-loop-info>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,vector-combine,instcombine<max-iterations=1000;no-use-loop-info>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1000;no-use-loop-info>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>),globaldce,constmerge,cg-profile,rel-lookup-table-converter,function(annotation-remarks),verify',
19
+ }.freeze
20
+ # rubocop:enable Layout/LineLength
21
+
22
+ def initialize
23
+ @passes = []
24
+ @inliner_threshold = nil
25
+ end
26
+
27
+ def add_function_pass
28
+ pb = PassBuilder.new
29
+ if block_given?
30
+ yield pb
31
+ end
32
+
33
+ add_pass("function(#{pb.pass_string})")
34
+ end
35
+
36
+ # --O0 - Optimization level 0. Similar to clang -O0. Use -passes='default<O0>' for the new PM
37
+ # --O1 - Optimization level 1. Similar to clang -O1. Use -passes='default<O1>' for the new PM
38
+ # --O2 - Optimization level 2. Similar to clang -O2. Use -passes='default<O2>' for the new PM
39
+ # --O3 - Optimization level 3. Similar to clang -O3. Use -passes='default<O3>' for the new PM
40
+ # --Os - Like -O2 but size-conscious. Similar to clang -Os. Use -passes='default<Os>' for the new PM
41
+ # --Oz - Like -O2 but optimize for code size above all else. Similar to clang -Oz. Use -passes='default<Oz>' for the new PM
42
+ # @return self
43
+ def o!(opt_level = '0')
44
+ opt_level = opt_level.to_s
45
+ if inliner_threshold || !OPT_PASSES.key?(opt_level)
46
+ add_pass("default<O#{opt_level}>")
47
+ else
48
+ add_pass(OPT_PASSES[opt_level].gsub(',inline,', ','))
49
+ end
50
+ end
51
+
52
+ # @return self
53
+ def add_pass(pass)
54
+ passes << pass
55
+ self
56
+ end
57
+
58
+ # @return self
59
+ def dce!
60
+ add_pass('dce')
61
+ end
62
+
63
+ # @return self
64
+ def licm!
65
+ add_pass('licm')
66
+ end
67
+
68
+ # A pass to simplify and canonicalize the CFG of a function.
69
+ # This pass iteratively simplifies the entire CFG of a function. It may change
70
+ # or remove control flow to put the CFG into a canonical form expected by
71
+ # other passes of the mid-level optimizer. Depending on the specified options,
72
+ # it may further optimize control-flow to create non-canonical form
73
+ # https://llvm.org/doxygen/SimplifyCFG_8h_source.html
74
+ # TODO: takes params
75
+ # Options: simplifycfg<no-forward-switch-cond;forward-switch-cond;no-switch-range-to-icmp;switch-range-to-icmp;no-switch-to-lookup;switch-to-lookup;no-keep-loops;keep-loops;no-hoist-common-insts;hoist-common-insts;no-sink-common-insts;sink-common-insts;bonus-inst-threshold=N>
76
+ # @return self
77
+ def simplifycfg!
78
+ add_pass('simplifycfg')
79
+ end
80
+
81
+ # @return self
82
+ def scalarizer!
83
+ add_pass('scalarizer')
84
+ end
85
+
86
+ # Merged Load Store Motion
87
+ # @return self
88
+ def mldst_motion!
89
+ add_pass('mldst-motion')
90
+ end
91
+
92
+ # Global Value Numbering pass
93
+ # https://llvm.org/doxygen/GVN_8h_source.html
94
+ # TODO: takes params
95
+ # @return self
96
+ def gvn!
97
+ add_pass('gvn')
98
+ end
99
+
100
+ # New Global Value Numbering pass
101
+ # https://llvm.org/doxygen/NewGVN_8cpp.html#details
102
+ # @return self
103
+ def newgvn!
104
+ add_pass('newgvn')
105
+ end
106
+
107
+ # hoists expressions from branches to a common dominator.
108
+ # https://llvm.org/doxygen/GVNHoist_8cpp_source.html
109
+ # @return self
110
+ def gvn_hoist!
111
+ add_pass('gvn-hoist')
112
+ end
113
+
114
+ # sink instructions into successors
115
+ # https://llvm.org/doxygen/GVNSink_8cpp_source.html
116
+ # @return self
117
+ def gvn_sink!
118
+ add_pass('gvn-sink')
119
+ end
120
+
121
+ # @return self
122
+ def jump_threading!
123
+ add_pass('jump-threading')
124
+ end
125
+
126
+ # @return self
127
+ def indvars!
128
+ add_pass('indvars')
129
+ end
130
+
131
+ # @return self
132
+ def alignment_from_assumptions!
133
+ add_pass('alignment-from-assumptions')
134
+ end
135
+
136
+ # @return self
137
+ def loop_deletion!
138
+ add_pass('loop-deletion')
139
+ end
140
+
141
+ # @return self
142
+ def loop_idiom!
143
+ add_pass('loop-idiom')
144
+ end
145
+
146
+ # @return self
147
+ def loop_rotate!
148
+ add_pass('loop-rotate')
149
+ end
150
+
151
+ # @return self
152
+ def loop_reroll!
153
+ add_pass('loop-reroll')
154
+ end
155
+
156
+ # @return self
157
+ def loop_unroll!
158
+ add_pass('loop-unroll')
159
+ end
160
+
161
+ # @return self
162
+ def loop_unroll_and_jam!
163
+ add_pass('loop-unroll-and-jam')
164
+ end
165
+
166
+ # @return self
167
+ def simple_loop_unswitch!
168
+ add_pass('simple-loop-unswitch')
169
+ end
170
+
171
+ # @return self
172
+ def loop_unswitch!
173
+ simple_loop_unswitch!
174
+ end
175
+
176
+ # TODO: takes params
177
+ # @return self
178
+ def loop_vectorize!
179
+ add_pass('loop-vectorize')
180
+ end
181
+
182
+ # @return self
183
+ def memcpyopt!
184
+ add_pass('memcpyopt')
185
+ end
186
+
187
+ # @return self
188
+ def sccp!
189
+ add_pass('sccp')
190
+ end
191
+
192
+ # Combine instructions to form fewer, simple instructions.
193
+ # This pass does not modify the CFG.
194
+ # This pass is where algebraic simplification happens.
195
+ # https://llvm.org/doxygen/InstructionCombining_8cpp_source.html
196
+ # https://llvm.org/doxygen/InstCombineInternal_8h_source.html
197
+ # @return self
198
+ def instcombine!
199
+ add_pass('instcombine')
200
+ end
201
+
202
+ # @return self
203
+ def instsimplify!
204
+ add_pass('instsimplify')
205
+ end
206
+
207
+ # @return self
208
+ def loweratomic!
209
+ add_pass('loweratomic')
210
+ end
211
+
212
+ # @return self
213
+ def partially_inline_libcalls!
214
+ add_pass('partially-inline-libcalls')
215
+ end
216
+
217
+ # @return self
218
+ def reassociate!
219
+ add_pass('reassociate')
220
+ end
221
+
222
+ # @return self
223
+ def tailcallelim!
224
+ add_pass('tailcallelim')
225
+ end
226
+
227
+ # @return self
228
+ def reg2mem!
229
+ add_pass('reg2mem')
230
+ end
231
+
232
+ # @return self
233
+ def mem2reg!
234
+ add_pass('mem2reg')
235
+ end
236
+
237
+ # @return self
238
+ def verify!
239
+ add_pass('verify')
240
+ end
241
+
242
+ # @return self
243
+ def module_summary!
244
+ add_pass('require<module-summary>')
245
+ end
246
+
247
+ # @return self
248
+ def no_op_module!
249
+ add_pass('no-op-module')
250
+ end
251
+
252
+ # @return self
253
+ def no_op_cgscc!
254
+ add_pass('no-op-cgscc')
255
+ end
256
+
257
+ # @return self
258
+ def no_op_function!
259
+ add_pass('no-op-function')
260
+ end
261
+
262
+ # @return self
263
+ def stack_safety!
264
+ add_pass('require<stack-safety>')
265
+ end
266
+
267
+ # A simple and fast domtree-based CSE pass.
268
+ #
269
+ # This pass does a simple depth-first walk over the dominator tree,
270
+ # eliminating trivially redundant instructions and using instsimplify to
271
+ # canonicalize things as it goes. It is intended to be fast and catch obvious
272
+ # cases so that instcombine and other passes are more effective. It is
273
+ # expected that a later pass of GVN will catch the interesting/hard cases.
274
+ # https://llvm.org/doxygen/EarlyCSE_8h_source.html
275
+ # https://llvm.org/doxygen/EarlyCSE_8cpp.html
276
+ # @return self
277
+ def early_cse!
278
+ add_pass('early-cse')
279
+ end
280
+
281
+ # A simple and fast domtree-based CSE pass.
282
+ # https://llvm.org/doxygen/EarlyCSE_8h_source.html
283
+ # https://llvm.org/doxygen/EarlyCSE_8cpp.html
284
+ # @return self
285
+ def early_cse_memssa!
286
+ add_pass('early-cse<memssa>')
287
+ end
288
+
289
+ # @return self
290
+ def lcssa!
291
+ add_pass('lcssa')
292
+ end
293
+
294
+ # @return self
295
+ def memoryssa!
296
+ add_pass('require<memoryssa>')
297
+ end
298
+
299
+ # Scalar Replacement Of Aggregates
300
+ # https://llvm.org/doxygen/SROA_8h_source.html
301
+ # https://llvm.org/doxygen/SROA_8cpp.html
302
+ # @return self
303
+ def sroa!
304
+ add_pass('sroa')
305
+ end
306
+
307
+ # @return self
308
+ def lower_expect!
309
+ add_pass('lower-expect')
310
+ end
311
+
312
+ # @return self
313
+ def cvprop!
314
+ correlated_propagation!
315
+ end
316
+
317
+ # @return self
318
+ def correlated_propagation!
319
+ add_pass('correlated-propagation')
320
+ end
321
+
322
+ # @return self
323
+ def lower_constant_intrinsics!
324
+ add_pass('lower-constant-intrinsics')
325
+ end
326
+
327
+ # @return self
328
+ def slp_vectorize!
329
+ slp_vectorizer!
330
+ end
331
+
332
+ # @return self
333
+ def slp_vectorizer!
334
+ add_pass('slp-vectorizer')
335
+ end
336
+
337
+ # @return self
338
+ def add_discriminators!
339
+ add_pass('add-discriminators')
340
+ end
341
+
342
+ # @return self
343
+ def mergereturn!
344
+ add_pass('mergereturn')
345
+ end
346
+
347
+ # @return self
348
+ def mergeicmps!
349
+ add_pass('mergeicmps')
350
+ end
351
+
352
+ # @return self
353
+ def basic_aa!
354
+ add_pass('require<basic-aa>')
355
+ end
356
+
357
+ alias basicaa! basic_aa!
358
+
359
+ # @return self
360
+ def objc_arc_aa
361
+ add_pass('require<objc-arc-aa>')
362
+ end
363
+
364
+ # @return self
365
+ def scev_aa!
366
+ add_pass('require<scev-aa>')
367
+ end
368
+
369
+ # @return self
370
+ def scoped_noalias_aa!
371
+ add_pass('require<scoped-noalias-aa>')
372
+ end
373
+
374
+ # @return self
375
+ def tbaa!
376
+ add_pass('require<tbaa>')
377
+ end
378
+
379
+ # @return self
380
+ def gobals_aa!
381
+ add_pass('require<globals-aa>')
382
+ end
383
+
384
+ # @return self
385
+ def lowerswitch!
386
+ add_pass('lowerswitch')
387
+ end
388
+
389
+ # Inlines functions marked as "always_inline".
390
+ # https://llvm.org/doxygen/AlwaysInliner_8h_source.html
391
+ # https://llvm.org/doxygen/AlwaysInliner_8cpp_source.html
392
+ # @return self
393
+ def always_inline!
394
+ add_pass('always-inline')
395
+ end
396
+
397
+ # This pass looks for equivalent functions that are mergable and folds them.
398
+ # https://llvm.org/docs/MergeFunctions.html
399
+ # https://llvm.org/doxygen/MergeFunctions_8cpp_source.html
400
+ # https://llvm.org/doxygen/MergeFunctions_8h_source.html
401
+ # @return self
402
+ def mergefunc!
403
+ add_pass('mergefunc')
404
+ end
405
+
406
+ # Propagate called values
407
+ # This file implements a transformation that attaches !callees metadata to
408
+ # indirect call sites. For a given call site, the metadata, if present,
409
+ # indicates the set of functions the call site could possibly target at
410
+ # run-time. This metadata is added to indirect call sites when the set of
411
+ # possible targets can be determined by analysis and is known to be small. The
412
+ # analysis driving the transformation is similar to constant propagation and
413
+ # makes uses of the generic sparse propagation solver.
414
+ # https://llvm.org/doxygen/CalledValuePropagation_8h_source.html
415
+ # @return self
416
+ def called_value_propagation!
417
+ add_pass('called-value-propagation')
418
+ end
419
+
420
+ # @return self
421
+ def deadargelim!
422
+ add_pass('deadargelim')
423
+ end
424
+
425
+ alias dae! deadargelim!
426
+
427
+ # ConstantMerge is designed to build up a map of available constants and eliminate duplicates when it is initialized.
428
+ # https://llvm.org/doxygen/ConstantMerge_8cpp_source.html
429
+ # https://llvm.org/doxygen/ConstantMerge_8h_source.html
430
+ # @return self
431
+ def constmerge!
432
+ add_pass('constmerge')
433
+ end
434
+
435
+ alias const_merge! constmerge!
436
+
437
+ # Aggressive Dead Code Elimination
438
+ # @return self
439
+ def adce!
440
+ add_pass('adce')
441
+ end
442
+
443
+ # @return self
444
+ def function_attrs!
445
+ add_pass('function-attrs')
446
+ end
447
+
448
+ alias fun_attrs! function_attrs!
449
+
450
+ # @return self
451
+ def strip!
452
+ add_pass('strip')
453
+ end
454
+
455
+ # @return self
456
+ def strip_dead_prototypes!
457
+ add_pass('strip-dead-prototypes')
458
+ end
459
+
460
+ alias sdp! strip_dead_prototypes!
461
+
462
+ # @return self
463
+ # TODO: test this
464
+ def internalize!(_all_but_main = true) # rubocop:disable Style/OptionalBooleanParameter
465
+ add_pass('internalize')
466
+ end
467
+
468
+ # This pass implements interprocedural sparse conditional constant propagation and merging.
469
+ # https://llvm.org/doxygen/IPO_2SCCP_8h_source.html
470
+ # https://llvm.org/doxygen/IPO_2SCCP_8cpp_source.html
471
+ # @return self
472
+ # @todo accept parameters ipsccp<no-func-spec;func-spec>
473
+ def ipsccp!
474
+ add_pass('ipsccp')
475
+ end
476
+
477
+ # @return self
478
+ def global_opt!
479
+ add_pass('globalopt')
480
+ end
481
+
482
+ # Global Dead Code Elimination
483
+ # TODO: takes params
484
+ # @return self
485
+ def globaldce!
486
+ add_pass('globaldce')
487
+ end
488
+
489
+ alias gdce! globaldce!
490
+
491
+ # Bit-Tracking Dead Code Elimination pass
492
+ # @return self
493
+ def bdce!
494
+ add_pass('bdce')
495
+ end
496
+
497
+ # Dead Store Elimination
498
+ # his file implements a trivial dead store elimination that only considers basic-block local redundant stores.
499
+ # https://llvm.org/doxygen/DeadStoreElimination_8h_source.html
500
+ # @return self
501
+ def dse!
502
+ add_pass('dse')
503
+ end
504
+
505
+ # @return self
506
+ def argpromotion!
507
+ add_pass('argpromotion')
508
+ end
509
+
510
+ alias arg_promote! argpromotion!
511
+
512
+ # The inliner pass for the new pass manager.
513
+ # https://llvm.org/doxygen/classllvm_1_1InlinerPass.html
514
+ # https://llvm.org/doxygen/Inliner_8h_source.html
515
+ # https://llvm.org/doxygen/Inliner_8cpp_source.html
516
+ # @return self
517
+ def inline!
518
+ add_pass('inline')
519
+ end
520
+
521
+ # Thread Sanitizer
522
+ # https://clang.llvm.org/docs/ThreadSanitizer.html
523
+ # @return self
524
+ def tsan!
525
+ add_pass('tsan')
526
+ end
527
+
528
+ # Thread Sanitiver - Module
529
+ # https://clang.llvm.org/docs/ThreadSanitizer.html
530
+ # @return self
531
+ def tsan_module!
532
+ add_pass('tsan-module')
533
+ end
534
+
535
+ # Hardware Assisted Address Sanitiver
536
+ # TODO: takes params
537
+ # https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
538
+ # https://llvm.org/doxygen/HWAddressSanitizer_8cpp_source.html
539
+ # @return self
540
+ def hwasan!(_options = {})
541
+ add_pass('hwasan')
542
+ end
543
+
544
+ # Address Sanitizer
545
+ # TODO: takes params
546
+ # https://clang.llvm.org/docs/AddressSanitizer.html
547
+ # https://llvm.org/doxygen/AddressSanitizer_8h_source.html
548
+ # https://llvm.org/doxygen/AddressSanitizer_8cpp_source.html
549
+ # @return self
550
+ def asan!(options = {})
551
+ opt_str = options[:kernel] ? '<kernel>' : ''
552
+ add_pass("asan#{opt_str}")
553
+ end
554
+
555
+ # Memory Sanitizer
556
+ # TODO: takes params
557
+ # https://llvm.org/doxygen/MemorySanitizer_8cpp.html
558
+ # https://llvm.org/doxygen/MemorySanitizer_8h_source.html
559
+ # https://clang.llvm.org/docs/MemorySanitizer.html
560
+ # KernelMemorySanitizer only supports X86_64 and SystemZ at the moment.
561
+ # @return self
562
+ def msan!(options = {})
563
+ opt_str = options[:kernel] ? '<kernel>' : ''
564
+ add_pass("msan#{opt_str}")
565
+ end
566
+
567
+ # DataFlow Sanitizer
568
+ # https://clang.llvm.org/docs/DataFlowSanitizer.html
569
+ # @return self
570
+ def dfsan!
571
+ add_pass('dfsan')
572
+ end
573
+
574
+ # https://clang.llvm.org/docs/SanitizerCoverage.html
575
+ # @return self
576
+ def sancov_module!
577
+ add_pass('sancov-module')
578
+ end
579
+
580
+ # https://llvm.org/docs/doxygen/SanitizerBinaryMetadata_8h_source.html
581
+ # @return self
582
+ def sanmd_module!
583
+ add_pass('sanmd-module')
584
+ end
585
+
586
+ def run(mod, target)
587
+ return self if passes.empty?
588
+
589
+ options = build_options
590
+ error = C.run_passes(mod, pass_string, target, options)
591
+ if !error.null?
592
+ error_msg = get_error_message(error)
593
+ # save_message = error_msg.clone
594
+ # dispose_error_message(error_msg)
595
+ raise "There was an error: #{error_msg}"
596
+ end
597
+ self
598
+ end
599
+
600
+ def pass_string
601
+ passes.join(',')
602
+ end
603
+
604
+ def ipcp!
605
+ deprecated('ipcp! / LLVMAddIPConstantPropagationPass was removed from LLVM')
606
+ end
607
+
608
+ def prune_eh!
609
+ deprecated('prune_eh! / LLVMAddPruneEHPass was removed in LLVM 16')
610
+ end
611
+
612
+ def simplify_libcalls!
613
+ deprecated('simplify_libcalls! / LLVMAddSimplifyLibCallsPass was removed from LLVM')
614
+ end
615
+
616
+ def scalarrepl!
617
+ deprecated('TODO: scalarrepl')
618
+ end
619
+
620
+ def scalarrepl_ssa!
621
+ deprecated('TODO: scalarrepl_ssa')
622
+ end
623
+
624
+ def scalarrepl_threshold!(_threshold = 0)
625
+ deprecated('TODO: scalarrepl_threshold')
626
+ end
627
+
628
+ def bb_vectorize!
629
+ warn('bb_vectorize! / LLVMAddBBVectorizePass was removed from LLVM - replace with slp_vectorize!')
630
+ slp_vectorize!
631
+ end
632
+
633
+ def constprop!
634
+ warn('constprop! / LLVMAddConstantPropagationPass was removed from LLVM')
635
+ end
636
+
637
+ private
638
+
639
+ def build_options
640
+ options = C.create_pass_builder_options
641
+
642
+ if inliner_threshold
643
+ C.set_inliner_threshold(options, inliner_threshold)
644
+ end
645
+
646
+ options
647
+ end
648
+
649
+ attr_writer :passes
650
+
651
+ def deprecated(message)
652
+ warn message
653
+ self
654
+ end
655
+
656
+ end
657
+
658
+ module C
659
+ #
660
+ # @method run_passes(pmb, opt_level)
661
+ # @param [OpaquePassManagerBuilder] pmb
662
+ # @param [Integer] opt_level
663
+ # @return [nil]
664
+ # @scope class
665
+ # /**
666
+ # * Construct and run a set of passes over a module
667
+ # *
668
+ # * This function takes a string with the passes that should be used. The format
669
+ # * of this string is the same as opt's -passes argument for the new pass
670
+ # * manager. Individual passes may be specified, separated by commas. Full
671
+ # * pipelines may also be invoked using `default<O3>` and friends. See opt for
672
+ # * full reference of the Passes format.
673
+ # */
674
+ # LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes,
675
+ # LLVMTargetMachineRef TM,
676
+ # LLVMPassBuilderOptionsRef Options);
677
+
678
+ attach_function :run_passes, :LLVMRunPasses, [:pointer, :string, :pointer, :pointer], :pointer
679
+
680
+ attach_function :create_pass_builder_options, :LLVMCreatePassBuilderOptions, [], :pointer
681
+
682
+ attach_function(:get_error_message, :LLVMGetErrorMessage, [:pointer], :string)
683
+
684
+ attach_function(:dispose_error_message, :LLVMDisposeErrorMessage, [:string], :void)
685
+
686
+ attach_function(:set_inliner_threshold, :LLVMPassBuilderOptionsSetInlinerThreshold, [:pointer, :int], :void)
687
+ end
688
+ end