Copy a u128 into [u64;2]

721 Views Asked by At

How can a u128 be converted to an array of u64s. While passing a u128 to an API which takes arbitrary precision int, the API takes 3 parameters

LLVMValueRef LLVMConstIntOfArbitraryPrecision   (
  LLVMTypeRef IntTy,
  unsigned  NumWords,
  const uint64_t Words[] 
)

The first two parameters are known (IntTy = LLVMInt128Type, and NumWords = 2). The third parameter needs an array of uint64_ts. The provided u128 needs to be converted to an array of u64. From the rust doc it seems u128 can be converted to an array of bytes e.g.

let buff: [u8; 16] = u128_val.to_ne_bytes();
let Words: [u64; 2] = ?? // What to do here?

How can buff be converted to an array of Words? Also, how to deal with endianness. For simplicity, the code generator and the API will run on the machine with same endianness.

2

There are 2 best solutions below

3
Stargateur On BEST ANSWER

I would just made it by hand, this avoid any unsafe and is straight forward and care about endianness:

pub fn foo(a: u128) -> [u64; 2] {
    [(a >> 64) as u64, a as u64]
}

This translate to:

playground::foo:
    movq    %rdi, %rax
    movq    %rdx, (%rdi)
    movq    %rsi, 8(%rdi)
    retq
6
Chayim Friedman On

Nothing built in in the standard library (but see Project Safe Transmute). With bytemuck:

let words: [u64; 2] = bytemuck::cast(u128_val);

With unsafe:

let words: [u64; 2] = unsafe { std::mem::transmute::<u128, [u64; 2]>(v) };