feat: support heterogeneous vector-vector numeric unification (closes #270)#271
feat: support heterogeneous vector-vector numeric unification (closes #270)#271Jaskirat-s7 wants to merge 3 commits intoarxlang:mainfrom
Conversation
here is the justification why
|
| 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
- Douki docstrings — this project enforces structured
title:/parameters:/returns:docstrings
via thedoukipre-commit hook. These are mandatory for every public function and class. - Explicit
ir.Constantconstruction — llvmlite requires type and value to be specified
separately; there is no shorthand, so each vector constant takes 3–4 lines. - 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. @pytest.mark.parametrizeis used where sensible (compare ops) to avoid repeating 18
near-identical test bodies.
|
@xmnlab , PR ready for a review! |
|
@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. |
|
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
6a0442e to
902860e
Compare
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 promotedto the wider common type using the same logic already used for scalars:
vector<i16>+vector<i32>→ both promoted tovector<i32>(sext/zext)vector<float>+vector<double>→ both promoted tovector<double>(fpext)vector<i32>+vector<float>→ int converted to float (sitofp/uitofp)Gap 2 — Vector compare operators
Compare operators (
<,>,<=,>=,==,!=) were previouslyunhandled in the vector ops block and raised
"Vector binop not implemented".Now they emit:
fcmp_orderedfor float vectorsicmp_unsigned/icmp_signedfor integer vectorsGap 3 — FMA operand unification
The FMA addend (
fma_rhs) previously raised on any type mismatch withlhs.It is now unified via
_unify_numeric_operands, soFMA(vec<float>, vec<float>, vec<double>)promotes all operands tovector<double>before emission.Tests
tests/test_vector_numeric_unification.pycovering allthree gaps (int widening, FP rank, signedness semantics, vector compares,
FMA unification)
tests/test_vector.pyto reflect promotion behavior replacing theold hard-error cases
Screenshots
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