Begin work on inline / builtin functions.
This commit is contained in:
		
							parent
							
								
									5e93fa1963
								
							
						
					
					
						commit
						35b9c7651a
					
				
							
								
								
									
										21
									
								
								src/chalk/builtin.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/chalk/builtin.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | module Chalk | ||||||
|  |   class BuiltinFunction | ||||||
|  |       getter param_count : Int32 | ||||||
|  | 
 | ||||||
|  |       def initialize(@param_count) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def generate!(into) | ||||||
|  |       end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   class InlineFunction | ||||||
|  |       getter param_count : Int32 | ||||||
|  |        | ||||||
|  |       def initialize(@param_count) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def generate!(codegen, params, table, target, free) | ||||||
|  |       end | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -4,9 +4,12 @@ require "./emitter.cr" | |||||||
| module Chalk | module Chalk | ||||||
|   class CodeGenerator |   class CodeGenerator | ||||||
|     include Emitter |     include Emitter | ||||||
|  | 
 | ||||||
|     RETURN_REG = 14 |     RETURN_REG = 14 | ||||||
|     STACK_REG  = 13 |     STACK_REG  = 13 | ||||||
| 
 | 
 | ||||||
|  |     property instructions : Array(Instruction) | ||||||
|  | 
 | ||||||
|     def initialize(table, @function : TreeFunction) |     def initialize(table, @function : TreeFunction) | ||||||
|       @registers = 0 |       @registers = 0 | ||||||
|       @instructions = [] of Instruction |       @instructions = [] of Instruction | ||||||
| @ -18,25 +21,12 @@ module Chalk | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def generate!(tree, table, target, free) |     def generate!(tree, function : InlineFunction, table, target, free) | ||||||
|       case tree |         start = free | ||||||
|       when TreeId |         function.generate!(self, tree.params, table, target, free) | ||||||
|         entry = table[tree.id]? |     end | ||||||
|         raise "Unknown variable" unless entry && |  | ||||||
|                                         entry.is_a?(VarEntry) |  | ||||||
|         loadr target, entry.register |  | ||||||
|       when TreeLit |  | ||||||
|         load target, tree.lit |  | ||||||
|       when TreeOp |  | ||||||
|         generate! tree.left, table, target, free |  | ||||||
|         generate! tree.right, table, free, free + 1 |  | ||||||
|         opr tree.op, target, free |  | ||||||
|       when TreeCall |  | ||||||
|         entry = table[tree.name]? |  | ||||||
|         raise "Unknown function" unless entry && |  | ||||||
|                                         entry.is_a?(FunctionEntry) |  | ||||||
|         raise "Invalid call" if tree.params.size != entry.function.params.size |  | ||||||
| 
 | 
 | ||||||
