about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-12-23 13:50:28 -0800
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-12-23 13:50:28 -0800
commitbaa4379e5aa0d810304577b41dbe2b59d3030c20 (patch)
treec7ab893c9a945edb83c24f5bd988060212b498b8
parent915246314b92c06fa7b0923c25849278b76f4daa (diff)
parent82641d4c39dd547c44c2d2ef4c0c98c5bfbd8b55 (diff)
downloadrust-baa4379e5aa0d810304577b41dbe2b59d3030c20.tar.gz
rust-baa4379e5aa0d810304577b41dbe2b59d3030c20.zip
Merge pull request #4245 from JensNockert/bit-intrinsics
Add support for bitcount intrinsics Issue #2777
-rw-r--r--src/librustc/middle/trans/base.rs36
-rw-r--r--src/librustc/middle/trans/foreign.rs68
-rw-r--r--src/librustc/middle/trans/type_use.rs5
-rw-r--r--src/librustc/middle/typeck/check/mod.rs50
-rw-r--r--src/test/run-pass/intrinsics-integer.rs112
5 files changed, 270 insertions, 1 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index a65f6668cd3..d0ce66da43f 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2396,6 +2396,30 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> {
                                 T_fn(~[T_f32()], T_f32()));
     let truncf64 = decl_cdecl_fn(llmod, ~"llvm.trunc.f64",
                                 T_fn(~[T_f64()], T_f64()));
+    let ctpop8 = decl_cdecl_fn(llmod, ~"llvm.ctpop.i8",
+                                T_fn(~[T_i8()], T_i8()));
+    let ctpop16 = decl_cdecl_fn(llmod, ~"llvm.ctpop.i16",
+                                T_fn(~[T_i16()], T_i16()));
+    let ctpop32 = decl_cdecl_fn(llmod, ~"llvm.ctpop.i32",
+                                T_fn(~[T_i32()], T_i32()));
+    let ctpop64 = decl_cdecl_fn(llmod, ~"llvm.ctpop.i64",
+                                T_fn(~[T_i64()], T_i64()));
+    let ctlz8 = decl_cdecl_fn(llmod, ~"llvm.ctlz.i8",
+                                T_fn(~[T_i8(), T_i1()], T_i8()));
+    let ctlz16 = decl_cdecl_fn(llmod, ~"llvm.ctlz.i16",
+                                T_fn(~[T_i16(), T_i1()], T_i16()));
+    let ctlz32 = decl_cdecl_fn(llmod, ~"llvm.ctlz.i32",
+                                T_fn(~[T_i32(), T_i1()], T_i32()));
+    let ctlz64 = decl_cdecl_fn(llmod, ~"llvm.ctlz.i64",
+                                T_fn(~[T_i64(), T_i1()], T_i64()));
+    let cttz8 = decl_cdecl_fn(llmod, ~"llvm.cttz.i8",
+                                T_fn(~[T_i8(), T_i1()], T_i8()));
+    let cttz16 = decl_cdecl_fn(llmod, ~"llvm.cttz.i16",
+                                T_fn(~[T_i16(), T_i1()], T_i16()));
+    let cttz32 = decl_cdecl_fn(llmod, ~"llvm.cttz.i32",
+                                T_fn(~[T_i32(), T_i1()], T_i32()));
+    let cttz64 = decl_cdecl_fn(llmod, ~"llvm.cttz.i64",
+                                T_fn(~[T_i64(), T_i1()], T_i64()));
 
     let intrinsics = HashMap();
     intrinsics.insert(~"llvm.gcroot", gcroot);
@@ -2436,6 +2460,18 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> {
     intrinsics.insert(~"llvm.ceil.f64", ceilf64);
     intrinsics.insert(~"llvm.trunc.f32", truncf32);
     intrinsics.insert(~"llvm.trunc.f64", truncf64);
+    intrinsics.insert(~"llvm.ctpop.i8", ctpop8);
+    intrinsics.insert(~"llvm.ctpop.i16", ctpop16);
+    intrinsics.insert(~"llvm.ctpop.i32", ctpop32);
+    intrinsics.insert(~"llvm.ctpop.i64", ctpop64);
+    intrinsics.insert(~"llvm.ctlz.i8", ctlz8);
+    intrinsics.insert(~"llvm.ctlz.i16", ctlz16);
+    intrinsics.insert(~"llvm.ctlz.i32", ctlz32);
+    intrinsics.insert(~"llvm.ctlz.i64", ctlz64);
+    intrinsics.insert(~"llvm.cttz.i8", cttz8);
+    intrinsics.insert(~"llvm.cttz.i16", cttz16);
+    intrinsics.insert(~"llvm.cttz.i32", cttz32);
+    intrinsics.insert(~"llvm.cttz.i64", cttz64);
 
     return intrinsics;
 }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 38c3a4f7cb3..e7cdf82fd15 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -1194,6 +1194,74 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
             let truncf = ccx.intrinsics.get(~"llvm.trunc.f64");
             Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr);
         }
