#![allow(unused_must_use)]
extern crate gcc;
use std::mem;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
type Limb = usize;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("bases_table.rs");
let mut f = File::create(&dest_path).unwrap();
gen_bases(&mut f);
if let Ok(_) = env::var("CARGO_FEATURE_ASM") {
compile_asm();
}
}
fn compile_asm() {
if let Ok(target) = env::var("TARGET") {
if let Ok(host) = env::var("HOST") {
if host != target { panic!("Cross compiling not currently supported"); }
if (target.contains("x86-64") || target.contains("x86_64")) && target.contains("linux") {
let asm_srcs = &[
"src/ll/asm/addsub_n.S",
"src/ll/asm/mul_1.S",
"src/ll/asm/addmul_1.S",
];
gcc::compile_library("libasm.a", asm_srcs);
println!("cargo:rustc-cfg=asm");
}
}
}
}
fn gen_bases(f: &mut File) {
let limb_size = get_limb_size();
f.write_all(b"static BASES : [Base; 257] = [
/* 0 */ Base { digits_per_limb: 0, big_base: ::ll::limb::Limb(0) },
/* 1 */ Base { digits_per_limb: 0, big_base: ::ll::limb::Limb(0) },\n");
for i in 2..257 {
gen_base(f, limb_size, i);
}
f.write_all(b"];\n");
}
fn gen_base(f: &mut File, _limb_size: usize, base: usize) {
let mut digits_per_limb = 1;
let mut big_base : usize = base;
loop {
let (bh, bl) = umul_single(big_base, base);
if bh > 0 {
if bh == 1 && bl == 0 {
digits_per_limb += 1;
}
break;
}
digits_per_limb += 1;
big_base = bl;
}
if base.is_power_of_two() {
big_base = base.trailing_zeros() as usize;
}
writeln!(f, " /* {:3} */ Base {{ digits_per_limb: {}, big_base: ::ll::limb::Limb(0x{:x}) }},",
base, digits_per_limb, big_base);
}
fn get_limb_size() -> usize {
if let Ok(tgt) = env::var("TARGET") {
if let Ok(host) = env::var("HOST") {
if host != tgt { panic!("Cross compiling not currently supported"); }
}
}
return mem::size_of::<Limb>();
}
fn split_limb(l: Limb) -> (Limb, Limb) {
let bits = mem::size_of::<Limb>() * 8;
let mask = (1 << (bits / 2)) - 1;
let low = l & mask;
let high = l >> (bits / 2);
(high, low)
}
fn umul_single(u: Limb, v: Limb) -> (Limb, Limb) {
let bits = mem::size_of::<Limb>() * 8;
let (uh, ul) = split_limb(u);
let (vh, vl) = split_limb(v);
let x0 = ul * vl;
let mut x1 = ul * vh;
let x2 = uh * vl;
let mut x3 = uh * vh;
x1 += split_limb(x0).0;
x1 = x1.wrapping_add(x2);
if x1 < x2 { x3 += 1 << (bits / 2); }
(x3 + split_limb(x1).0, (x1 << (bits/2)) + split_limb(x0).1)
}