|  |     def generate!(tree, function : TreeFunction | BuiltinFunction, table, target, free) | ||||||
|         start_at = free |         start_at = free | ||||||
|         # Move I to stack |         # Move I to stack | ||||||
|         setis |         setis | ||||||
| @ -71,6 +61,28 @@ module Chalk | |||||||
|         restore (start_at - 1) unless start_at == 0 |         restore (start_at - 1) unless start_at == 0 | ||||||
|         # Get call value into target |         # Get call value into target | ||||||
|         loadr target, RETURN_REG |         loadr target, RETURN_REG | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def generate!(tree, table, target, free) | ||||||
|  |       case tree | ||||||
|  |       when TreeId | ||||||
|  |         entry = table[tree.id]? | ||||||
|  |         raise "Unknown variable" unless entry && | ||||||
|  |                                         entry.is_a?(VarEntry) | ||||||
|  |         loadr target, entry.register | ||||||
|  |       when TreeLit | ||||||
|  |         load target, tree.lit | ||||||
|  |       when TreeOp | ||||||
|  |         generate! tree.left, table, target, free | ||||||
|  |         generate! tree.right, table, free, free + 1 | ||||||
|  |         opr tree.op, target, free | ||||||
|  |       when TreeCall | ||||||
|  |         entry = table[tree.name]? | ||||||
|  |         raise "Unknown function" unless entry && | ||||||
|  |                                         entry.is_a?(FunctionEntry) | ||||||
|  |         function = entry.function | ||||||
|  |         raise "Invalid call" if tree.params.size != function.param_count | ||||||
|  |         generate! tree, function, table, target, free | ||||||
|       when TreeBlock |       when TreeBlock | ||||||
|         table = Table.new(table) |         table = Table.new(table) | ||||||
|         tree.children.each do |child| |         tree.children.each do |child| | ||||||
| @ -110,13 +122,6 @@ module Chalk | |||||||
|       return 0 |       return 0 | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def check_dead(inst) |  | ||||||
|       if inst.is_a?(LoadRegInstruction) |  | ||||||
|         return inst.from == inst.into |  | ||||||
|       end |  | ||||||
|       return false |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def generate! |     def generate! | ||||||
|       generate!(@function.block, @table, -1, @registers) |       generate!(@function.block, @table, -1, @registers) | ||||||
|       return @instructions |       return @instructions | ||||||
|  | |||||||
| @ -43,6 +43,9 @@ module Chalk | |||||||
|         table[tree.name] = FunctionEntry.new tree |         table[tree.name] = FunctionEntry.new tree | ||||||
|       end |       end | ||||||
|       @logger.debug("Done creating symbol table") |       @logger.debug("Done creating symbol table") | ||||||
|  | 
 | ||||||
|  |       table["draw"] = FunctionEntry.new InlineDrawFunction.new | ||||||
|  |       table["get_key"] = FunctionEntry.new InlineAwaitKeyFunction.new | ||||||
|       return table |       return table | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
| @ -52,6 +55,12 @@ module Chalk | |||||||
|       return generator.generate! |       return generator.generate! | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     private def create_code(tree : BuiltinFunction, table) | ||||||
|  |       instructions = [] of Instruction | ||||||
|  |       tree.generate!(instructions) | ||||||
|  |       return instructions | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     private def create_code(trees : Array(TreeFunction), table) |     private def create_code(trees : Array(TreeFunction), table) | ||||||
|       code = {} of String => Array(Instruction) |       code = {} of String => Array(Instruction) | ||||||
|       trees.each do |tree| |       trees.each do |tree| | ||||||
| @ -97,14 +106,16 @@ module Chalk | |||||||
|       while !open.empty? |       while !open.empty? | ||||||
|         first = open.first |         first = open.first | ||||||
|         open.delete first |         open.delete first | ||||||
|         done << first |  | ||||||
| 
 | 
 | ||||||
|         entry = table[first]? |         entry = table[first]? | ||||||
|         raise "Unknown function" unless entry && entry.is_a?(FunctionEntry) |         raise "Unknown function" unless entry && entry.is_a?(FunctionEntry) | ||||||
|         next unless entry.function.is_a?(TreeFunction) |         function = entry.function | ||||||
|  |         next if function.is_a?(InlineFunction) | ||||||
|  |         done << first | ||||||
|  |         next unless function.is_a?(TreeFunction) | ||||||
| 
 | 
 | ||||||
|         visitor = CallVisitor.new |         visitor = CallVisitor.new | ||||||
|         entry.function.accept(visitor) |         function.accept(visitor) | ||||||
|         open.concat(visitor.calls - done) |         open.concat(visitor.calls - done) | ||||||
|       end |       end | ||||||
|       return done |       return done | ||||||
| @ -118,14 +129,16 @@ module Chalk | |||||||
|       names.delete "main" |       names.delete "main" | ||||||
| 
 | 
 | ||||||
|       main_entry = table["main"]?.as(FunctionEntry) |       main_entry = table["main"]?.as(FunctionEntry) | ||||||
|       all_instructions.concat create_code(main_entry.function, table) |       all_instructions.concat create_code(main_entry.function.as(TreeFunction), table) | ||||||
|       main_entry.addr = 0 |       main_entry.addr = 0 | ||||||
|       all_instructions << JumpRelativeInstruction.new 0 |       all_instructions << JumpRelativeInstruction.new 0 | ||||||
| 
 | 
 | ||||||
