Add support for bitcount intrinsics

Adds support for the llvm.ctpop, llvm.ctlz and llvm.cttz intrinsics.
This commit is contained in:
Jens Nockert 2012-12-21 19:30:33 +01:00
parent 76a2891feb
commit 82641d4c39
5 changed files with 270 additions and 1 deletions

View File

@ -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;
}

View File

@ -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?

View File

@ -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"
};

View File

@ -3156,6 +3156,54 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
(0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
ty::mk_f64(tcx))
}
~"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) + ~"`");

View File

@ -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);
}