///|
// Constant type
pub(all) enum ConType {
CUndef
CBits // Numeric constant
CAddr // Symbol address
} derive(Eq, Debug)
///|
// Constant value bits
pub(all) struct ConBits {
i : Int64 // Integer value
d : Double // Double value
s : Float // Single (float) value
} derive(Debug, Eq)
///|
// Constant - corresponds to struct Con in QBE
pub(all) struct Con {
kind : ConType
label : Int32 // Interned string label for CAddr
bits : ConBits // Value bits
flt : Int32 // 0=integer, 1=print as s, 2=print as d
is_local : Bool // True if local symbol
} derive(Debug, Eq)
///|
pub fn Con::new() -> Con {
Con::{
kind: CUndef,
label: 0,
bits: ConBits::{ i: 0, d: 0.0, s: 0.0, },
flt: 0,
is_local: false,
}
}
///|
pub fn Con::int(i : Int64) -> Con {
Con::{
kind: CBits,
label: 0,
bits: ConBits::{ i, d: 0.0, s: 0.0, },
flt: 0,
is_local: false,
}
}
///|
pub fn Con::double(d : Double) -> Con {
Con::{
kind: CBits,
label: 0,
// bits.i mirrors C's Con.bits union view, so it always carries the raw
// bits; the fold, gvn and the emitters read it directly.
bits: ConBits::{ i: d.reinterpret_as_int64(), d, s: 0.0, },
flt: 2,
is_local: false,
}
}
///|
pub fn Con::single(s : Float) -> Con {
Con::{
kind: CBits,
label: 0,
bits: ConBits::{ i: s.reinterpret_as_uint().to_int64(), d: 0.0, s, },
flt: 1,
is_local: false,
}
}
///|
pub fn Con::addr(label : Int32) -> Con {
Con::{
kind: CAddr,
label,
bits: ConBits::{ i: 0, d: 0.0, s: 0.0, },
flt: 0,
is_local: false,
}
}
///|
// Check if constant is zero
pub fn Con::is_zero(self : Con, wide : Bool) -> Bool {
if self.kind != CBits {
return false
}
if wide {
self.bits.i == 0
} else {
(self.bits.i & 0xFFFFFFFF) == 0
}
}
///|
// Add two constants (for address arithmetic), matching C addcon in util.c
pub fn Con::add(self : Con, other : Con) -> Con {
if self.kind == CUndef {
other
} else {
let kind = if other.kind == CAddr { CAddr } else { self.kind }
let label = if other.kind == CAddr { other.label } else { self.label }
Con::{
kind,
label,
bits: ConBits::{
i: self.bits.i + other.bits.i,
d: self.bits.d,
s: self.bits.s,
},
flt: self.flt,
is_local: self.is_local,
}
}
}
///|
// Raw bit representation of a constant (for interning, like C's union)
pub fn Con::raw_bits(self : Con) -> Int64 {
// ConBits is a struct rather than C's union, so bits.i is kept canonical.
self.bits.i
}
///|
// Interning comparison: type + raw bits + label (ignores flt flag),
// matching C's `con[i].type == c.type && con[i].bits.i == c.bits.i`
fn con_eq(c : Con, other : Con) -> Bool {
c.kind == other.kind &&
c.raw_bits() == other.raw_bits() &&
c.label == other.label
}