|       names.each do |name| |       names.each do |name| | ||||||
|         entry = table[name]?.as(FunctionEntry) |         entry = table[name]?.as(FunctionEntry) | ||||||
|         entry.addr = all_instructions.size |         entry.addr = all_instructions.size | ||||||
|         all_instructions.concat create_code(entry.function, table) |         function = entry.function | ||||||
|  |         raise "Trying to compile inlined function" if function.is_a?(InlineFunction) | ||||||
|  |         all_instructions.concat create_code(function, table) | ||||||
|         all_instructions << ReturnInstruction.new |         all_instructions << ReturnInstruction.new | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,72 +1,72 @@ | |||||||
| module Chalk | module Chalk | ||||||
|   module Emitter |   module Emitter | ||||||
|     private def load(into, value) |     def load(into, value) | ||||||
|       inst = LoadInstruction.new into, value.to_i32 |       inst = LoadInstruction.new into, value.to_i32 | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def loadr(into, from) |     def loadr(into, from) | ||||||
|       inst = LoadRegInstruction.new into, from |       inst = LoadRegInstruction.new into, from | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def op(op, into, from) |     def op(op, into, from) | ||||||
|       inst = OpInstruction.new op, into, from |       inst = OpInstruction.new op, into, from | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def opr(op, into, from) |     def opr(op, into, from) | ||||||
|       inst = OpRegInstruction.new op, into, from |       inst = OpRegInstruction.new op, into, from | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def sne(l, r) |     def sne(l, r) | ||||||
|       inst = SkipNeInstruction.new l, r |       inst = SkipNeInstruction.new l, r | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def jr(o) |     def jr(o) | ||||||
|       inst = JumpRelativeInstruction.new o |       inst = JumpRelativeInstruction.new o | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def store(up_to) |     def store(up_to) | ||||||
|       inst = StoreInstruction.new up_to |       inst = StoreInstruction.new up_to | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def restore(up_to) |     def restore(up_to) | ||||||
|       inst = RestoreInstruction.new up_to |       inst = RestoreInstruction.new up_to | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def ret |     def ret | ||||||
|       inst = ReturnInstruction.new |       inst = ReturnInstruction.new | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def call(func) |     def call(func) | ||||||
|       inst = CallInstruction.new func |       inst = CallInstruction.new func | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def setis |     def setis | ||||||
|       inst = SetIStackInstruction.new |       inst = SetIStackInstruction.new | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def addi(reg) |     def addi(reg) | ||||||
|       inst = AddIRegInstruction.new reg |       inst = AddIRegInstruction.new reg | ||||||
|       @instructions << inst |       @instructions << inst | ||||||
|       return inst |       return inst | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								src/chalk/inline.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/chalk/inline.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | module Chalk | ||||||
|  |     class InlineDrawFunction < InlineFunction | ||||||
|  |         def initialize | ||||||
|  |             @param_count = 3 | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         def generate!(emitter, params, table, target, free) | ||||||
|  |             if !params[2].is_a?(TreeLit) | ||||||
|  |                 raise "Third parameter must be a constant." | ||||||
|  |             end | ||||||
|  |             emitter.generate! params[0], table, free, free + 1 | ||||||
|  |             emitter.generate! params[1], table, free + 1, free + 2 | ||||||
|  |             emitter.instructions << DrawInstruction.new free, free + 1, params[2].as(TreeLit).lit.to_i32 | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     class InlineAwaitKeyFunction < InlineFunction | ||||||
|  |         def initialize | ||||||
|  |             @param_count = 0 | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         def generate!(emitter, params, table, target, free) | ||||||
|  |             emitter.instructions << AwaitKeyInstruction.new target | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | end | ||||||
| @ -29,7 +29,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       0x6000 | (register << 8) | value |       0x6000 | (@register << 8) | @value | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -48,7 +48,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       0x8000 | (into << 8) | (from << 4) |       0x8000 | (@into << 8) | (@from << 4) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -69,7 +69,7 @@ module Chalk | |||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       case op |       case op | ||||||
|       when TokenType::OpAdd |       when TokenType::OpAdd | ||||||
|         return 0x7000 | (into << 8) | value |         return 0x7000 | (@into << 8) | @value | ||||||
|       else |       else | ||||||
|         raise "Invalid instruction" |         raise "Invalid instruction" | ||||||
|       end |       end | ||||||
| @ -107,7 +107,7 @@ module Chalk | |||||||
|       else |       else | ||||||
|         raise "Invalid instruction" |         raise "Invalid instruction" | ||||||
|       end |       end | ||||||
|       return 0x8000 | (into << 8) | (from << 4) | code |       return 0x8000 | (@into << 8) | (@from << 4) | code | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -123,7 +123,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0xf055 | (up_to << 8) |       return 0xf055 | (@up_to << 8) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -139,7 +139,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0xf065 | (up_to << 8) |       return 0xf065 | (@up_to << 8) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -167,7 +167,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0x1000 | ((offset + index) * 2 + 0x200) |       return 0x1000 | ((@offset + index) * 2 + 0x200) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -185,7 +185,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0x3000 | (left << 8) | right |       return 0x3000 | (@left << 8) | @right | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -203,7 +203,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0x4000 | (left << 8) | right |       return 0x4000 | (@left << 8) | @right | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -222,7 +222,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0x5000 | (left << 8) | (right << 4) |       return 0x5000 | (@left << 8) | (@right << 4) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -241,7 +241,7 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0x9000 | (left << 8) | (right << 4) |       return 0x9000 | (@left << 8) | (@right << 4) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| @ -282,7 +282,40 @@ module Chalk | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def to_bin(i, index) |     def to_bin(i, index) | ||||||
|       return 0xf000 | (reg << 8) | 0x1e |       return 0xf000 | (@reg << 8) | 0x1e | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   class DrawInstruction < Instruction | ||||||
|  |     property x : Int32 | ||||||
|  |     property y : Int32 | ||||||
|  |     property height : Int32 | ||||||
|  | 
 | ||||||
