Skip to content

feat: support heterogeneous vector-vector numeric unification (closes #270)#271

Draft
Jaskirat-s7 wants to merge 3 commits intoarxlang:mainfrom
Jaskirat-s7:feat/vector-numeric-unification-270
Draft

feat: support heterogeneous vector-vector numeric unification (closes #270)#271
Jaskirat-s7 wants to merge 3 commits intoarxlang:mainfrom
Jaskirat-s7:feat/vector-numeric-unification-270

Conversation

@Jaskirat-s7
Copy link
Copy Markdown
Contributor

@Jaskirat-s7 Jaskirat-s7 commented Apr 1, 2026

Summary

Completes the numeric unification story started in #237 by addressing the
three remaining gaps from issue #270.

Closes #270
Related: #135


What changed

Gap 1 — Vector-vector element-type promotion (_unify_numeric_operands)

Previously, two vectors with the same lane count but different element types
raised a "Vector element type mismatch" error. Now both vectors are promoted
to the wider common type using the same logic already used for scalars:

  • vector<i16> + vector<i32> → both promoted to vector<i32> (sext/zext)
  • vector<float> + vector<double> → both promoted to vector<double> (fpext)
  • vector<i32> + vector<float> → int converted to float (sitofp/uitofp)
  • Lane-count mismatches still raise

Gap 2 — Vector compare operators

Compare operators (<, >, <=, >=, ==, !=) were previously
unhandled in the vector ops block and raised "Vector binop not implemented".
Now they emit:

  • fcmp_ordered for float vectors
  • icmp_unsigned / icmp_signed for integer vectors

Gap 3 — FMA operand unification

The FMA addend (fma_rhs) previously raised on any type mismatch with lhs.
It is now unified via _unify_numeric_operands, so
FMA(vec<float>, vec<float>, vec<double>) promotes all operands to
vector<double> before emission.


Tests

  • 30 new tests in tests/test_vector_numeric_unification.py covering all
    three gaps (int widening, FP rank, signedness semantics, vector compares,
    FMA unification)
  • Updated tests/test_vector.py to reflect promotion behavior replacing the
    old hard-error cases
  • 355 tests pass with zero regressions

Screenshots

  1. All new tests passing:
image
  1. Full suite — zero regressions:
image

BEFORE (would raise "Vector element type mismatch")

v1 = vector x4
v2 = vector x4
v1 + v2 ← RuntimeError

AFTER (promotes and computes)

v1 + v2 ← result: vector x4

@Jaskirat-s7
Copy link
Copy Markdown
Contributor Author

Jaskirat-s7 commented Apr 1, 2026

@xmnlab

here is the justification why tests/test_vector_numeric_unification.py adds 326 lines

This is a new, self-contained test module dedicated to the three behaviours
introduced by this PR. No existing test file covered heterogeneous
vector-vector promotion, vector compare ops, or FMA unification, so a
dedicated file keeps concerns separated and makes regressions easy to locate.

Line breakdown

Section Lines Purpose
Module docstring + imports ~11 Standard file header
setup_builder() helper ~13 Creates a live LLVMLiteIRVisitor with a real IRBuilder
_make_binop_visitor() helper ~29 Patches visit() to inject pre-built ir.Values without a full AST
_run_vector_binop() helper ~35 Drives a BinaryOp through the visitor and returns the result
TestVectorVectorPromotion (Gap 1) ~131 8 tests for element-type promotion
TestVectorCompare (Gap 2) ~93 5 methods → 20 parametrized cases (6 compare ops × 3 int/float/unsigned paths + 2 extra)
TestFMAUnification (Gap 3) ~37 2 tests: mixed-type FMA + same-type regression guard

####What each test class covers

TestVectorVectorPromotion — Gap 1, 8 tests

This class checks that mixed-type vector arithmetic promotes operands correctly before operating on them. The main cases: vector<i16> + vector<i32> should widen both sides to vector<i32>, and vector<float> + vector<double> should widen to vector<double>. On the IR side, unsigned widening should lower to zext, signed to sext, unsigned-to-float to uitofp, and signed-to-float to sitofp. There are also two boundary cases — one confirming that a lane-count mismatch still raises an error, and one confirming that identical element types pass through untouched.


TestVectorCompare — Gap 2, 20 cases via @pytest.mark.parametrize

Covers all six comparison operators (<, >, <=, >=, ==, !=) across three element-type categories: floats (should emit fcmp), signed ints (icmp), and unsigned ints (icmp with an unsigned predicate). Two extra cases round things out — comparing vector<float> against vector<double> to make sure promotion and comparison chain together correctly (Gap 1 + Gap 2 combined), and comparing a scalar against a vector to verify the scalar gets splatted first.


TestFMAUnification — Gap 3, 2 tests

A small but important class. The first test checks that FMA(vec<float>, vec<float>, vec<double>) promotes all three arguments to vec<double> before fusing. The second is a regression guard — it makes sure that swapping the old hard error for a promotion-based path doesn't silently break the same-type case.

Why the line count is high

  1. Douki docstrings — this project enforces structured title:/parameters:/returns: docstrings
    via the douki pre-commit hook. These are mandatory for every public function and class.
  2. Explicit ir.Constant construction — llvmlite requires type and value to be specified
    separately; there is no shorthand, so each vector constant takes 3–4 lines.
  3. Helpers are shared — the ~77 lines of helpers (setup_builder, _make_binop_visitor,
    _run_vector_binop) are reused across all 30 tests, keeping per-test logic to ~8–10 lines each.
  4. @pytest.mark.parametrize is used where sensible (compare ops) to avoid repeating 18
    near-identical test bodies.

@Jaskirat-s7
Copy link
Copy Markdown
Contributor Author

@xmnlab , PR ready for a review!

@xmnlab
Copy link
Copy Markdown
Contributor

xmnlab commented Apr 1, 2026

@Jaskirat-s7 as i mentioned on discord, I need to do a big refactoring. so probably this PR will not be included before that. let's stop the development of new PRs for now until I have the refactoring merged.

@xmnlab xmnlab marked this pull request as draft April 1, 2026 14:56
@Jaskirat-s7
Copy link
Copy Markdown
Contributor Author

Thanks for the heads-up, @xmnlab! Totally understand — no worries at all. I'll keep this branch open and rebase/adapt it on top of the refactoring once it's merged. Looking forward to seeing the new architecture.

…in (rebased from PR arxlang#239)

- Replace LLVMLiteIR with Builder as LLVMBuilder (new public API after arxlang#272)
- Replace 'from irx.system import PrintExpr' with 'from irx.astx import PrintExpr'
- Extend test_while_expr parametrize to cover Float32 and Float64
- Change UnaryOp('++') update to VariableAssignment+BinaryOp('+') for float compat
- Add test_while_float_condition: Float32 condition covers fcmp_ordered path
- Add test_binary_op_float_comparison: parametrized <=, >=, ==, != with Float32
…ation

Ported onto modular architecture from PR arxlang#271 (pre-refactoring).

Gap 1 — _unify_numeric_operands (core.py):
  Replace 'Vector element type mismatch' error with promotion logic:
  - int+int vectors: widen to max(width) using sext/zext
  - float+float vectors: widen to widest FP type using fpext
  - int+float vectors: convert int to float using sitofp/uitofp
  Lane-count mismatches still raise an error.

Gap 2 — Vector compare operators (binary_ops.py):
  Remove 'Vector binop not implemented' guards from Lt/Gt/Le/Ge/Eq/Ne
  visitors. Fix _emit_ordered_compare to detect FP via .type.element
  for vector operands so fcmp_ordered/icmp_* dispatches correctly.

Gap 3 — FMA operand unification (binary_ops.py):
  Replace FMA type mismatch error with _unify_numeric_operands calls
  for both lhs/fma_rhs and rhs/fma_rhs pairs. Add unsigned param to
  _emit_vector_mul to thread signedness through FMA path.

Tests:
  - tests/test_vector_numeric_unification.py: 30 new unit tests
    covering all three gaps (element widening, vector compares, FMA)
  - tests/test_vector.py: import names updated for new package API
  - 398 tests pass with zero regressions
@Jaskirat-s7 Jaskirat-s7 force-pushed the feat/vector-numeric-unification-270 branch from 6a0442e to 902860e Compare April 2, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support heterogeneous vector-vector numeric unification

2 participants