Permalink
Browse files

Add support for bitcount intrinsics

Adds support for the llvm.ctpop, llvm.ctlz and llvm.cttz intrinsics.
  • Loading branch information...
1 parent 76a2891 commit 82641d4c39dd547c44c2d2ef4c0c98c5bfbd8b55 @jensnockert jensnockert committed Dec 21, 2012
@@ -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;
}
@@ -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?
@@ -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"
};
@@ -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;
@@ -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);
+
+}

0 comments on commit 82641d4

Please sign in to comment.