+        ~"ctpop8" => {
+            let x = get_param(decl, first_real_arg);
+            let ctpop = ccx.intrinsics.get(~"llvm.ctpop.i8");
+            Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr)
+        }
+        ~"ctpop16" => {
+            let x = get_param(decl, first_real_arg);
+            let ctpop = ccx.intrinsics.get(~"llvm.ctpop.i16");
+            Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr)
+        }
+        ~"ctpop32" => {
+            let x = get_param(decl, first_real_arg);
+            let ctpop = ccx.intrinsics.get(~"llvm.ctpop.i32");
+            Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr)
+        }
+        ~"ctpop64" => {
+            let x = get_param(decl, first_real_arg);
+            let ctpop = ccx.intrinsics.get(~"llvm.ctpop.i64");
+            Store(bcx, Call(bcx, ctpop, ~[x]), fcx.llretptr)
+        }
+        ~"ctlz8" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let ctlz = ccx.intrinsics.get(~"llvm.ctlz.i8");
+            Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr)
+        }
+        ~"ctlz16" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let ctlz = ccx.intrinsics.get(~"llvm.ctlz.i16");
+            Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr)
+        }
+        ~"ctlz32" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let ctlz = ccx.intrinsics.get(~"llvm.ctlz.i32");
+            Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr)
+        }
+        ~"ctlz64" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let ctlz = ccx.intrinsics.get(~"llvm.ctlz.i64");
+            Store(bcx, Call(bcx, ctlz, ~[x, y]), fcx.llretptr)
+        }
+        ~"cttz8" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let cttz = ccx.intrinsics.get(~"llvm.cttz.i8");
+            Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr)
+        }
+        ~"cttz16" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let cttz = ccx.intrinsics.get(~"llvm.cttz.i16");
+            Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr)
+        }
+        ~"cttz32" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let cttz = ccx.intrinsics.get(~"llvm.cttz.i32");
+            Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr)
+        }
+        ~"cttz64" => {
+            let x = get_param(decl, first_real_arg);
+            let y = C_bool(false);
+            let cttz = ccx.intrinsics.get(~"llvm.cttz.i64");
+            Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr)
+        }
         _ => {
             // Could we make this an enum rather than a string? does it get
             // checked earlier?
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 08ee59f5d89..7f3b78359fe 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -130,6 +130,11 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
                 ~"floorf32"| ~"floorf64"| ~"ceilf32" | ~"ceilf64" |
                 ~"truncf32"| ~"truncf64" => 0,
 
+                ~"ctpop8" | ~"ctpop16" | ~"ctpop32" | ~"ctpop64" => 0,
+
+                ~"ctlz8" | ~"ctlz16" | ~"ctlz32" | ~"ctlz64" => 0,
+                ~"cttz8" | ~"cttz16" | ~"cttz32" | ~"cttz64" => 0,
+
                 // would be cool to make these an enum instead of strings!
                 _ => fail ~"unknown intrinsic in type_use"
             };
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 8af091fdb9a..93bdfd5ccda 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3156,7 +3156,55 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
         (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
          ty::mk_f64(tcx))
      }
