Module: Kumi::IR::Vec::Passes::Support::AlgebraicIdentities

Defined in:
lib/kumi/ir/vec/passes/support/algebraic_identities.rb

Overview

Algebraic identities that reduce a binary ‘map` (`a OP b`) to one of its operands. Applied ONLY when it is exact for the dtype under IEEE 754 and keeps the result dtype/axes (so no promotion is dropped):

x * 1, 1 * x, x / 1, x - 0   safe for every numeric dtype
x + 0, 0 + x, x * 0, 0 * x   integer only
  (float x + 0.0 drops a -0.0 sign; float x * 0.0 is NaN when x is
   Infinity/NaN — both would change the result)

Pure: given the rewritten operand registers, their known constant values, and a reg=>instruction table for dtype/axes, it returns the surviving register or nil. The caller drops the map and rewrites uses.

Class Method Summary collapse

Class Method Details

.keep(reg, instr, defs) ⇒ Object

The surviving operand replaces the map only when it carries the same dtype (never erase a promotion) and the same axes.



50
51
52
53
54
55
56
57
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 50

def keep(reg, instr, defs)
  src = defs[reg]
  return nil unless src
  return nil unless numeric_kind(src.dtype) == numeric_kind(instr.dtype)
  return nil unless Array(src.axes) == Array(instr.axes)

  reg
end

.numeric_kind(dtype) ⇒ Object



62
63
64
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 62

def numeric_kind(dtype)
  dtype.respond_to?(:kind) ? dtype.kind : dtype
end

.one?(value) ⇒ Boolean

Returns:

  • (Boolean)


59
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 59

def one?(value)  = [1, 1.0].include?(value)

.survivor(instr, inputs, constants, defs) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 23

def survivor(instr, inputs, constants, defs)
  return nil unless inputs.size == 2

  left, right = inputs
  left_const = constants[left]
  right_const = constants[right]
  integer = numeric_kind(instr.dtype) == :integer

  case instr.attributes[:fn]
  when :"core.mul:numeric"
    return keep(right, instr, defs) if one?(left_const)              # 1 * x
    return keep(left, instr, defs)  if one?(right_const)             # x * 1
    return keep(left, instr, defs)  if integer && zero?(left_const)  # 0 * x -> zero
    return keep(right, instr, defs) if integer && zero?(right_const) # x * 0 -> zero
  when :"core.div"
    return keep(left, instr, defs) if one?(right_const) # x / 1
  when :"core.add"
    return keep(right, instr, defs) if integer && zero?(left_const)  # 0 + x
    return keep(left, instr, defs)  if integer && zero?(right_const) # x + 0
  when :"core.sub"
    return keep(left, instr, defs) if zero?(right_const) # x - 0
  end
  nil
end

.zero?(value) ⇒ Boolean

Returns:

  • (Boolean)


60
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 60

def zero?(value) = [0, 0.0].include?(value)