|  |     def initialize(@x, @y, @height) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def to_s(io) | ||||||
|  |         io << "draw R" | ||||||
|  |         x.to_s(16, io) | ||||||
|  |         io << " R" | ||||||
|  |         y.to_s(16, io) | ||||||
|  |         io << " " << height | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def to_bin(i, index) | ||||||
|  |         return 0xd000 | (@x << 8) | (@y << 4) | height | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   class AwaitKeyInstruction < Instruction | ||||||
|  |     property into : Int32 | ||||||
|  | 
 | ||||||
|  |     def initialize(@into) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def to_s(io) | ||||||
|  |         io << "getk R" | ||||||
|  |         @into.to_s(16, io) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -4,6 +4,13 @@ module Chalk | |||||||
|       @instructions = instructions.dup |       @instructions = instructions.dup | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     private def check_dead(inst) | ||||||
|  |       if inst.is_a?(LoadRegInstruction) | ||||||
|  |         return inst.from == inst.into | ||||||
|  |       end | ||||||
|  |       return false | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     private def optimize!(range) |     private def optimize!(range) | ||||||
|       offset = 0 |       offset = 0 | ||||||
|       range.each do |index| |       range.each do |index| | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ module Chalk | |||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   class FunctionEntry < Entry |   class FunctionEntry < Entry | ||||||
|     property function : TreeFunction |     property function : TreeFunction | BuiltinFunction | InlineFunction | ||||||
|     property addr : Int32 |     property addr : Int32 | ||||||
| 
 | 
 | ||||||
|     def initialize(@function, @addr = -1) |     def initialize(@function, @addr = -1) | ||||||
|  | |||||||
| @ -109,6 +109,10 @@ module Chalk | |||||||
|     def initialize(@name, @params, @block) |     def initialize(@name, @params, @block) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     def param_count | ||||||
|  |       return @params.size | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     def accept(v) |     def accept(v) | ||||||
|       v.visit(self) |       v.visit(self) | ||||||
|       @block.accept(v) |       @block.accept(v) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user