-      ref other => {
+     ~"ctpop8" => {
+        (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
+         ty::mk_i8(tcx))
+     }
+     ~"ctpop16" => {
+        (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
+         ty::mk_i16(tcx))
+     }
+     ~"ctpop32" => {
+        (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
+         ty::mk_i32(tcx))
+     }
+     ~"ctpop64" => {
+        (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
+         ty::mk_i64(tcx))
+     }
+     ~"ctlz8" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
+         ty::mk_i8(tcx))
+     }
+     ~"ctlz16" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
+         ty::mk_i16(tcx))
+     }
+     ~"ctlz32" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
+         ty::mk_i32(tcx))
+     }
+     ~"ctlz64" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
+         ty::mk_i64(tcx))
+     }
+     ~"cttz8" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
+         ty::mk_i8(tcx))
+     }
+     ~"cttz16" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
+         ty::mk_i16(tcx))
+     }
+     ~"cttz32" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
+         ty::mk_i32(tcx))
+     }
+     ~"cttz64" => {
+         (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
+         ty::mk_i64(tcx))
+     }
+     ref other => {
         tcx.sess.span_err(it.span, ~"unrecognized intrinsic function: `" +
                           (*other) + ~"`");
         return;
diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs
new file mode 100644
index 00000000000..588cc496b28
--- /dev/null
+++ b/src/test/run-pass/intrinsics-integer.rs
@@ -0,0 +1,112 @@
+// xfail-fast
+
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod std;
+
+#[abi = "rust-intrinsic"]  
+extern mod rusti {
+    fn ctpop8(x: i8) -> i8;
+    fn ctpop16(x: i16) -> i16;
+    fn ctpop32(x: i32) -> i32;
+    fn ctpop64(x: i64) -> i64;
+
+    fn ctlz8(x: i8) -> i8;
+    fn ctlz16(x: i16) -> i16;
+    fn ctlz32(x: i32) -> i32;
+    fn ctlz64(x: i64) -> i64;
+
+    fn cttz8(x: i8) -> i8;
+    fn cttz16(x: i16) -> i16;
+    fn cttz32(x: i32) -> i32;
+    fn cttz64(x: i64) -> i64;
+}
+
+fn main() {
+
+    use rusti::*;
+
+    assert(ctpop8(0i8) == 0i8);
+    assert(ctpop16(0i16) == 0i16);
+    assert(ctpop32(0i32) == 0i32);
+    assert(ctpop64(0i64) == 0i64);
+
+    assert(ctpop8(1i8) == 1i8);
+    assert(ctpop16(1i16) == 1i16);
+    assert(ctpop32(1i32) == 1i32);
+    assert(ctpop64(1i64) == 1i64);
+
+    assert(ctpop8(10i8) == 2i8);
+    assert(ctpop16(10i16) == 2i16);
+    assert(ctpop32(10i32) == 2i32);
+    assert(ctpop64(10i64) == 2i64);
+
+    assert(ctpop8(100i8) == 3i8);
+    assert(ctpop16(100i16) == 3i16);
+    assert(ctpop32(100i32) == 3i32);
+    assert(ctpop64(100i64) == 3i64);
+
+    assert(ctpop8(-1i8) == 8i8);
+    assert(ctpop16(-1i16) == 16i16);
+    assert(ctpop32(-1i32) == 32i32);
+    assert(ctpop64(-1i64) == 64i64);
+
+    assert(ctlz8(0i8) == 8i8);
+    assert(ctlz16(0i16) == 16i16);
+    assert(ctlz32(0i32) == 32i32);
+    assert(ctlz64(0i64) == 64i64);
+
+    assert(ctlz8(1i8) == 7i8);
+    assert(ctlz16(1i16) == 15i16);
+    assert(ctlz32(1i32) == 31i32);
+    assert(ctlz64(1i64) == 63i64);
+
+    assert(ctlz8(10i8) == 4i8);
+    assert(ctlz16(10i16) == 12i16);
+    assert(ctlz32(10i32) == 28i32);
+    assert(ctlz64(10i64) == 60i64);
+
+    assert(ctlz8(100i8) == 1i8);
+    assert(ctlz16(100i16) == 9i16);
+    assert(ctlz32(100i32) == 25i32);
+    assert(ctlz64(100i64) == 57i64);
+
+    assert(cttz8(-1i8) == 0i8);
+    assert(cttz16(-1i16) == 0i16);
+    assert(cttz32(-1i32) == 0i32);
+    assert(cttz64(-1i64) == 0i64);
+    
+    assert(cttz8(0i8) == 8i8);
+    assert(cttz16(0i16) == 16i16);
+    assert(cttz32(0i32) == 32i32);
+    assert(cttz64(0i64) == 64i64);
+
+    assert(cttz8(1i8) == 0i8);
+    assert(cttz16(1i16) == 0i16);
+    assert(cttz32(1i32) == 0i32);
+    assert(cttz64(1i64) == 0i64);
+
+    assert(cttz8(10i8) == 1i8);
+    assert(cttz16(10i16) == 1i16);
+    assert(cttz32(10i32) == 1i32);
+    assert(cttz64(10i64) == 1i64);
+
+    assert(cttz8(100i8) == 2i8);
+    assert(cttz16(100i16) == 2i16);
+    assert(cttz32(100i32) == 2i32);
+    assert(cttz64(100i64) == 2i64);
+
+    assert(cttz8(-1i8) == 0i8);
+    assert(cttz16(-1i16) == 0i16);
+    assert(cttz32(-1i32) == 0i32);
+    assert(cttz64(-1i64) == 0i64);
+
+}