use super::CodeGen;
use super::error::CodeGenError;
use std::fmt::Write;
pub(in crate::codegen) const I63_MIN_LIT: &str = "-4611686018427387904";
pub(in crate::codegen) const I63_MAX_LIT: &str = "4611686018427387903";
pub(in crate::codegen) const I63_MASK_LIT: &str = "9223372036854775807";
impl CodeGen {
pub(in crate::codegen) fn emit_clamp_to_i63(
&mut self,
val: &str,
) -> Result<String, CodeGenError> {
let fits_min = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = icmp sge i64 %{}, {}",
fits_min, val, I63_MIN_LIT
)?;
let fits_max = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = icmp sle i64 %{}, {}",
fits_max, val, I63_MAX_LIT
)?;
let fits = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = and i1 %{}, %{}",
fits, fits_min, fits_max
)?;
let clamped = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = select i1 %{}, i64 %{}, i64 0",
clamped, fits, val
)?;
Ok(clamped)
}
pub(in crate::codegen) fn emit_popcount_i63(
&mut self,
val: &str,
) -> Result<String, CodeGenError> {
let masked = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = and i64 %{}, {}",
masked, val, I63_MASK_LIT
)?;
let result = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = call i64 @llvm.ctpop.i64(i64 %{})",
result, masked
)?;
Ok(result)
}
pub(in crate::codegen) fn emit_clz_i63(&mut self, val: &str) -> Result<String, CodeGenError> {
let raw = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = call i64 @llvm.ctlz.i64(i64 %{}, i1 false)",
raw, val
)?;
let raw_is_zero = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = icmp eq i64 %{}, 0",
raw_is_zero, raw
)?;
let minus_one = self.fresh_temp();
writeln!(&mut self.output, " %{} = sub i64 %{}, 1", minus_one, raw)?;
let result = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = select i1 %{}, i64 0, i64 %{}",
result, raw_is_zero, minus_one
)?;
Ok(result)
}
pub(in crate::codegen) fn emit_ctz_i63(&mut self, val: &str) -> Result<String, CodeGenError> {
let raw = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = call i64 @llvm.cttz.i64(i64 %{}, i1 false)",
raw, val
)?;
let val_is_zero = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = icmp eq i64 %{}, 0",
val_is_zero, val
)?;
let result = self.fresh_temp();
writeln!(
&mut self.output,
" %{} = select i1 %{}, i64 63, i64 %{}",
result, val_is_zero, raw
)?;
Ok(result)
}
}