From a51661e8c1d62f88a5b6f368f397fa6b33785973 Mon Sep 17 00:00:00 2001 From: Jens Nockert Date: Thu, 27 Dec 2012 19:07:05 +0100 Subject: [PATCH] Add support for byteswap intrinsics 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. --- src/librustc/middle/trans/base.rs | 9 +++++++++ src/librustc/middle/trans/foreign.rs | 15 +++++++++++++++ src/librustc/middle/trans/type_use.rs | 2 ++ src/librustc/middle/typeck/check/mod.rs | 12 ++++++++++++ src/test/run-pass/intrinsics-integer.rs | 8 ++++++++ 5 files changed, 46 insertions(+) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 43d81c9f92b..2b22852b646 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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); @@ -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; } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index e7cdf82fd15..1f12f65933d 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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? diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 7f3b78359fe..a75cd13a125 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -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" }; diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 93bdfd5ccda..0aeb9049ca2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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) + ~"`"); diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 588cc496b28..feddd0ab9cb 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -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() { @@ -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); + }