rltk 1.2.0 → 2.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,62 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/04/16
4
+ # Description: This file defines the MemoryBuffer class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+
13
+ #######################
14
+ # Classes and Modules #
15
+ #######################
16
+
17
+ module RLTK::CG # :nodoc:
18
+
19
+ # This class is used by the {Module} class to dump and load LLVM bitcode.
20
+ class MemoryBuffer
21
+ include BindingClass
22
+
23
+ # Create a new memory buffer.
24
+ #
25
+ # @param [FFI::Pointer, String, nil] overloaded This parameter may be either a pointer to an existing memory
26
+ # buffer, the name of a file containing LLVM bitcode, or nil. If it is nil the memory buffer will read
27
+ # from standard in.
28
+ def initialize(overloaded = nil)
29
+ @ptr =
30
+ case overloaded
31
+ when FFI::Pointer
32
+ overloaded
33
+ else
34
+ buf_ptr = FFI::MemoryPointer.new(:pointer)
35
+ msg_ptr = FFI::MemoryPointer.new(:pointer)
36
+
37
+ status =
38
+ case overloaded
39
+ when String
40
+ Bindings.create_memory_buffer_with_contents_of_file(overloaded, buf_ptr, msg_ptr)
41
+ else
42
+ Bindings.create_memory_buffer_with_stdin(buf_ptr, msg_ptr)
43
+ end
44
+
45
+ raise msg_ptr.get_pointer(0).get_string(0) if status != 0
46
+
47
+ buf_ptr.get_pointer(0)
48
+ end
49
+ end
50
+
51
+ # Frees the resources used by LLVM for this memory buffer.
52
+ #
53
+ # @return [void]
54
+ def dispose
55
+ if @ptr
56
+ Bindings.dispose_memory_buffer(@ptr)
57
+
58
+ @ptr = nil
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,328 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/20
4
+ # Description: This file defines the Module class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+ require 'rltk/cg/context'
13
+
14
+ #######################
15
+ # Classes and Modules #
16
+ #######################
17
+
18
+ module RLTK::CG # :nodoc:
19
+
20
+ # This class represents a collection of functions, constants, and global
21
+ # variables.
22
+ class Module
23
+ include BindingClass
24
+
25
+ # Load a module from LLVM bitcode.
26
+ #
27
+ # @see MemoryBuffer#initialize
28
+ #
29
+ # @param [MemoryBuffer, FFI::Pointer, String, nil] overloaded Where to read the bytecode from.
30
+ #
31
+ # @return [Module]
32
+ def self.read_bitcode(overloaded)
33
+ buffer = if overloaded.is_a?(MemoryBuffer) then overloaded else MemoryBuffer.new(overloaded) end
34
+
35
+ mod_ptr = FFI::MemoryPointer.new(:pointer)
36
+ msg_ptr = FFI::MemoryPointer.new(:pointer)
37
+
38
+ status = Bindings.parse_bitcode(buffer, mod_ptr, msg_ptr)
39
+
40
+ if status != 0
41
+ raise msg_ptr.get_pointer(0).get_string(0)
42
+ else
43
+ Module.new(mod_ptr.get_pointer(0))
44
+ end
45
+ end
46
+
47
+ # Create a new LLVM module.
48
+ #
49
+ # @param [FFI::Pointer, String] overloaded Pointer to existing module or name of new module.
50
+ # @param [Context, nil] context Optional context in which to create the module.
51
+ # @param [Proc] block Block to be executed inside the context of the module.
52
+ def initialize(overloaded, context = nil, &block)
53
+ @ptr =
54
+ case overloaded
55
+ when FFI::Pointer
56
+ overloaded
57
+
58
+ when String
59
+ if context
60
+ Bindings.module_create_with_name_in_context(overloaded, check_type(context, Context, 'context'))
61
+ else
62
+ Bindings.module_create_with_name(overloaded)
63
+ end
64
+ end
65
+
66
+ self.instance_exec(&block) if block
67
+ end
68
+
69
+ # @return [Context] Context in which this module exists.
70
+ def context
71
+ Context.new(Bindings.get_module_context(@ptr))
72
+ end
73
+
74
+ # Frees the resources used by LLVM for this module.
75
+ #
76
+ # @return [void]
77
+ def dispose
78
+ if @ptr
79
+ Bindings.dispose_module(@ptr)
80
+
81
+ @ptr = nil
82
+ end
83
+ end
84
+
85
+ # Print the IR of this module to standard out.
86
+ #
87
+ # @return [void]
88
+ def dump
89
+ Bindings.dump_module(@ptr)
90
+ end
91
+
92
+ # @return [FunctionCollection] Proxy object for inspecting this module's functions.
93
+ def functions
94
+ @functions ||= FunctionCollection.new(self)
95
+ end
96
+ alias :funs :functions
97
+
98
+ # @return [GlobalCollection] Proxy object for inspecting this module's global values and variables.
99
+ def globals
100
+ @globals ||= GlobalCollection.new(self)
101
+ end
102
+
103
+ # Write the module as LLVM bitcode to a file.
104
+ #
105
+ # @param [#path, #fileno, Integer, String] overloaded Where to write the bitcode.
106
+ #
107
+ # @return [Boolean] If the write was successful.
108
+ def write_bitcode(overloaded)
109
+ 0 ==
110
+ if overloaded.respond_to?(:path)
111
+ Bindings.write_bitcode_to_file(@ptr, overloaded.path)
112
+
113
+ elsif overloaded.respond_to?(:fileno)
114
+ Bindings.write_bitcode_to_fd(@ptr, overloaded.fileno, 0, 1)
115
+
116
+ elsif overloaded.is_a?(Integer)
117
+ Bindings.write_bitcode_to_fd(@ptr, overloaded, 0, 1)
118
+
119
+ elsif overloaded.is_a?(String)
120
+ Bindings.write_bitcode_to_file(@ptr, overloaded)
121
+ end
122
+ end
123
+
124
+ # Verify that the module is valid LLVM IR.
125
+ #
126
+ # @return [nil, String] Human-readable description of any invalid constructs if invalid.
127
+ def verify
128
+ do_verification(:return_status)
129
+ end
130
+
131
+ # Verify that a module is valid LLVM IR and abort the process if it isn't.
132
+ #
133
+ # @return [nil]
134
+ def verify!
135
+ do_verification(:abort_process)
136
+ end
137
+
138
+ # Helper function for {#verify} and {#verify!}
139
+ def do_verification(action)
140
+ str_ptr = FFI::MemoryPointer.new(:pointer)
141
+ status = Bindings.verify_module(@ptr, action, str_ptr)
142
+
143
+ returning(status == 1 ? str_ptr.read_string : nil) { Bindings.dispose_message(str_ptr.read_pointer) }
144
+ end
145
+ private :do_verification
146
+
147
+ # This class is used to access a module's {Function Functions}.
148
+ class FunctionCollection
149
+ include Enumerable
150
+
151
+ # @param [Module] mod Module for which this is a proxy.
152
+ def initialize(mod)
153
+ @module = mod
154
+ end
155
+
156
+ # Retreive a Function object.
157
+ #
158
+ # @param [String, Symbol, Integer] key Function identifier. Either the name of the function or its index.
159
+ #
160
+ # @return [Function]
161
+ def [](key)
162
+ case key
163
+ when String, Symbol
164
+ self.named(key)
165
+
166
+ when Integer
167
+ (1...key).inject(self.first) { |fun| if fun then self.next(fun) else break end }
168
+ end
169
+ end
170
+
171
+ # Add a Function to this module.
172
+ #
173
+ # @param [String] name Name of the module in LLVM IR.
174
+ # @param [FunctionType, Array(Type, Array<Type>)] type_info FunctionType or Values that will be passed to {FunctionType#initialize}.
175
+ # @param [Proc] block Block to be executed inside the context of the function.
176
+ #
177
+ # @return [Function]
178
+ def add(name, *type_info, &block)
179
+ Function.new(@module, name, *type_info, &block)
180
+ end
181
+
182
+ # Remove a function from the module.
183
+ #
184
+ # @param [Function] fun Function to remove.
185
+ #
186
+ # @return [void]
187
+ def delete(fun)
188
+ Bindings.delete_function(fun)
189
+ end
190
+
191
+ # An iterator for each function inside this collection.
192
+ #
193
+ # @yieldparam fun [Function]
194
+ #
195
+ # @return [Enumerator] Returns an Enumerator if no block is given.
196
+ def each
197
+ return to_enum(:each) unless block_given?
198
+
199
+ fun = self.first
200
+
201
+ while fun
202
+ yield fun
203
+ fun = self.next(fun)
204
+ end
205
+ end
206
+
207
+ # @return [Function, nil] The module's first function if one has been added.
208
+ def first
209
+ if (ptr = Bindings.get_first_function(@module)).null? then nil else Function.new(ptr) end
210
+ end
211
+
212
+ # @return [Function, nil] The module's last function if one has been added.
213
+ def last
214
+ if (ptr = Bindings.get_last_function(@module)).null? then nil else Function.new(ptr) end
215
+ end
216
+
217
+ # @param [String, Symbol] name Name of the desired function.
218
+ #
219
+ # @return [Function, nil] The function with the given name.
220
+ def named(name)
221
+ if (ptr = Bindings.get_named_function(@module, name)).null? then nil else Function.new(ptr) end
222
+ end
223
+
224
+ # @param [Function] fun Function you want the successor for.
225
+ #
226
+ # @return [Function, nil] Next function in the collection.
227
+ def next(fun)
228
+ if (ptr = Bindings.get_next_function(fun)).null? then nil else Function.new(ptr) end
229
+ end
230
+
231
+ # @param [Function] fun Function you want the predecessor for.
232
+ #
233
+ # @return [Function, nil] Previous function in the collection.
234
+ def previous(fun)
235
+ if (ptr = Bindings.get_previous_function(fun)).null? then nil else Function.new(ptr) end
236
+ end
237
+ end
238
+
239
+ # This class is used to access a module's global variables.
240
+ class GlobalCollection
241
+ include Enumerable
242
+
243
+ # @param [Module] mod Module for which this is a proxy.
244
+ def initialize(mod)
245
+ @module = mod
246
+ end
247
+
248
+ # Retreive a GlobalVariable object.
249
+ #
250
+ # @param [String, Symbol, Integer] key Global variable identifier. Either the name of the variable or its index.
251
+ #
252
+ # @return [GlobalVariable]
253
+ def [](key)
254
+ case key
255
+ when String, Symbol
256
+ self.named(key)
257
+
258
+ when Integer
259
+ (1...key).inject(self.first) { |global| if global then self.next(global) else break end }
260
+ end
261
+ end
262
+
263
+ # Add a global variable to a module.
264
+ #
265
+ # @param [Type] type Type of the global variable.
266
+ # @param [String] name Name of the global variable in LLVM IR.
267
+ def add(type, name)
268
+ GlobalVariable.new(Bindings.add_global(@module, type, name))
269
+ end
270
+
271
+ # Remove a global variable from the module.
272
+ #
273
+ # @param [GlobalVariable] global Global variable to remove.
274
+ #
275
+ # @return [void]
276
+ def delete(global)
277
+ Bindings.delete_global(global)
278
+ end
279
+
280
+ # An iterator for each global variable inside this collection.
281
+ #
282
+ # @yieldparam fun [GlobalVariable]
283
+ #
284
+ # @return [Enumerator] Returns an Enumerator if no block is given.
285
+ def each
286
+ return to_enum(:each) unless block_given?
287
+
288
+ global = self.first
289
+
290
+ while global
291
+ yield global
292
+ global = self.next(global)
293
+ end
294
+ end
295
+
296
+ # @return [GlobalVariable, nil] The module's first global variable if one has been added.
297
+ def first
298
+ if (ptr = Bindings.get_first_global(@module)).null? then nil else GlobalValue.new(ptr) end
299
+ end
300
+
301
+ # @return [GlobalVariable, nil] The module's last global variable if one has been added.
302
+ def last
303
+ if (ptr = Bindings.get_last_global(@module)).null? then nil else GlobalValue.new(ptr) end
304
+ end
305
+
306
+ # @param [String, Symbol] name Name of the desired global variable.
307
+ #
308
+ # @return [GlobalVariable, nil] The global variable with the given name.
309
+ def named(name)
310
+ if (ptr = Bindings.get_named_global(@module, name)).null? then nil else GlobalValue.new(ptr) end
311
+ end
312
+
313
+ # @param [GlobalVariable] global Global variable you want the successor for.
314
+ #
315
+ # @return [GlobalVariable, nil] global Next global variable in the collection.
316
+ def next(global)
317
+ if (ptr = Bindings.get_next_global(global)).null? then nil else GlobalValue.new(ptr) end
318
+ end
319
+
320
+ # @param [GlobalVariable] global Global variable you want the predecessor for.
321
+ #
322
+ # @return [GlobalVariable, nil] Previous global variable in the collection.
323
+ def previous(global)
324
+ if (ptr = Bindings.get_previous_global(global)).null? then nil else GlobalValue.new(ptr) end
325
+ end
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,201 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/15
4
+ # Description: This file defines the PassManager class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+
13
+ #######################
14
+ # Classes and Modules #
15
+ #######################
16
+
17
+ module RLTK::CG # :nodoc:
18
+
19
+ # A PassManager is responsible for scheduling and running optimization
20
+ # passes on modules.
21
+ class PassManager
22
+ include BindingClass
23
+
24
+ # A list of passes that are available to be added to the pass
25
+ # manager via the {PassManager#add} method.
26
+ PASSES = {
27
+ :ADCE => :agressive_dce,
28
+ :AlwaysInline => :always_inliner,
29
+ :ArgPromote => :argument_promotion,
30
+ :BasicAliasAnalysis => :basic_alias_analysis,
31
+ :CFGSimplify => :cfg_simplification,
32
+ :ConstMerge => :constant_merge,
33
+ :ConstProp => :constant_propagation,
34
+ :CorValProp => :correlated_value_propagation,
35
+ :DAE => :dead_arg_elimination,
36
+ :DSE => :dead_store_elimination,
37
+ :DemoteMemToReg => :demote_memory_to_register,
38
+ :EarlyCSE => :early_cse,
39
+ :FunctionAttrs => :function_attrs,
40
+ :FunctionInline => :function_inlining,
41
+ :GDCE => :global_dce,
42
+ :GlobalOpt => :global_optimizer,
43
+ :GVN => :gvn,
44
+ :Internalize => :internalize,
45
+ :IndVarSimplify => :ind_var_simplify,
46
+ :InstCombine => :instruction_combining,
47
+ :IPConstProp => :ip_constant_propagation,
48
+ :IPSCCP => :ipsccp,
49
+ :JumpThreading => :jump_threading,
50
+ :LICM => :licm,
51
+ :LoopDeletion => :loop_deletion,
52
+ :LoopIdiom => :loop_idiom,
53
+ :LoopRotate => :loop_rotate,
54
+ :LoopUnroll => :loop_unroll,
55
+ :LoopUnswitch => :loop_unswitch,
56
+ :LEI => :lower_expect_intrinsics,
57
+ :MemCopyOpt => :mem_cpy_opt,
58
+ :PromoteMemToReg => :promote_memory_to_register,
59
+ :PruneEH => :prune_eh,
60
+ :Reassociate => :reassociate,
61
+ :SCCP => :sccp,
62
+ :ScalarRepl => :scalar_repl_aggregates,
63
+ :SimplifyLibCalls => :simplify_lib_calls,
64
+ :StripDeadProtos => :strip_dead_prototypes,
65
+ :StripSymbols => :strip_symbols,
66
+ :TailCallElim => :tail_call_elimination,
67
+ :TBAA => :type_based_alias_analysis,
68
+ :Verifier => :verifier
69
+ }
70
+
71
+ # Creat a new pass manager. You should never have to do this as
72
+ # {ExecutionEngine ExecutionEngines} creates a PassManager whenever
73
+ # one is requested.
74
+ #
75
+ # @param [ExecutionEngine] engine ExecutionEngine this pass manager belongs to.
76
+ # @param [Module] mod Module this pass manager belongs to.
77
+ def initialize(engine, mod)
78
+ # LLVM Initialization
79
+ @ptr = Bindings.create_pass_manager
80
+ @mod = mod
81
+
82
+ Bindings.add_target_data(Bindings.get_execution_engine_target_data(engine), @ptr)
83
+
84
+ # RLTK Initialization
85
+ @enabled = Array.new
86
+ end
87
+
88
+ # Frees the resources used by LLVM for this pass manager.
89
+ #
90
+ # @return [void]
91
+ def dispose
92
+ if @ptr
93
+ self.finalize
94
+
95
+ Bindings.dispose_pass_manager(@ptr)
96
+
97
+ @ptr = nil
98
+ end
99
+ end
100
+
101
+ # Add a pass or passes to this pass manager. Passes may either be
102
+ # specified via the keys for the PASSES hash or any string that will
103
+ # be turned into a string (via the {Bindings.get_bname} method)
104
+ # appearing as a value of the PASSES hash.
105
+ #
106
+ # @see PASSES
107
+ #
108
+ # @param [Array<Symbol>] names Passes to add to the pass manager.
109
+ #
110
+ # @return [PassManager] self
111
+ def add(*names)
112
+ names.each do |name|
113
+ name = name.to_sym
114
+
115
+ if PASSES.has_key?(name)
116
+ next if @enabled.include?(name)
117
+
118
+ Bindings.send("add_#{PASSES[name]}_pass", @ptr)
119
+
120
+ @enabled << name
121
+
122
+ elsif PASSES.has_value?(bname = Bindings.get_bname(name))
123
+ next if @enabled.include?(PASSES.key(bname))
124
+
125
+ Bindings.send("add_#{bname}_pass", @ptr)
126
+
127
+ @enabled << PASSES.key(bname)
128
+
129
+ else
130
+ raise "Unknown pass: #{name}"
131
+ end
132
+ end
133
+
134
+ self
135
+ end
136
+ alias :<< :add
137
+
138
+ # @return [Array<Symbol>] List of passes that have been enabled.
139
+ def enabled
140
+ @enabled.clone
141
+ end
142
+
143
+ # @return [Boolean] Weather the pass has been enabled or not.
144
+ def enabled?(name)
145
+ @enabled.include?(name) or @enabled.include?(PASSES.key(Bindings.get_bname(name)))
146
+ end
147
+
148
+ # Run the enabled passes on the execution engine's module.
149
+ #
150
+ # @return [void]
151
+ def run
152
+ Bindings.run_pass_manager(@ptr, @mod).to_bool
153
+ end
154
+
155
+ protected
156
+ # Empty method used by {FunctionPassManager} to clean up resources.
157
+ def finalize
158
+ end
159
+ end
160
+
161
+ # A FunctionPassManager is responsible for scheduling and running optimization
162
+ # passes on individual functions inside the context of a module.
163
+ class FunctionPassManager < PassManager
164
+ # Creat a new function pass manager. You should never have to do
165
+ # this as {ExecutionEngine ExecutionEngines} creates a
166
+ # FunctionPassManager whenever one is requested.
167
+ #
168
+ # @param [ExecutionEngine] engine ExecutionEngine this pass manager belongs to.
169
+ # @param [Module] mod Module this pass manager belongs to.
170
+ def initialize(engine, mod)
171
+ # LLVM Initialization
172
+ @ptr = Bindings.create_function_pass_manager_for_module(mod)
173
+
174
+ Bindings.add_target_data(Bindings.get_execution_engine_target_data(engine), @ptr)
175
+
176
+ Bindings.initialize_function_pass_manager(@ptr).to_bool
177
+
178
+ # RLTK Initialization
179
+ @enabled = Array.new
180
+ end
181
+
182
+ # Run the enabled passes on the given function inside the execution
183
+ # engine's module.
184
+ #
185
+ # @param [Function] fun Function to optimize.
186
+ #
187
+ # @return [void]
188
+ def run(fun)
189
+ Bindings.run_function_pass_manager(@ptr, fun).to_bool
190
+ end
191
+
192
+ protected
193
+ # Called by {#dispose} to finalize any operations of the function
194
+ # pass manager.
195
+ #
196
+ # @return [void]
197
+ def finalize
198
+ Bindings.finalize_function_pass_manager(@ptr).to_bool
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,29 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/15
4
+ # Description: This file defines the Support module.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+
13
+ #######################
14
+ # Classes and Modules #
15
+ #######################
16
+
17
+ module RLTK::CG # :nodoc:
18
+
19
+ # Support functionality for LLVM code generation.
20
+ module Support
21
+ # Load a shared library into memory and make its exported symbols
22
+ # available to execution engines.
23
+ #
24
+ # @param [String] lib Path to the shared library to load.
25
+ def self.load_library(lib)
26
+ Bindings.load_library_permanently(lib).to_bool
27
+ end
28
+ end
29
+ end