module Carbon::Core::Integer::Math

Defines math operations on almost all integers except booleans. Provides the following methods on all integer types except booleans:

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

define_comp_function(left, right, op) click to toggle source

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
define_comp_functions(left, right) click to toggle source

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
define_math_function(left, right, op) click to toggle source

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
define_math_functions(left, right) click to toggle source

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

define_comp_definition(left, right, op, definition) click to toggle source
# 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
define_math_definition(left, right, op, definition) click to toggle source
# 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
destination_size(params) click to toggle source
# 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
divide(entry, params, left) click to toggle source
# 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
force_same_cast(params, entry, left, right) click to toggle source
# 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
perform_operation(entry, params, left, op) click to toggle source
# 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
remainder(entry, params, left) click to toggle source
# 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
return_original_size(entry, result, left, right) click to toggle source
# 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
right_shift(entry, params, left) click to toggle source
# 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