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
-
.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.
- .numeric_kind(dtype) ⇒ Object
- .one?(value) ⇒ Boolean
- .survivor(instr, inputs, constants, defs) ⇒ Object
- .zero?(value) ⇒ Boolean
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
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
60 |
# File 'lib/kumi/ir/vec/passes/support/algebraic_identities.rb', line 60 def zero?(value) = [0, 0.0].include?(value) |