Skip to content

Commit

Permalink
Add support for byteswap intrinsics
Browse files Browse the repository at this point in the history
Adds support for the llvm.bswap.i{8,16,32} intrinsics, which swaps the
byte order from little endian to big endian, or the reverse.
  • Loading branch information
auroranockert committed Dec 27, 2012
1 parent efb8711 commit a51661e
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/librustc/middle/trans/base.rs
Expand Up @@ -2423,6 +2423,12 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> {
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 bswap16 = decl_cdecl_fn(llmod, ~"llvm.bswap.i16",
T_fn(~[T_i16()], T_i16()));
let bswap32 = decl_cdecl_fn(llmod, ~"llvm.bswap.i32",
T_fn(~[T_i32()], T_i32()));
let bswap64 = decl_cdecl_fn(llmod, ~"llvm.bswap.i64",
T_fn(~[T_i64()], T_i64()));

let intrinsics = HashMap();
intrinsics.insert(~"llvm.gcroot", gcroot);
Expand Down Expand Up @@ -2475,6 +2481,9 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> {
intrinsics.insert(~"llvm.cttz.i16", cttz16);
intrinsics.insert(~"llvm.cttz.i32", cttz32);
intrinsics.insert(~"llvm.cttz.i64", cttz64);
intrinsics.insert(~"llvm.bswap.i16", bswap16);
intrinsics.insert(~"llvm.bswap.i32", bswap32);
intrinsics.insert(~"llvm.bswap.i64", bswap64);

return intrinsics;
}
Expand Down
15 changes: 15 additions & 0 deletions src/librustc/middle/trans/foreign.rs
Expand Up @@ -1262,6 +1262,21 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let cttz = ccx.intrinsics.get(~"llvm.cttz.i64");
Store(bcx, Call(bcx, cttz, ~[x, y]), fcx.llretptr)
}
~"bswap16" => {
let x = get_param(decl, first_real_arg);
let cttz = ccx.intrinsics.get(~"llvm.bswap.i16");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr)
}
~"bswap32" => {
let x = get_param(decl, first_real_arg);
let cttz = ccx.intrinsics.get(~"llvm.bswap.i32");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr)
}
~"bswap64" => {
let x = get_param(decl, first_real_arg);
let cttz = ccx.intrinsics.get(~"llvm.bswap.i64");
Store(bcx, Call(bcx, cttz, ~[x]), fcx.llretptr)
}
_ => {
// Could we make this an enum rather than a string? does it get
// checked earlier?
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/trans/type_use.rs
Expand Up @@ -135,6 +135,8 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
~"ctlz8" | ~"ctlz16" | ~"ctlz32" | ~"ctlz64" => 0,
~"cttz8" | ~"cttz16" | ~"cttz32" | ~"cttz64" => 0,

~"bswap16" | ~"bswap32" | ~"bswap64" => 0,

// would be cool to make these an enum instead of strings!
_ => fail ~"unknown intrinsic in type_use"
};
Expand Down
12 changes: 12 additions & 0 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -3204,6 +3204,18 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
(0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
ty::mk_i64(tcx))
}
~"bswap16" => {
(0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
ty::mk_i16(tcx))
}
~"bswap32" => {
(0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
ty::mk_i32(tcx))
}
~"bswap64" => {
(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) + ~"`");
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-pass/intrinsics-integer.rs
Expand Up @@ -28,6 +28,10 @@ extern mod rusti {
fn cttz16(x: i16) -> i16;
fn cttz32(x: i32) -> i32;
fn cttz64(x: i64) -> i64;

fn bswap16(x: i16) -> i16;
fn bswap32(x: i32) -> i32;
fn bswap64(x: i64) -> i64;
}

fn main() {
Expand Down Expand Up @@ -109,4 +113,8 @@ fn main() {
assert(cttz32(-1i32) == 0i32);
assert(cttz64(-1i64) == 0i64);

assert(bswap16(0x0A0Bi16) == 0x0B0Ai16);
assert(bswap32(0x0ABBCC0Di32) == 0x0DCCBB0Ai32);
assert(bswap64(0x0122334455667708i64) == 0x0877665544332201i64);

}

0 comments on commit a51661e

Please sign in to comment.