Class: Citrus::Generator
- Inherits:
-
Object
- Object
- Citrus::Generator
- Defined in:
- lib/citrus/compiler/generator.rb
Instance Attribute Summary collapse
-
#basic_block ⇒ Object
readonly
Returns the value of attribute basic_block.
-
#builder ⇒ Object
readonly
Returns the value of attribute builder.
-
#locals ⇒ Object
readonly
Returns the value of attribute locals.
-
#module ⇒ Object
readonly
Returns the value of attribute module.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
Instance Method Summary collapse
- #array(values) ⇒ Object
- #assign(name, value) ⇒ Object
- #assign_global(name, value) ⇒ Object
- #assign_index(name, index, value) ⇒ Object
- #begin(rblock, elblock, enblock) ⇒ Object
- #block ⇒ Object
- #bool(value) ⇒ Object
- #break(block) ⇒ Object
- #call(func, *args) ⇒ Object
- #case(val, cases, elseblock) ⇒ Object
- #compare(op, lval, rval) ⇒ Object
- #condition(cond, thenblock, elseblock, elsifs = []) ⇒ Object
- #declare(name, args, ret, varargs = false) ⇒ Object
- #equate(op, lval, rval) ⇒ Object
- #finish ⇒ Object
- #float(value) ⇒ Object
- #for(var, indices) {|generator| ... } ⇒ Object
- #function(name, args) ⇒ Object
-
#initialize(mod, function, parent = nil) ⇒ Generator
constructor
A new instance of Generator.
- #load(name) ⇒ Object
- #load_global(name) ⇒ Object
- #load_index(ary, index) ⇒ Object
- #negate(value) ⇒ Object
- #not(value) ⇒ Object
- #number(value) ⇒ Object
-
#preploop(looptype = nil, *args) ⇒ Object
Needs to be called before running any loop command (specifically before calculating the conditions for the loop).
- #range(first, last, full) ⇒ Object
- #resolve_conflict(name, *gens) ⇒ Object
- #resolve_conflicts(*gens) ⇒ Object
- #return(value = self.number(0)) ⇒ Object
- #string(value) ⇒ Object
- #unwind ⇒ Object
- #vars ⇒ Object
- #while(cond) {|generator| ... } ⇒ Object
Constructor Details
#initialize(mod, function, parent = nil) ⇒ Generator
Returns a new instance of Generator.
10 11 12 13 14 15 16 17 18 |
# File 'lib/citrus/compiler/generator.rb', line 10 def initialize(mod, function, parent=nil) @module = mod @locals = {} @parent = parent @function = function @basic_block = @function.basic_blocks.append @builder = LLVM::Builder.create @builder.position_at_end(@basic_block) end |
Instance Attribute Details
#basic_block ⇒ Object (readonly)
Returns the value of attribute basic_block.
4 5 6 |
# File 'lib/citrus/compiler/generator.rb', line 4 def basic_block @basic_block end |
#builder ⇒ Object (readonly)
Returns the value of attribute builder.
6 7 8 |
# File 'lib/citrus/compiler/generator.rb', line 6 def builder @builder end |
#locals ⇒ Object (readonly)
Returns the value of attribute locals.
7 8 9 |
# File 'lib/citrus/compiler/generator.rb', line 7 def locals @locals end |
#module ⇒ Object (readonly)
Returns the value of attribute module.
5 6 7 |
# File 'lib/citrus/compiler/generator.rb', line 5 def module @module end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
8 9 10 |
# File 'lib/citrus/compiler/generator.rb', line 8 def parent @parent end |
Instance Method Details
#array(values) ⇒ Object
20 21 22 |
# File 'lib/citrus/compiler/generator.rb', line 20 def array(values) return Array.create(values, @builder) end |
#assign(name, value) ⇒ Object
107 108 109 110 111 112 113 |
# File 'lib/citrus/compiler/generator.rb', line 107 def assign(name, value) unless @locals.has_key?(name) @locals[name] = Variable.new(value, @builder) else @locals[name].assign(value, @builder) end end |
#assign_global(name, value) ⇒ Object
115 116 117 118 119 120 121 |
# File 'lib/citrus/compiler/generator.rb', line 115 def assign_global(name, value) unless GlobalVariables.named(name) GlobalVariables.add(name, value, @builder) else GlobalVariables.named(name).assign(value, @builder) end end |
#assign_index(name, index, value) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/citrus/compiler/generator.rb', line 123 def assign_index(name, index, value) ary = self.load(name) length = @builder.alloca(INT) @builder.store(ary.length, length) tb = self.block do |gb| gb.builder.store(gb.equate(:+, index, gb.number(1)), length) end cond = gb.compare(:<=, ary.length, index) self.condition(cond, tb.bb, self.block.bb) ary.length = @builder.load(length) ptr = @builder.gep(ary.pointer, [INT.from_i(0), index]) @builder.store(value, ptr) end |
#begin(rblock, elblock, enblock) ⇒ Object
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/citrus/compiler/generator.rb', line 249 def begin(rblock, elblock, enblock) cond = self.compare(:==, self.load_global(STS_GLOBAL), self.number(1)) @builder.cond(cond, rblock.bb, elblock.bb) @basic_block = self.block.bb @builder.position_before(rblock.bb.instructions.first) self.assign_global(STS_GLOBAL, self.number(0)) @builder.position_at_end(rblock.bb) @builder.br(enblock.bb) @builder.position_at_end(elblock.bb) @builder.br(enblock.bb) @builder.position_before(enblock.bb.instructions.first) self.resolve_conflicts(rblock, elblock) @builder.position_at_end(enblock.bb) @builder.br(@basic_block) @builder.position_at_end(@basic_block) @locals.merge!(enblock.locals) end |
#block ⇒ Object
206 207 208 |
# File 'lib/citrus/compiler/generator.rb', line 206 def block return Block.new(@module, @function, self) { |g| yield g if block_given? } end |
#bool(value) ⇒ Object
56 57 58 |
# File 'lib/citrus/compiler/generator.rb', line 56 def bool(value) BOOL.from_i(value ? 1 : 0) end |
#break(block) ⇒ Object
318 319 320 321 322 |
# File 'lib/citrus/compiler/generator.rb', line 318 def break(block) unless @finished @builder.br(block) end end |
#call(func, *args) ⇒ Object
68 69 70 71 72 73 74 75 76 |
# File 'lib/citrus/compiler/generator.rb', line 68 def call(func, *args) begin GlobalFunctions.named(func).call(args, @builder) rescue NoMethodError # for C methods f = @module.functions.named(func) raise NoMethodError if f.nil? @builder.call(f, *args) end end |
#case(val, cases, elseblock) ⇒ Object
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/citrus/compiler/generator.rb', line 232 def case(val, cases, elseblock) ncases = {} for pair in cases ncases[pair[0]] = pair[1].bb end switch = @builder.switch(val, elseblock.bb, ncases) @basic_block = self.block.bb @builder.position_at_end(elseblock.bb) @builder.br(@basic_block) ncases.each_value do |c| @builder.position_at_end(c[1]) @builder.br(@basic_block) end @builder.position_at_end(@basic_block) self.resolve_conflicts(elseblock, *cases.keys) end |
#compare(op, lval, rval) ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/citrus/compiler/generator.rb', line 137 def compare(op, lval, rval) case op.to_s when *CMP_MAPPING.keys if LLVM::Type(lval) == FLOAT.type || LLVM::Type(rval) == FLOAT.type symbol = "o#{CMP_MAPPING[op.to_s].to_s}".to_sym if LLVM::Type(lval) != FLOAT.type lval = @builder.ui2fp(lval, FLOAT.type) elsif LLVM::Type(rval) != FLOAT.type rval = @builder.ui2fp(rval, FLOAT.type) end @builder.fcmp(symbol, lval, rval) else symbol = CMP_MAPPING[op.to_s] symbol = "s#{symbol.to_s}".to_sym unless symbol == :eq || symbol == :ne @builder.icmp(symbol, lval, rval) end when "&&", "and" @builder.and(lval, rval) when "||", "or" @builder.or(lval, rval) end end |
#condition(cond, thenblock, elseblock, elsifs = []) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/citrus/compiler/generator.rb', line 210 def condition(cond, thenblock, elseblock, elsifs=[]) @basic_block = self.block.bb eb = elsifs.empty? ? elseblock : self.block efbs = [] @builder.cond(cond, thenblock.bb, eb.bb) for i in 0...elsifs.length efbs += eb @builder.position_at_end(eb.bb) neb = i+1 == elsifs.length ? elseblock : self.block @builder.cond(elsifs[i][0], elsifs[i][1].bb, eb.bb) @builder.position_at_end(elsifs[i][1].bb) @builder.br(@basic_block) eb = neb end @builder.position_at_end(thenblock.bb) @builder.br(@basic_block) @builder.position_at_end(elseblock.bb) @builder.br(@basic_block) @builder.position_at_end(@basic_block) self.resolve_conflicts(thenblock, elseblock, *efbs) end |
#declare(name, args, ret, varargs = false) ⇒ Object
200 201 202 203 204 |
# File 'lib/citrus/compiler/generator.rb', line 200 def declare(name, args, ret, varargs = false) rtype = DEC_MAPPING[ret.to_sym] atypes = args.map{|arg| DEC_MAPPING[arg.to_sym]} @module.functions.add(name.to_s, LLVM::Type.function(atypes, rtype, :varargs => varargs)) end |
#equate(op, lval, rval) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/citrus/compiler/generator.rb', line 160 def equate(op, lval, rval) if LLVM::Type(lval) == FLOAT.type || LLVM::Type(rval) == FLOAT.type symbol = "f#{EQU_MAPPING[op.to_s].to_s}".to_sym if LLVM::Type(lval) != FLOAT.type lval = @builder.ui2fp(lval, FLOAT.type) elsif LLVM::Type(rval) != FLOAT.type rval = @builder.ui2fp(rval, FLOAT.type) end @builder.send(symbol, lval, rval) else symbol = EQU_MAPPING[op.to_s] symbol = :sdiv if symbol == :div @builder.send(symbol, lval, rval) end end |
#finish ⇒ Object
324 325 326 |
# File 'lib/citrus/compiler/generator.rb', line 324 def finish @builder.dispose end |
#float(value) ⇒ Object
48 49 50 |
# File 'lib/citrus/compiler/generator.rb', line 48 def float(value) FLOAT.from_f(value) end |
#for(var, indices) {|generator| ... } ⇒ Object
296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/citrus/compiler/generator.rb', line 296 def for(var, indices) generator = Generator.new(@module, @function, self) generator.assign(var, generator.load_index(indices, generator.load("for"))) yield generator generator.assign("for", generator.equate(:+, generator.load("for"), generator.number(1))) generator.break(@basic_block) generator.finish @builder.position_at_end(@basic_block) self.resolve_conflict("for", generator, self) @basic_block = self.block.bb cond = self.compare(:<, self.load("for"), indices.length) @builder.cond(cond, generator.basic_block, @basic_block) @builder.position_at_end(@basic_block) end |
#function(name, args) ⇒ Object
196 197 198 |
# File 'lib/citrus/compiler/generator.rb', line 196 def function(name, args) return GlobalFunctions.add(name, args) { |g| yield g } end |
#load(name) ⇒ Object
180 181 182 183 184 185 186 |
# File 'lib/citrus/compiler/generator.rb', line 180 def load(name) if @locals.has_key?(name) @locals[name].value(@builder) else self.vars[name].value(@builder) end end |
#load_global(name) ⇒ Object
188 189 190 |
# File 'lib/citrus/compiler/generator.rb', line 188 def load_global(name) GlobalVariables.named(name).value(@builder) end |
#load_index(ary, index) ⇒ Object
192 193 194 |
# File 'lib/citrus/compiler/generator.rb', line 192 def load_index(ary, index) @builder.load(@builder.gep(ary.pointer, [INT.from_i(0), index])) end |
#negate(value) ⇒ Object
60 61 62 |
# File 'lib/citrus/compiler/generator.rb', line 60 def negate(value) @builder.neg(value) end |
#not(value) ⇒ Object
64 65 66 |
# File 'lib/citrus/compiler/generator.rb', line 64 def not(value) @builder.not(value) end |
#number(value) ⇒ Object
52 53 54 |
# File 'lib/citrus/compiler/generator.rb', line 52 def number(value) INT.from_i(value) end |
#preploop(looptype = nil, *args) ⇒ Object
Needs to be called before running any loop command (specifically before calculating the conditions for the loop)
273 274 275 276 277 278 279 280 281 |
# File 'lib/citrus/compiler/generator.rb', line 273 def preploop(looptype=nil, *args) if looptype == :for self.assign("for", INT.from_i(0)) self.assign(args[0], self.load_index(args[1], self.number(0))) end @basic_block = self.block.bb @builder.br(@basic_block) @builder.position_at_end(@basic_block) end |
#range(first, last, full) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/citrus/compiler/generator.rb', line 24 def range(first, last, full) ival = nil ary = @builder.alloca(LLVM::Array(INT, 0)) iteration = @builder.alloca(INT) @builder.store(first, iteration) index = @builder.alloca(INT) @builder.store(INT.from_i(0), index) self.preploop(:while) self.while(self.compare(full ? :<= : :<, @builder.load(iteration), last)) do |gw| ival = gw.builder.load(index) val = gw.builder.load(iteration) ptr = gw.builder.gep(ary, [INT.from_i(0), ival]) gw.builder.store(val, ptr) gw.builder.store(gw.equate(:+, val, gw.number(1)), iteration) gw.builder.store(gw.equate(:+, ival, gw.number(1)), index) end ival = @builder.load(index) return Array.new(ary, ival) end |
#resolve_conflict(name, *gens) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/citrus/compiler/generator.rb', line 87 def resolve_conflict(name, *gens) ty = INT nodes = {} gens.select{|g| g.locals.has_key?(name)}.each do |g| bb = g.basic_block var = g.locals[name] builder = LLVM::Builder.create if bb == @builder.insert_block && !nodes.has_key?(bb.previous) builder.position_before(bb.previous.instructions.last) nodes[bb.previous] = var.value(builder) else builder.position_before(bb.instructions.last) nodes[bb] = var.value(builder) end builder.dispose end ptr = @builder.phi(ty, nodes) self.assign(name, ptr) end |
#resolve_conflicts(*gens) ⇒ Object
78 79 80 81 82 83 84 85 |
# File 'lib/citrus/compiler/generator.rb', line 78 def resolve_conflicts(*gens) locals = [] gens.each{|g| locals += g.locals.keys} stat = locals.inject(Hash.new(0)){|h, e| h[e]+=1; h} stat.select{|k, v| v > 1}.collect{|a| a[0]}.each do |k| resolve_conflict(k, *gens) end end |
#return(value = self.number(0)) ⇒ Object
311 312 313 314 315 316 |
# File 'lib/citrus/compiler/generator.rb', line 311 def return(value=self.number(0)) unless @finished @function.return(value, @builder) @finished = true end end |
#string(value) ⇒ Object
44 45 46 |
# File 'lib/citrus/compiler/generator.rb', line 44 def string(value) ptr = GlobalStrings.pointer(value) end |
#unwind ⇒ Object
267 268 269 |
# File 'lib/citrus/compiler/generator.rb', line 267 def unwind @builder.unwind end |
#vars ⇒ Object
176 177 178 |
# File 'lib/citrus/compiler/generator.rb', line 176 def vars return @parent.nil? ? @locals : @locals.merge(@parent.vars) end |
#while(cond) {|generator| ... } ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/citrus/compiler/generator.rb', line 283 def while(cond) @builder.position_before(@basic_block.instructions.first) generator = Generator.new(@module, @function, self) yield generator generator.break(@basic_block) generator.finish self.resolve_conflicts(generator, self) @builder.position_at_end(@basic_block) @basic_block = self.block.bb @builder.cond(cond, generator.basic_block, @basic_block) @builder.position_at_end(@basic_block) end |