From 76d66baf72ee075e7671286f513efb2ce9cc14bc Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 28 Jan 2015 20:20:55 +1100 Subject: [PATCH] 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. --- src/librustc_trans/trans/base.rs | 43 +++++++++++++++++++------------- src/test/run-pass/simd-binop.rs | 25 ++++++++++--------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 5a98bc4da36..faca4ce4103 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -623,7 +623,7 @@ pub fn compare_simd_types<'blk, 'tcx>( size: uint, op: ast::BinOp) -> ValueRef { - match t.sty { + let cmp = match t.sty { ty::ty_float(_) => { // The comparison operators for floating point vectors are challenging. // LLVM outputs a `< size x i1 >`, but if we perform a sign extension @@ -632,25 +632,32 @@ pub fn compare_simd_types<'blk, 'tcx>( cx.sess().bug("compare_simd_types: comparison operators \ not supported for floating point SIMD types") }, - ty::ty_uint(_) | ty::ty_int(_) => { - let cmp = match op.node { - ast::BiEq => llvm::IntEQ, - ast::BiNe => llvm::IntNE, - ast::BiLt => llvm::IntSLT, - ast::BiLe => llvm::IntSLE, - ast::BiGt => llvm::IntSGT, - ast::BiGe => llvm::IntSGE, - _ => cx.sess().bug("compare_simd_types: must be a comparison operator"), - }; - let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64); - // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension - // to get the correctly sized type. This will compile to a single instruction - // once the IR is converted to assembly if the SIMD instruction is supported - // by the target architecture. - SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty) + ty::ty_uint(_) => match op.node { + ast::BiEq => llvm::IntEQ, + ast::BiNe => llvm::IntNE, + ast::BiLt => llvm::IntULT, + ast::BiLe => llvm::IntULE, + ast::BiGt => llvm::IntUGT, + ast::BiGe => llvm::IntUGE, + _ => cx.sess().bug("compare_simd_types: must be a comparison operator"), + }, + ty::ty_int(_) => match op.node { + ast::BiEq => llvm::IntEQ, + ast::BiNe => llvm::IntNE, + ast::BiLt => llvm::IntSLT, + ast::BiLe => llvm::IntSLE, + ast::BiGt => llvm::IntSGT, + ast::BiGe => llvm::IntSGE, + _ => cx.sess().bug("compare_simd_types: must be a comparison operator"), }, _ => cx.sess().bug("compare_simd_types: invalid SIMD type"), - } + }; + let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64); + // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension + // to get the correctly sized type. This will compile to a single instruction + // once the IR is converted to assembly if the SIMD instruction is supported + // by the target architecture. + SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty) } // Iterates through the elements of a structural type. diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs index 482eea19823..779e507f43d 100644 --- a/src/test/run-pass/simd-binop.rs +++ b/src/test/run-pass/simd-binop.rs @@ -55,17 +55,18 @@ pub fn main() { // comparison operators - assert!(eq_u32x4(u32x4(1, 2, 3, 4) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0))); + // check !0/-1 to ensure operators are using the correct signedness. + assert!(eq_u32x4(u32x4(1, 2, 3, !0) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0))); + assert!(eq_u32x4(u32x4(1, 2, 3, !0) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0))); + assert!(eq_u32x4(u32x4(1, 2, 3, !0) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0))); + assert!(eq_u32x4(u32x4(1, 2, 3, !0) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0))); + assert!(eq_u32x4(u32x4(1, 2, 3, !0) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0))); + assert!(eq_u32x4(u32x4(1, 2, 3, !0) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, !0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, !0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, !0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, 0))); + assert!(eq_i32x4(i32x4(1, 2, 3, -1) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, 0))); } -- GitLab