Skip to content

Commit 76d66ba

Browse files
committed
Use unsigned comparison operators for unsigned SIMD types.
Previously comparisons of SIMD types were always signed, even unsigned comparisons, meaning 0xFFFF_FFFF_u32 < 0 inside a SIMD vector. Fixes #21719.
1 parent a530cc9 commit 76d66ba

File tree

2 files changed

+38
-30
lines changed

2 files changed

+38
-30
lines changed

src/librustc_trans/trans/base.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ pub fn compare_simd_types<'blk, 'tcx>(
623623
size: uint,
624624
op: ast::BinOp)
625625
-> ValueRef {
626-
match t.sty {
626+
let cmp = match t.sty {
627627
ty::ty_float(_) => {
628628
// The comparison operators for floating point vectors are challenging.
629629
// LLVM outputs a `< size x i1 >`, but if we perform a sign extension
@@ -632,25 +632,32 @@ pub fn compare_simd_types<'blk, 'tcx>(
632632
cx.sess().bug("compare_simd_types: comparison operators \
633633
not supported for floating point SIMD types")
634634
},
635-
ty::ty_uint(_) | ty::ty_int(_) => {
636-
let cmp = match op.node {
637-
ast::BiEq => llvm::IntEQ,
638-
ast::BiNe => llvm::IntNE,
639-
ast::BiLt => llvm::IntSLT,
640-
ast::BiLe => llvm::IntSLE,
641-
ast::BiGt => llvm::IntSGT,
642-
ast::BiGe => llvm::IntSGE,
643-
_ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
644-
};
645-
let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64);
646-
// LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
647-
// to get the correctly sized type. This will compile to a single instruction
648-
// once the IR is converted to assembly if the SIMD instruction is supported
649-
// by the target architecture.
650-
SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty)
635+
ty::ty_uint(_) => match op.node {
636+
ast::BiEq => llvm::IntEQ,
637+
ast::BiNe => llvm::IntNE,
638+
ast::BiLt => llvm::IntULT,
639+
ast::BiLe => llvm::IntULE,
640+
ast::BiGt => llvm::IntUGT,
641+
ast::BiGe => llvm::IntUGE,
642+
_ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
643+
},
644+
ty::ty_int(_) => match op.node {
645+
ast::BiEq => llvm::IntEQ,
646+
ast::BiNe => llvm::IntNE,
647+
ast::BiLt => llvm::IntSLT,
648+
ast::BiLe => llvm::IntSLE,
649+
ast::BiGt => llvm::IntSGT,
650+
ast::BiGe => llvm::IntSGE,
651+
_ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
651652
},
652653
_ => cx.sess().bug("compare_simd_types: invalid SIMD type"),
653-
}
654+
};
655+
let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64);
656+
// LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
657+
// to get the correctly sized type. This will compile to a single instruction
658+
// once the IR is converted to assembly if the SIMD instruction is supported
659+
// by the target architecture.
660+
SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty)
654661
}
655662

656663
// Iterates through the elements of a structural type.

src/test/run-pass/simd-binop.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,18 @@ pub fn main() {
5555

5656
// comparison operators
5757

58-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0)));
59-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0)));
60-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0)));
61-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0)));
62-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0)));
63-
assert!(eq_u32x4(u32x4(1, 2, 3, 4) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0)));
58+
// check !0/-1 to ensure operators are using the correct signedness.
59+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0)));
60+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0)));
61+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0)));
62+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0)));
63+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0)));
64+
assert!(eq_u32x4(u32x4(1, 2, 3, !0) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0)));
6465

65-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0)));
66-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0)));
67-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, 0)));
68-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, 0)));
69-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, !0)));
70-
assert!(eq_i32x4(i32x4(1, 2, 3, 4) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, !0)));
66+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0)));
67+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0)));
68+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, !0)));
69+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, !0)));
70+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, 0)));
71+
assert!(eq_i32x4(i32x4(1, 2, 3, -1) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, 0)));
7172
}

0 commit comments

Comments
 (0)