module Carbon::Core::Integer::Math
Defines math operations on almost all integers except booleans. Provides the following methods on all integer types except booleans:
-
`.+<T: Carbon::Numeric>(self, T: other): self`
-
`.-<T: Carbon::Numeric>(self, T: other): self`
-
`.*<T: Carbon::Numeric>(self, T: other): self`
-
`./<T: Carbon::Numeric>(self, T: other): self`
-
`.%<T: Carbon::Numeric>(self, T: other): self`
-
`.|<T: Carbon::Numeric>(self, T: other): self`
-
`.&<T: Carbon::Numeric>(self, T: other): self`
-
`.<<<T: Carbon::Numeric>(self, T: other): self`
-
`.>><T: Carbon::Numeric>(self, T: other): self`
-
`.^<T: Carbon::Numeric>(self, T: other): self`
-
`.==<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
-
`.===<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
-
`.<<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
-
`.><T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
-
`.<=<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
-
`.>=<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
Note that the core library never actually uses generics. Instead, all math operations are defined relative to another integer, and overloading is used to match to the right function. For example, `Int32.+(Int32, Int8)` is a different function than `Int32.+(Int32, UInt8)`; the functions use no actual generics.
@api private
Constants
- COMP_OPERATIONS
The comparison operations that can be performed. Note that for LLVM, `:<`, `:>`, `:<=`, and `:>=` are sign-dependant.
@return [<::Symbol>]
- COMP_OPERATIONS_MAP
A mapping of comparison operations to their icmp equivalents. Since most of the icmp values are sign-dependant, the keys also contain sign information.
@return [{(::Symbol, ::Symbol) => ::Symbol}]
- MATH_OPERATIONS
The math operations that can be performed. Note that for LLVM, `:/`, `:%`, and `:>>` are sign-dependant.
@return [<::Symbol>]
- OPERATIONS
Public Instance Methods
Defines a compare function. The left and right integer types are given, as well as the specific operation.
@param left [Core::Int] The left (receiver) value. @param right [Core::Int] The right value. @param op [::Symbol] The comparison operation. One of
{COMP_OPERATIONS}.
@return [void]
# File lib/carbon/core/integer/math.rb, line 108 def define_comp_function(left, right, op) function_name = left.name.call(op, [left.name, right.name]) Core.define(function: function_name) do |function| function[:return] = Carbon::Boolean define_comp_definition(left, right, op, function[:definition]) end end
Defines all of the comparison functinos. The left and right integer types are given, and the {COMP_OPERATIONS} are iterated over, providing the operator for the {#define_comp_function} method.
@param left [Core::Int] The left (receiver) value. @param right [Core::Int] The right value. @return [void]
# File lib/carbon/core/integer/math.rb, line 80 def define_comp_functions(left, right) COMP_OPERATIONS.each { |op| define_comp_function(left, right, op) } end
Defines a math function. The left and right integer types are given, as well as the specific operation.
@param left [Core::Int] The left (receiver) value. @param right [Core::Int] The right value. @param op [::Symbol] The mathmatical operation. One of
{MATH_OPERATIONS}.
@return [void]
# File lib/carbon/core/integer/math.rb, line 92 def define_math_function(left, right, op) function_name = left.name.call(op, [left.name, right.name]) Core.define(function: function_name) do |function| function[:return] = left.name define_math_definition(left, right, op, function[:definition]) end end
Defines all of the math functions. The left and right integer types are given, and the {MATH_OPERATIONS} are iterated over, providing the operator for the {#define_math_function} method.
@param left [Core::Int] The left (receiver) value. @param right [Core::Int] The right value. @return [void]
# File lib/carbon/core/integer/math.rb, line 69 def define_math_functions(left, right) MATH_OPERATIONS.each { |op| define_math_function(left, right, op) } end
Private Instance Methods
# File lib/carbon/core/integer/math.rb, line 118 def define_comp_definition(left, right, op, definition) entry = definition.add("entry").build params = definition.params params[0].name, params[1].name = %w(self other) this, other = force_same_cast(params, entry, left, right) icmp = COMP_OPERATIONS_MAP.fetch(left.sign, op) entry.ret(entry.icmp(icmp, this, other).as(Carbon::Boolean)) end
# File lib/carbon/core/integer/math.rb, line 127 def define_math_definition(left, right, op, definition) entry = definition.add("entry").build params = definition.params params[0].name, params[1].name = %w(self other) this, other = force_same_cast(params, entry, left, right) result = perform_operation(entry, [this, other], left, op) .as(this.type) return_original_size(entry, result, left, right) end
# File lib/carbon/core/integer/math.rb, line 190 def destination_size(params) sign = params[0].sign size = params.map(&:size).max Int.find(size: size, sign: sign) end
# File lib/carbon/core/integer/math.rb, line 159 def divide(entry, params, left) case left.sign when :unsigned then entry.udiv(*params) when :signed then entry.sdiv(*params) end end
# File lib/carbon/core/integer/math.rb, line 182 def force_same_cast(params, entry, left, right) dest = destination_size([left, right]) lcall, rcall = [left, right].map { |p| p.name.call(dest.cast, [p.name]) } [entry.call(lcall, params[0]).as(dest.name), entry.call(rcall, params[1]).as(dest.name)] end
# File lib/carbon/core/integer/math.rb, line 142 def perform_operation(entry, params, left, op) if OPERATIONS.key?(op) entry.public_send(OPERATIONS[op], *params) elsif op == :>> then right_shift(entry, params, left) elsif op == :/ then divide(entry, params, left) elsif op == :% then remainder(entry, params, left) else fail # Not possible. end end
# File lib/carbon/core/integer/math.rb, line 166 def remainder(entry, params, left) case left.sign when :unsigned then entry.urem(*params) when :signed then entry.srem(*params) end end
# File lib/carbon/core/integer/math.rb, line 173 def return_original_size(entry, result, left, right) size = left.size <=> right.size return entry.ret(result) if size == 0 || size == 1 type = Int.find(size: right.size, sign: left.sign) fname = type.name.call(left.cast, [type.name]) entry.call(fname, result) end
# File lib/carbon/core/integer/math.rb, line 152 def right_shift(entry, params, left) case left.sign when :unsigned then entry.lshr(*params) when :signed then entry.ashr(*params) end end