about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2015-01-28 20:20:55 +1100
committerHuon Wilson <dbau.pp+github@gmail.com>2015-01-28 22:56:55 +1100
commit76d66baf72ee075e7671286f513efb2ce9cc14bc (patch)
tree9584a4c81f2cef98da6977389579b2ff424bfaae
parenta530cc9706324ad44dba464d541a807eb5afdb08 (diff)
downloadrust-76d66baf72ee075e7671286f513efb2ce9cc14bc.tar.gz
rust-76d66baf72ee075e7671286f513efb2ce9cc14bc.zip
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.
-rw-r--r--src/librustc_trans/trans/base.rs43
-rw-r--r--src/test/run-pass/simd-binop.rs25
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)));
 }