fix: promote mismatched comparison operands before emitting cmp (issue 0146)
A comparison with int-vs-float (or two float widths) operands emitted cmp on the raw operands with no promotion, unlike the arithmetic arms -- producing a mixed-type compare the LLVM verifier rejects / mis-evaluates. lowerBinaryOp now coerces each operand to the promoted common type (from arithResultType) via coerceToType (SIToFP / FPExt) for the ordering/equality arms when the promoted type is a float, so LLVM gets a well-typed fcmp. Regression: examples/0189-types-int-float-compare-promote.sx
This commit is contained in:
@@ -2761,6 +2761,34 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
|
||||
}
|
||||
}
|
||||
|
||||
// Comparison operand promotion. Arithmetic arms below carry the promoted
|
||||
// common type `ty` on the result op, so the LLVM emitter re-matches the
|
||||
// operands against it (`matchBinOpTypes`). Comparisons carry `.bool`
|
||||
// instead, so `emitCmp`/`emitCmpOrdered` only see the raw operand LLVM
|
||||
// types — and those only reconcile int↔int width (SExt/ZExt). A mixed
|
||||
// int-vs-float compare (`xx i < t`, i:i32 t:f32) or a two-float-width
|
||||
// compare (`f64 >= f32`) reaches the emitter with mismatched operands and
|
||||
// fails LLVM verification (issue 0146). Coerce each operand up to the
|
||||
// promoted common type HERE — `coerceToType` emits the SIToFP / FPExt /
|
||||
// width-ext — so the operands are already type-equal when the cmp is built.
|
||||
// Restricted to float `ty`: an int↔int compare is handled by the emitter,
|
||||
// and a non-numeric `ty` (struct/string/enum) has its own cmp path.
|
||||
switch (bop.op) {
|
||||
.eq, .neq, .lt, .lte, .gt, .gte => {
|
||||
if (Lowering.isFloat(ty)) {
|
||||
const lhs_ir = self.builder.getRefType(lhs);
|
||||
if (lhs_ir != ty and (Lowering.isFloat(lhs_ir) or self.isIntEx(lhs_ir))) {
|
||||
lhs = self.coerceToType(lhs, lhs_ir, ty);
|
||||
}
|
||||
const rhs_ir = self.builder.getRefType(rhs);
|
||||
if (rhs_ir != ty and (Lowering.isFloat(rhs_ir) or self.isIntEx(rhs_ir))) {
|
||||
rhs = self.coerceToType(rhs, rhs_ir, ty);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
return switch (bop.op) {
|
||||
.add => self.builder.add(lhs, rhs, ty),
|
||||
.sub => self.builder.sub(lhs, rhs, ty),
|
||||
|
||||
Reference in New Issue
Block a user