rubyx/lib/mom/builtin/integer.rb
Torsten Rüger fa0aa30386 Move builtin wholesale to Mom
Since Builtin generates risc, just like mom instructions, it was a design mistake to put builtin into risc in the first place. Now that borders are coming more into focus, it make much more sense to have the builtin in mom.
In fact the instructions should be moved out and a seperate invocation mechanism used , so functions can be parsed, not generated (wip)
2019-08-12 12:38:29 +03:00

210 lines
7.2 KiB
Ruby

module Mom
module Builtin
# integer related kernel functions
# all these functions (return the function they implement) assume interger input
# Also the returned integer object has to be passed in to avoid having to allocate it.
#
# This means the methods will have to be renamed at some point and wrapped
module Integer
module ClassMethods
include CompileHelper
# div by 4, ie shift right by 2
# Mostly created for testing at this point, as it is short
# return new int with result
def div4(context)
compiler = compiler_for(:Integer,:div4 ,{})
compiler.add_code Div4.new("div4")
return compiler
end
class Div4 < ::Mom::Instruction
def to_risc(compiler)
builder = compiler.builder(compiler.source)
integer_tmp = builder.allocate_int
builder.build do
integer_self! << message[:receiver]
integer_self.reduce_int
integer_1! << 2
integer_self.op :>> , integer_1
integer_tmp[Parfait::Integer.integer_index] << integer_self
message[:return_value] << integer_tmp
end
return compiler
end
end
# implemented by the comparison
def >( context )
comparison( :> )
end
# implemented by the comparison
def <( context )
comparison( :< )
end
# implemented by the comparison
def <=( context )
comparison( :<= )
end
# implemented by the comparison
def >=( context )
comparison( :>= )
end
# all (four) comparison operation are quite similar and implemented here
# - reduce the ints (assume int as input)
# - subtract the fixnums
# - check for minus ( < and > )
# - also check for zero (<= and >=)
# - load true or false object into return, depending on check
# - return
def comparison( operator )
compiler = compiler_for(:Integer, operator ,{other: :Integer })
compiler.add_code Comparison.new("comparison" , operator)
return compiler
end
class Comparison < ::Mom::Instruction
attr_reader :operator
def initialize(name , operator)
super(name)
@operator = operator
end
def to_risc(compiler)
builder = compiler.builder(compiler.source)
operator = @operator # make accessible in block
builder.build do
integer! << message[:receiver]
integer.reduce_int
integer_reg! << message[:arguments]
integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0
integer_reg.reduce_int
swap_names(:integer , :integer_reg) if(operator.to_s.start_with?('<') )
integer.op :- , integer_reg
if_minus false_label
if_zero( false_label ) if operator.to_s.length == 1
object! << Parfait.object_space.true_object
branch merge_label
add_code false_label
object << Parfait.object_space.false_object
add_code merge_label
message[:return_value] << object
end
return compiler
end
end
# implemented all known binary operators that map straight to machine codes
# this function (similar to comparison):
# - unpacks the intergers to fixnum
# - applies the operator (at a risc level)
# - gets a new integer and stores the result
# - returns the new int
def operator_method( op_sym )
compiler = compiler_for(:Integer, op_sym ,{other: :Integer })
compiler.add_code OperatorInstruction.new("operator" , op_sym)
return compiler
end
class OperatorInstruction < ::Mom::Instruction
attr_reader :operator
def initialize(name , operator)
super(name)
@operator = operator
end
def to_risc(compiler)
builder = compiler.builder(compiler.source)
integer_tmp = builder.allocate_int
operator = @operator # make accessible in block
builder.build do
integer! << message[:receiver]
integer.reduce_int
integer_reg! << message[:arguments]
integer_reg << integer_reg[Parfait::NamedList.type_length + 0] #"other" is at index 0
integer_reg.reduce_int
integer.op operator , integer_reg
integer_tmp[Parfait::Integer.integer_index] << integer
message[:return_value] << integer_tmp
end
return compiler
end
end
# as the name suggests, this devides the integer (self) by ten
#
# This version is lifted from some arm assembler tricks and is _much_
# faster than the general div versions. I think it was about three
# times less instructions. Useful for itos
#
# In fact it is possible to generate specific div function for any given
# integer and some are even more faster (as eg div4).
def div10( context )
compiler = compiler_for(:Integer,:div10 ,{})
compiler.add_code Div10.new("div10")
return compiler
end
class Div10 < ::Mom::Instruction
def to_risc(compiler)
s = "div_10 "
builder = compiler.builder(compiler.source)
integer_tmp = builder.allocate_int
builder.build do
integer_self! << message[:receiver]
integer_self.reduce_int
integer_1! << integer_self
integer_reg! << integer_self
integer_const! << 1
integer_1.op :>> , integer_const
integer_const << 2
integer_reg.op :>> , integer_const
integer_reg.op :+ , integer_1
integer_const << 4
integer_1 << integer_reg
integer_reg.op :>> , integer_1
integer_reg.op :+ , integer_1
integer_const << 8
integer_1 << integer_reg
integer_1.op :>> , integer_const
integer_reg.op :+ , integer_1
integer_const << 16
integer_1 << integer_reg
integer_1.op :>> , integer_const
integer_reg.op :+ , integer_1
integer_const << 3
integer_reg.op :>> , integer_const
integer_const << 10
integer_1 << integer_reg
integer_1.op :* , integer_const
integer_self.op :- , integer_1
integer_1 << integer_self
integer_const << 6
integer_1.op :+ , integer_const
integer_const << 4
integer_1.op :>> , integer_const
integer_reg.op :+ , integer_1
integer_tmp[Parfait::Integer.integer_index] << integer_reg
message[:return_value] << integer_tmp
end
return compiler
end
end
end
extend ClassMethods
end
end
end