fortrangoingonforty/armfortas / 5d82427

Browse files

Widen i128 constant storage

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
5d8242714d082a0219814e29a67ddb23a8971dad
Parents
c205da3
Tree
21f9750

19 changed files

StatusFile+-
M src/codegen/isel.rs 3 2
M src/ir/builder.rs 7 3
M src/ir/inst.rs 3 3
M src/ir/lower.rs 27 22
M src/opt/bce.rs 1 1
M src/opt/const_arg.rs 1 1
M src/opt/const_fold.rs 41 32
M src/opt/const_prop.rs 3 2
M src/opt/cse.rs 15 15
M src/opt/dep_analysis.rs 2 2
M src/opt/gvn.rs 14 14
M src/opt/loop_utils.rs 1 1
M src/opt/peel.rs 1 1
M src/opt/return_prop.rs 1 1
M src/opt/strength_reduce.rs 4 2
M src/opt/unroll.rs 4 4
M src/opt/vectorize.rs 1 1
A tests/fixtures/integer16_wide_values.f90 12 0
M tests/i128_ir.rs 28 0
src/codegen/isel.rsmodified
@@ -896,7 +896,7 @@ fn select_inst(mf: &mut MachineFunction, ctx: &mut ISelCtx, mb: MBlockId, inst:
896896
             if let Some(idx) = indices.first() {
897897
                 let idx_vreg = ctx.lookup_vreg(*idx);
898898
                 let tmp = mf.new_vreg(RegClass::Gp64);
899
-                emit_const_int(mf, mb, tmp, elem_size, IntWidth::I64);
899
+                emit_const_int(mf, mb, tmp, elem_size as i128, IntWidth::I64);
900900
                 let scaled = mf.new_vreg(RegClass::Gp64);
901901
                 mf.block_mut(mb).insts.push(MachineInst {
902902
                     opcode: ArmOpcode::Mul,
@@ -1417,7 +1417,8 @@ fn emit_epilogue(mf: &mut MachineFunction, mb: MBlockId) {
14171417
 
14181418
 /// Emit a constant integer using movz/movk sequence.
14191419
 /// Respects width: 32-bit values mask to 32 bits and only emit shifts 0/16.
1420
-fn emit_const_int(mf: &mut MachineFunction, mb: MBlockId, dest: VRegId, val: i64, width: IntWidth) {
1420
+fn emit_const_int(mf: &mut MachineFunction, mb: MBlockId, dest: VRegId, val: i128, width: IntWidth) {
1421
+    debug_assert!(width != IntWidth::I128, "backend should reject i128 before isel");
14211422
     let is_32 = matches!(width, IntWidth::I8 | IntWidth::I16 | IntWidth::I32);
14221423
     // Mask to the appropriate width to prevent sign-extension artifacts.
14231424
     let uval = if is_32 { (val as u32) as u64 } else { val as u64 };
src/ir/builder.rsmodified
@@ -65,16 +65,20 @@ impl<'a> FuncBuilder<'a> {
6565
 
6666
     // ---- Constants ----
6767
 
68
-    pub fn const_int(&mut self, value: i64, width: IntWidth) -> ValueId {
68
+    pub fn const_int(&mut self, value: i128, width: IntWidth) -> ValueId {
6969
         self.emit(InstKind::ConstInt(value, width), IrType::Int(width))
7070
     }
7171
 
7272
     pub fn const_i32(&mut self, value: i32) -> ValueId {
73
-        self.const_int(value as i64, IntWidth::I32)
73
+        self.const_int(value as i128, IntWidth::I32)
7474
     }
7575
 
7676
     pub fn const_i64(&mut self, value: i64) -> ValueId {
77
-        self.const_int(value, IntWidth::I64)
77
+        self.const_int(value as i128, IntWidth::I64)
78
+    }
79
+
80
+    pub fn const_i128(&mut self, value: i128) -> ValueId {
81
+        self.const_int(value, IntWidth::I128)
7882
     }
7983
 
8084
     pub fn const_float(&mut self, value: f64, width: FloatWidth) -> ValueId {
src/ir/inst.rsmodified
@@ -69,7 +69,7 @@ pub struct Inst {
6969
 #[derive(Debug, Clone)]
7070
 pub enum InstKind {
7171
     // ---- Constants ----
72
-    ConstInt(i64, IntWidth),
72
+    ConstInt(i128, IntWidth),
7373
     ConstFloat(f64, FloatWidth),
7474
     ConstBool(bool),
7575
     ConstString(Vec<u8>),
@@ -337,7 +337,7 @@ pub struct Global {
337337
 #[derive(Debug, Clone)]
338338
 pub enum GlobalInit {
339339
     Zero,
340
-    Int(i64),
340
+    Int(i128),
341341
     Float(f64),
342342
     String(Vec<u8>),
343343
     /// Array literal: a sequence of per-element initializers of
@@ -346,7 +346,7 @@ pub enum GlobalInit {
346346
     /// constructors. The Vec's length is the array's total element
347347
     /// count (product of dims); shorter initializers are padded
348348
     /// with Zero at lowering time.
349
-    IntArray(Vec<i64>),
349
+    IntArray(Vec<i128>),
350350
     FloatArray(Vec<f64>),
351351
 }
352352
 
src/ir/lower.rsmodified
@@ -736,7 +736,7 @@ fn collect_module_globals(
736736
 ///   2. `[(expr, i = lo, hi[, step])]` implied-do iterator
737737
 ///   3. `reshape(constructor, shape)` reshape of (1) or (2)
738738
 ///
739
-/// Each path produces a flat list of `i64` (for integer types)
739
+/// Each path produces a flat list of `i128` (for integer types)
740740
 /// or `f64` (for float types) of length `total`. Shorter lists
741741
 /// are zero-padded; longer lists return `None` (a future Maj-3
742742
 /// fix will add a proper diagnostic for shape-mismatch errors).
@@ -762,9 +762,9 @@ fn eval_const_array_init(
762762
         while (out.len() as i64) < total { out.push(0.0); }
763763
         Some(GlobalInit::FloatArray(out))
764764
     } else {
765
-        let mut out: Vec<i64> = scalars.iter().map(|s| match s {
765
+        let mut out: Vec<i128> = scalars.iter().map(|s| match s {
766766
             ConstScalar::Int(i) => *i,
767
-            ConstScalar::Float(f) => *f as i64,
767
+            ConstScalar::Float(f) => *f as i128,
768768
         }).collect();
769769
         while (out.len() as i64) < total { out.push(0); }
770770
         Some(GlobalInit::IntArray(out))
@@ -1239,15 +1239,15 @@ fn lower_unit(
12391239
 /// global address + load.
12401240
 fn materialize_const_scalar(b: &mut FuncBuilder, c: ConstScalar, target: &IrType) -> ValueId {
12411241
     match (c, target) {
1242
-        (ConstScalar::Int(i), IrType::Int(IntWidth::I128)) => b.const_int(i, IntWidth::I128),
1243
-        (ConstScalar::Int(i), IrType::Int(IntWidth::I64)) => b.const_i64(i),
1242
+        (ConstScalar::Int(i), IrType::Int(IntWidth::I128)) => b.const_i128(i),
1243
+        (ConstScalar::Int(i), IrType::Int(IntWidth::I64)) => b.const_i64(i as i64),
12441244
         (ConstScalar::Int(i), IrType::Int(_)) => b.const_i32(i as i32),
12451245
         (ConstScalar::Int(i), IrType::Bool) => b.const_bool(i != 0),
12461246
         (ConstScalar::Int(i), IrType::Float(FloatWidth::F64)) => b.const_f64(i as f64),
12471247
         (ConstScalar::Int(i), IrType::Float(FloatWidth::F32)) => b.const_f32(i as f32),
12481248
         (ConstScalar::Float(f), IrType::Float(FloatWidth::F64)) => b.const_f64(f),
12491249
         (ConstScalar::Float(f), IrType::Float(FloatWidth::F32)) => b.const_f32(f as f32),
1250
-        (ConstScalar::Float(f), IrType::Int(IntWidth::I128)) => b.const_int(f as i64, IntWidth::I128),
1250
+        (ConstScalar::Float(f), IrType::Int(IntWidth::I128)) => b.const_i128(f as i128),
12511251
         (ConstScalar::Float(f), IrType::Int(IntWidth::I64)) => b.const_i64(f as i64),
12521252
         (ConstScalar::Float(f), IrType::Int(_)) => b.const_i32(f as i32),
12531253
         // Fallback — emit a zero of the target's class.
@@ -1264,13 +1264,16 @@ fn materialize_const_scalar(b: &mut FuncBuilder, c: ConstScalar, target: &IrType
12641264
 fn clamp_const_to_type(v: ConstScalar, target: &IrType) -> ConstScalar {
12651265
     match (v, target) {
12661266
         (ConstScalar::Int(i), IrType::Int(IntWidth::I8)) => {
1267
-            ConstScalar::Int((i as i8) as i64)
1267
+            ConstScalar::Int((i as i8) as i128)
12681268
         }
12691269
         (ConstScalar::Int(i), IrType::Int(IntWidth::I16)) => {
1270
-            ConstScalar::Int((i as i16) as i64)
1270
+            ConstScalar::Int((i as i16) as i128)
12711271
         }
12721272
         (ConstScalar::Int(i), IrType::Int(IntWidth::I32)) => {
1273
-            ConstScalar::Int((i as i32) as i64)
1273
+            ConstScalar::Int((i as i32) as i128)
1274
+        }
1275
+        (ConstScalar::Int(i), IrType::Int(IntWidth::I64)) => {
1276
+            ConstScalar::Int((i as i64) as i128)
12741277
         }
12751278
         (ConstScalar::Int(i), IrType::Bool) => {
12761279
             ConstScalar::Int(if i != 0 { 1 } else { 0 })
@@ -1317,7 +1320,7 @@ fn eval_const_global_init(
13171320
 /// used for real/double precision.
13181321
 #[derive(Debug, Clone, Copy)]
13191322
 enum ConstScalar {
1320
-    Int(i64),
1323
+    Int(i128),
13211324
     Float(f64),
13221325
 }
13231326
 
@@ -1333,7 +1336,7 @@ fn eval_const_scalar(
13331336
 ) -> Option<ConstScalar> {
13341337
     use crate::ast::expr::{UnaryOp, BinaryOp};
13351338
     match &e.node {
1336
-        Expr::IntegerLiteral { text, .. } => text.parse::<i64>().ok().map(ConstScalar::Int),
1339
+        Expr::IntegerLiteral { text, .. } => text.parse::<i128>().ok().map(ConstScalar::Int),
13371340
         Expr::RealLiteral { text, .. } => {
13381341
             text.replace('d', "e").replace('D', "E").parse::<f64>().ok().map(ConstScalar::Float)
13391342
         }
@@ -1393,8 +1396,8 @@ fn eval_const_scalar(
13931396
                     }
13941397
                     BinaryOp::Pow => {
13951398
                         // Integer power with non-negative exponent.
1396
-                        if r < 0 || r > i32::MAX as i64 { return None; }
1397
-                        let mut acc: i64 = 1;
1399
+                        if r < 0 || r > i32::MAX as i128 { return None; }
1400
+                        let mut acc: i128 = 1;
13981401
                         for _ in 0..r { acc = acc.wrapping_mul(l); }
13991402
                         Some(ConstScalar::Int(acc))
14001403
                     }
@@ -1921,7 +1924,7 @@ fn install_globals_as_locals(
19211924
                                 by_ref: false,
19221925
                                 char_kind: CharKind::None,
19231926
                                 derived_type: None,
1924
-                                inline_const: Some(ConstScalar::Int(cv)),
1927
+                                inline_const: Some(ConstScalar::Int(cv as i128)),
19251928
                             });
19261929
                             installed_from.insert(local_key, mod_key);
19271930
                         }
@@ -7439,17 +7442,19 @@ fn lower_expr_full(
74397442
 ) -> ValueId {
74407443
     match &expr.node {
74417444
         Expr::IntegerLiteral { text, kind, .. } => {
7442
-            let val: i64 = text.parse().unwrap_or(0);
74437445
             let kind = kind.as_deref();
74447446
             if kind == Some("16") {
7445
-                b.const_int(val, IntWidth::I128)
7446
-            } else if kind == Some("8")
7447
-                || val > i32::MAX as i64
7448
-                || val < i32::MIN as i64
7449
-            {
7450
-                b.const_i64(val)
7447
+                b.const_i128(text.parse::<i128>().unwrap_or(0))
74517448
             } else {
7452
-                b.const_i32(val as i32)
7449
+                let val: i64 = text.parse().unwrap_or(0);
7450
+                if kind == Some("8")
7451
+                    || val > i32::MAX as i64
7452
+                    || val < i32::MIN as i64
7453
+                {
7454
+                    b.const_i64(val)
7455
+                } else {
7456
+                    b.const_i32(val as i32)
7457
+                }
74537458
             }
74547459
         }
74557460
         Expr::RealLiteral { text, .. } => {
src/opt/bce.rsmodified
@@ -249,7 +249,7 @@ fn update_step_const(func: &Function, index: ValueId, next: ValueId) -> Option<i
249249
 fn resolve_int_scalar(func: &Function, value: ValueId) -> Option<i64> {
250250
     let kind = find_inst_kind(func, value)?;
251251
     match kind {
252
-        InstKind::ConstInt(v, _) => Some(*v),
252
+        InstKind::ConstInt(v, _) => i64::try_from(*v).ok(),
253253
         InstKind::IntExtend(src, _, _) | InstKind::IntTrunc(src, _) => {
254254
             resolve_int_scalar(func, *src)
255255
         }
src/opt/const_arg.rsmodified
@@ -46,7 +46,7 @@ enum ParamMode {
4646
 
4747
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4848
 enum ScalarConst {
49
-    Int(i64, IntWidth),
49
+    Int(i128, IntWidth),
5050
     Float(u64, FloatWidth),
5151
     Bool(bool),
5252
 }
src/opt/const_fold.rsmodified
@@ -33,7 +33,7 @@ use std::collections::HashMap;
3333
 /// Compile-time constant value, normalized for folding.
3434
 #[derive(Debug, Clone, Copy)]
3535
 enum Const {
36
-    Int(i64, IntWidth),
36
+    Int(i128, IntWidth),
3737
     Float(f64, FloatWidth),
3838
     Bool(bool),
3939
 }
@@ -68,29 +68,39 @@ impl Const {
6868
     }
6969
 }
7070
 
71
-/// Sign-extend `v` from `bits` to a full i64. Used so that comparisons
71
+/// Sign-extend `v` from `bits` to a full i128. Used so that comparisons
7272
 /// and arithmetic on narrower integer types match hardware behavior.
73
-fn sext(v: i64, bits: u32) -> i64 {
74
-    if bits >= 64 { v }
73
+fn sext(v: i128, bits: u32) -> i128 {
74
+    if bits >= 128 { v }
7575
     else {
76
-        let shift = 64 - bits;
76
+        let shift = 128 - bits;
7777
         (v << shift) >> shift
7878
     }
7979
 }
8080
 
81
-/// Mask `v` down to `bits` low bits. The IR stores integers as i64 but
81
+/// Mask `v` down to `bits` low bits. The IR stores integers as i128 but
8282
 /// arithmetic must wrap at the declared width.
83
-fn mask(v: i64, bits: u32) -> i64 {
84
-    if bits >= 64 { v }
85
-    else { v & ((1i64 << bits) - 1) }
83
+fn mask(v: i128, bits: u32) -> i128 {
84
+    if bits >= 128 { v }
85
+    else { v & ((1i128 << bits) - 1) }
8686
 }
8787
 
8888
 /// Truncate-then-sign-extend a wide arithmetic result back to its
89
-/// declared width, normalized to a sign-extended i64.
90
-fn norm(v: i64, w: IntWidth) -> i64 {
89
+/// declared width, normalized to a sign-extended i128.
90
+fn norm(v: i128, w: IntWidth) -> i128 {
9191
     sext(mask(v, w.bits()), w.bits())
9292
 }
9393
 
94
+fn signed_min(w: IntWidth) -> i128 {
95
+    match w {
96
+        IntWidth::I8 => i8::MIN as i128,
97
+        IntWidth::I16 => i16::MIN as i128,
98
+        IntWidth::I32 => i32::MIN as i128,
99
+        IntWidth::I64 => i64::MIN as i128,
100
+        IntWidth::I128 => i128::MIN,
101
+    }
102
+}
103
+
94104
 /// Round an `f64`-stored value to the precision of its declared
95105
 /// `FloatWidth`. Audit B-3: used as defense in depth in `FCmp` and
96106
 /// `FloatToInt` so that those folds don't silently miscompute when
@@ -138,10 +148,9 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
138148
         }
139149
         InstKind::IDiv(a, b) => {
140150
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
141
-                if bv == 0 { return None; } // leave divide-by-zero to runtime
142
-                // i64::MIN / -1 also overflows; bail to keep behavior identical.
143
-                if av == i64::MIN && bv == -1 { return None; }
144151
                 if let IrType::Int(w) = ty {
152
+                    if bv == 0 { return None; } // leave divide-by-zero to runtime
153
+                    if av == signed_min(*w) && bv == -1 { return None; }
145154
                     return Some(InstKind::ConstInt(norm(av / bv, *w), *w));
146155
                 }
147156
             }
@@ -149,9 +158,9 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
149158
         }
150159
         InstKind::IMod(a, b) => {
151160
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
152
-                if bv == 0 { return None; }
153
-                if av == i64::MIN && bv == -1 { return None; }
154161
                 if let IrType::Int(w) = ty {
162
+                    if bv == 0 { return None; }
163
+                    if av == signed_min(*w) && bv == -1 { return None; }
155164
                     return Some(InstKind::ConstInt(norm(av % bv, *w), *w));
156165
                 }
157166
             }
@@ -267,7 +276,7 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
267276
         InstKind::Shl(a, b) => {
268277
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
269278
                 if let IrType::Int(w) = ty {
270
-                    let bits = w.bits() as i64;
279
+                    let bits = w.bits() as i128;
271280
                     if (0..bits).contains(&bv) {
272281
                         return Some(InstKind::ConstInt(
273282
                             norm(av.wrapping_shl(bv as u32), *w),
@@ -282,10 +291,10 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
282291
         InstKind::LShr(a, b) => {
283292
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
284293
                 if let IrType::Int(w) = ty {
285
-                    let bits = w.bits() as i64;
294
+                    let bits = w.bits() as i128;
286295
                     if (0..bits).contains(&bv) {
287
-                        let unsigned = (mask(av, w.bits()) as u64) >> (bv as u32);
288
-                        return Some(InstKind::ConstInt(norm(unsigned as i64, *w), *w));
296
+                        let unsigned = (mask(av, w.bits()) as u128) >> (bv as u32);
297
+                        return Some(InstKind::ConstInt(norm(unsigned as i128, *w), *w));
289298
                     }
290299
                     return None;
291300
                 }
@@ -295,7 +304,7 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
295304
         InstKind::AShr(a, b) => {
296305
             if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (get(a), get(b)) {
297306
                 if let IrType::Int(w) = ty {
298
-                    let bits = w.bits() as i64;
307
+                    let bits = w.bits() as i128;
299308
                     if (0..bits).contains(&bv) {
300309
                         let signed = sext(av, w.bits()) >> (bv as u32);
301310
                         return Some(InstKind::ConstInt(norm(signed, *w), *w));
@@ -314,19 +323,19 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
314323
         // produce a wrong-width constant if we kept reading from `w`.
315324
         InstKind::PopCount(a) => {
316325
             if let (Some(Const::Int(av, src_w)), IrType::Int(out_w)) = (get(a), ty) {
317
-                let val = mask(av, src_w.bits()) as u64;
318
-                return Some(InstKind::ConstInt(norm(val.count_ones() as i64, *out_w), *out_w));
326
+                let val = mask(av, src_w.bits()) as u128;
327
+                return Some(InstKind::ConstInt(norm(val.count_ones() as i128, *out_w), *out_w));
319328
             }
320329
             None
321330
         }
322331
         InstKind::CountLeadingZeros(a) => {
323332
             if let (Some(Const::Int(av, src_w)), IrType::Int(out_w)) = (get(a), ty) {
324333
                 let bits = src_w.bits();
325
-                let val = mask(av, bits) as u64;
334
+                let val = mask(av, bits) as u128;
326335
                 let lz = if val == 0 {
327
-                    bits as i64
336
+                    bits as i128
328337
                 } else {
329
-                    (val.leading_zeros() as i64) - (64 - bits as i64)
338
+                    (val.leading_zeros() as i128) - (128 - bits as i128)
330339
                 };
331340
                 return Some(InstKind::ConstInt(norm(lz, *out_w), *out_w));
332341
             }
@@ -335,8 +344,8 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
335344
         InstKind::CountTrailingZeros(a) => {
336345
             if let (Some(Const::Int(av, src_w)), IrType::Int(out_w)) = (get(a), ty) {
337346
                 let bits = src_w.bits();
338
-                let val = mask(av, bits) as u64;
339
-                let tz = if val == 0 { bits as i64 } else { val.trailing_zeros() as i64 };
347
+                let val = mask(av, bits) as u128;
348
+                let tz = if val == 0 { bits as i128 } else { val.trailing_zeros() as i128 };
340349
                 return Some(InstKind::ConstInt(norm(tz, *out_w), *out_w));
341350
             }
342351
             None
@@ -383,17 +392,17 @@ fn try_fold(kind: &InstKind, ty: &IrType, consts: &HashMap<ValueId, Const>) -> O
383392
                     IntWidth::I16 => i16::MIN as f64,
384393
                     IntWidth::I32 => i32::MIN as f64,
385394
                     IntWidth::I64 => i64::MIN as f64,
386
-                    IntWidth::I128 => i64::MIN as f64,
395
+                    IntWidth::I128 => return None,
387396
                 };
388397
                 let hi = match w {
389398
                     IntWidth::I8  => i8::MAX  as f64,
390399
                     IntWidth::I16 => i16::MAX as f64,
391400
                     IntWidth::I32 => i32::MAX as f64,
392401
                     IntWidth::I64 => i64::MAX as f64,
393
-                    IntWidth::I128 => i64::MAX as f64,
402
+                    IntWidth::I128 => return None,
394403
                 };
395404
                 if truncd < lo || truncd > hi { return None; }
396
-                return Some(InstKind::ConstInt(norm(truncd as i64, *w), *w));
405
+                return Some(InstKind::ConstInt(norm(truncd as i128, *w), *w));
397406
             }
398407
             None
399408
         }
@@ -513,7 +522,7 @@ where F: FnOnce(f64) -> f64
513522
 }
514523
 
515524
 fn fold_int_bin<F>(a: Option<Const>, b: Option<Const>, ty: &IrType, op: F) -> Option<InstKind>
516
-where F: FnOnce(i64, i64) -> i64
525
+where F: FnOnce(i128, i128) -> i128
517526
 {
518527
     if let (Some(Const::Int(av, _)), Some(Const::Int(bv, _))) = (a, b) {
519528
         if let IrType::Int(w) = ty {
src/opt/const_prop.rsmodified
@@ -56,10 +56,11 @@ impl Const {
5656
             InstKind::ConstInt(v, w) => {
5757
                 let bits = w.bits();
5858
                 let signed = if bits >= 64 {
59
-                    *v
59
+                    i64::try_from(*v).ok()?
6060
                 } else {
6161
                     let shift = 64 - bits;
62
-                    (*v << shift) >> shift
62
+                    let narrow = i64::try_from(*v).ok()?;
63
+                    (narrow << shift) >> shift
6364
                 };
6465
                 Some(Const::Int(signed, *w))
6566
             }
src/opt/cse.rsmodified
@@ -47,7 +47,7 @@ struct Key {
4747
     tag: u32,
4848
     operands: Vec<ValueId>,
4949
     /// Auxiliary integer (used for things like comparison op, bitwidth, etc.)
50
-    aux: i64,
50
+    aux: i128,
5151
     /// Optional name for instructions whose value depends on a
5252
     /// symbol (currently only `GlobalAddr`). Audit Med-2: a hashed
5353
     /// aux risked theoretical SipHash13 collisions merging two
@@ -62,7 +62,7 @@ struct Key {
6262
 /// Build a canonical key for an instruction. Returns `None` if the
6363
 /// instruction is impure or otherwise not a CSE candidate.
6464
 fn key_of(inst: &Inst) -> Option<Key> {
65
-    let mk = |tag: u32, ops: Vec<ValueId>, aux: i64| -> Option<Key> {
65
+    let mk = |tag: u32, ops: Vec<ValueId>, aux: i128| -> Option<Key> {
6666
         Some(Key { tag, operands: ops, aux, name: None, ty: inst.ty.clone() })
6767
     };
6868
     let mk_named = |tag: u32, name: String| -> Option<Key> {
@@ -90,15 +90,15 @@ fn key_of(inst: &Inst) -> Option<Key> {
9090
         InstKind::ConstInt(v, w)   => {
9191
             let bits = w.bits();
9292
             // Sign-extend at width: low `bits` bits → i64 sign-extended.
93
-            let signed = if bits >= 64 {
93
+            let signed = if bits >= 128 {
9494
                 *v
9595
             } else {
96
-                let shift = 64 - bits;
96
+                let shift = 128 - bits;
9797
                 (*v << shift) >> shift
9898
             };
9999
             mk(1, vec![], signed)
100100
         }
101
-        InstKind::ConstFloat(v, _) => mk(2, vec![], v.to_bits() as i64),
101
+        InstKind::ConstFloat(v, _) => mk(2, vec![], v.to_bits() as i128),
102102
         InstKind::ConstBool(b)     => mk(3, vec![], if *b { 1 } else { 0 }),
103103
 
104104
         // Integer arithmetic --------------------------------------------
@@ -121,12 +121,12 @@ fn key_of(inst: &Inst) -> Option<Key> {
121121
 
122122
         // Comparisons ---------------------------------------------------
123123
         InstKind::ICmp(op, a, b) => {
124
-            let aux = *op as i64;
124
+            let aux = *op as i128;
125125
             let ops = match op { CmpOp::Eq | CmpOp::Ne => canon(*a, *b), _ => vec![*a, *b] };
126126
             mk(30, ops, aux)
127127
         }
128128
         InstKind::FCmp(op, a, b) => {
129
-            let aux = *op as i64;
129
+            let aux = *op as i128;
130130
             let ops = match op { CmpOp::Eq | CmpOp::Ne => canon(*a, *b), _ => vec![*a, *b] };
131131
             mk(31, ops, aux)
132132
         }
@@ -151,12 +151,12 @@ fn key_of(inst: &Inst) -> Option<Key> {
151151
         InstKind::PopCount(a)           => mk(59, vec![*a], 0),
152152
 
153153
         // Conversions ---------------------------------------------------
154
-        InstKind::IntToFloat(v, fw)     => mk(60, vec![*v], fw.bits() as i64),
155
-        InstKind::FloatToInt(v, w)      => mk(61, vec![*v], w.bits() as i64),
156
-        InstKind::FloatExtend(v, fw)    => mk(62, vec![*v], fw.bits() as i64),
157
-        InstKind::FloatTrunc(v, fw)     => mk(63, vec![*v], fw.bits() as i64),
158
-        InstKind::IntExtend(v, w, sgn)  => mk(64, vec![*v], (w.bits() as i64) | ((*sgn as i64) << 32)),
159
-        InstKind::IntTrunc(v, w)        => mk(65, vec![*v], w.bits() as i64),
154
+        InstKind::IntToFloat(v, fw)     => mk(60, vec![*v], fw.bits() as i128),
155
+        InstKind::FloatToInt(v, w)      => mk(61, vec![*v], w.bits() as i128),
156
+        InstKind::FloatExtend(v, fw)    => mk(62, vec![*v], fw.bits() as i128),
157
+        InstKind::FloatTrunc(v, fw)     => mk(63, vec![*v], fw.bits() as i128),
158
+        InstKind::IntExtend(v, w, sgn)  => mk(64, vec![*v], (w.bits() as i128) | ((*sgn as i128) << 32)),
159
+        InstKind::IntTrunc(v, w)        => mk(65, vec![*v], w.bits() as i128),
160160
 
161161
         // Address arithmetic --------------------------------------------
162162
         InstKind::GetElementPtr(base, idxs) => {
@@ -166,10 +166,10 @@ fn key_of(inst: &Inst) -> Option<Key> {
166166
         }
167167
 
168168
         // Aggregates ----------------------------------------------------
169
-        InstKind::ExtractField(agg, i) => mk(80, vec![*agg], *i as i64),
169
+        InstKind::ExtractField(agg, i) => mk(80, vec![*agg], *i as i128),
170170
         // InsertField produces a new aggregate value — pure but rarely
171171
         // duplicate; include for completeness.
172
-        InstKind::InsertField(agg, i, v) => mk(81, vec![*agg, *v], *i as i64),
172
+        InstKind::InsertField(agg, i, v) => mk(81, vec![*agg, *v], *i as i128),
173173
 
174174
         // Impure / not handled ------------------------------------------
175175
         InstKind::Load(..)
src/opt/dep_analysis.rsmodified
@@ -102,7 +102,7 @@ pub fn extract_affine(
102102
     // Find the instruction that defines this value.
103103
     let inst = find_inst(func, val)?;
104104
     match &inst.kind {
105
-        InstKind::ConstInt(c, _) => Some(AffineExpr::from_const(*c)),
105
+        InstKind::ConstInt(c, _) => i64::try_from(*c).ok().map(AffineExpr::from_const),
106106
 
107107
         InstKind::IAdd(a, b) => {
108108
             let ea = extract_affine(func, *a, ivs)?;
@@ -142,7 +142,7 @@ pub fn extract_affine(
142142
 
143143
 fn resolve_const(func: &Function, vid: ValueId) -> Option<i64> {
144144
     let inst = find_inst(func, vid)?;
145
-    if let InstKind::ConstInt(c, _) = &inst.kind { Some(*c) } else { None }
145
+    if let InstKind::ConstInt(c, _) = &inst.kind { i64::try_from(*c).ok() } else { None }
146146
 }
147147
 
148148
 fn find_inst(func: &Function, vid: ValueId) -> Option<&Inst> {
src/opt/gvn.rsmodified
@@ -38,7 +38,7 @@ impl Pass for Gvn {
3838
 struct Key {
3939
     tag: u32,
4040
     operands: Vec<ValueId>,
41
-    aux: i64,
41
+    aux: i128,
4242
     name: Option<String>,
4343
     ty: IrType,
4444
 }
@@ -269,7 +269,7 @@ fn key_of(
269269
     pure_calls: &[PureCallPolicy],
270270
     wrapper_values: &HashMap<ValueId, ValueId>,
271271
 ) -> Option<Key> {
272
-    let mk = |tag: u32, ops: Vec<ValueId>, aux: i64| -> Option<Key> {
272
+    let mk = |tag: u32, ops: Vec<ValueId>, aux: i128| -> Option<Key> {
273273
         Some(Key { tag, operands: ops, aux, name: None, ty: inst.ty.clone() })
274274
     };
275275
     let mk_named = |tag: u32, name: String| -> Option<Key> {
@@ -297,13 +297,13 @@ fn key_of(
297297
         InstKind::FSqrt(a)    => mk(16, vec![remap(*a)], 0),
298298
         InstKind::FPow(a, b)  => mk(17, vec![remap(*a), remap(*b)], 0),
299299
         InstKind::ICmp(op, a, b) => {
300
-            let op_val = *op as i64;
300
+            let op_val = *op as i128;
301301
             match op {
302302
                 CmpOp::Eq | CmpOp::Ne => mk(20, canon(remap(*a), remap(*b)), op_val),
303303
                 _ => mk(20, vec![remap(*a), remap(*b)], op_val),
304304
             }
305305
         }
306
-        InstKind::FCmp(op, a, b) => mk(21, vec![remap(*a), remap(*b)], *op as i64),
306
+        InstKind::FCmp(op, a, b) => mk(21, vec![remap(*a), remap(*b)], *op as i128),
307307
         InstKind::And(a, b) => mk(30, canon(remap(*a), remap(*b)), 0),
308308
         InstKind::Or(a, b)  => mk(31, canon(remap(*a), remap(*b)), 0),
309309
         InstKind::Not(a)    => mk(32, vec![remap(*a)], 0),
@@ -319,16 +319,16 @@ fn key_of(
319319
         InstKind::CountTrailingZeros(a) => mk(48, vec![remap(*a)], 0),
320320
         InstKind::PopCount(a)           => mk(49, vec![remap(*a)], 0),
321321
         // Conversions.
322
-        InstKind::IntToFloat(a, w)   => mk(50, vec![remap(*a)], w.bits() as i64),
323
-        InstKind::FloatToInt(a, w)   => mk(51, vec![remap(*a)], w.bits() as i64),
324
-        InstKind::FloatExtend(a, w)  => mk(52, vec![remap(*a)], w.bits() as i64),
325
-        InstKind::FloatTrunc(a, w)   => mk(53, vec![remap(*a)], w.bits() as i64),
326
-        InstKind::IntExtend(a, w, s) => mk(54, vec![remap(*a)], w.bits() as i64 * if *s { 1 } else { -1 }),
327
-        InstKind::IntTrunc(a, w)     => mk(55, vec![remap(*a)], w.bits() as i64),
322
+        InstKind::IntToFloat(a, w)   => mk(50, vec![remap(*a)], w.bits() as i128),
323
+        InstKind::FloatToInt(a, w)   => mk(51, vec![remap(*a)], w.bits() as i128),
324
+        InstKind::FloatExtend(a, w)  => mk(52, vec![remap(*a)], w.bits() as i128),
325
+        InstKind::FloatTrunc(a, w)   => mk(53, vec![remap(*a)], w.bits() as i128),
326
+        InstKind::IntExtend(a, w, s) => mk(54, vec![remap(*a)], (w.bits() as i128) * if *s { 1 } else { -1 }),
327
+        InstKind::IntTrunc(a, w)     => mk(55, vec![remap(*a)], w.bits() as i128),
328328
         // Constants.
329
-        InstKind::ConstInt(v, w)   => mk(60, vec![], *v * 100 + w.bits() as i64),
330
-        InstKind::ConstFloat(v, w) => mk(61, vec![], ((*v).to_bits() as i64) ^ (w.bits() as i64)),
331
-        InstKind::ConstBool(v)     => mk(62, vec![], *v as i64),
329
+        InstKind::ConstInt(v, w)   => mk(60, vec![], *v * 100 + w.bits() as i128),
330
+        InstKind::ConstFloat(v, w) => mk(61, vec![], ((*v).to_bits() as i128) ^ (w.bits() as i128)),
331
+        InstKind::ConstBool(v)     => mk(62, vec![], *v as i128),
332332
         // GlobalAddr.
333333
         InstKind::GlobalAddr(name) => mk_named(70, name.clone()),
334334
         // GEP.
@@ -359,7 +359,7 @@ fn key_of(
359359
                     PureArgPolicy::Unsupported => return None,
360360
                 }
361361
             }
362
-            mk(90, ops, *idx as i64)
362
+            mk(90, ops, *idx as i128)
363363
         }
364364
         // Impure: loads, stores, runtime calls, external calls, alloca — not GVN candidates.
365365
         InstKind::Load(..) | InstKind::Store(..) | InstKind::Alloca(..)
src/opt/loop_utils.rsmodified
@@ -45,7 +45,7 @@ pub fn resolve_const_int(func: &Function, vid: ValueId) -> Option<i64> {
4545
         for inst in &block.insts {
4646
             if inst.id == vid {
4747
                 if let InstKind::ConstInt(v, _) = inst.kind {
48
-                    return Some(v);
48
+                    return i64::try_from(v).ok();
4949
                 }
5050
                 return None;
5151
             }
src/opt/peel.rsmodified
@@ -206,7 +206,7 @@ fn do_peel(
206206
     };
207207
     func.block_mut(clone_latch).insts.push(Inst {
208208
         id: next_init_id,
209
-        kind: InstKind::ConstInt(init_const + stride, iv_width),
209
+        kind: InstKind::ConstInt((init_const + stride) as i128, iv_width),
210210
         ty: iv_ty.clone(),
211211
         span: dummy_span,
212212
     });
src/opt/return_prop.rsmodified
@@ -38,7 +38,7 @@ impl Pass for ReturnPropagate {
3838
 
3939
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4040
 enum ScalarConst {
41
-    Int(i64, IntWidth),
41
+    Int(i128, IntWidth),
4242
     Float(u64, FloatWidth),
4343
     Bool(bool),
4444
 }
src/opt/strength_reduce.rsmodified
@@ -89,7 +89,9 @@ fn collect_int_consts(func: &Function) -> HashMap<ValueId, (i64, IntWidth)> {
8989
     for block in &func.blocks {
9090
         for inst in &block.insts {
9191
             if let InstKind::ConstInt(v, w) = inst.kind {
92
-                consts.insert(inst.id, (sext(v, w.bits()), w));
92
+                if let Ok(v) = i64::try_from(v) {
93
+                    consts.insert(inst.id, (sext(v, w.bits()), w));
94
+                }
9395
             }
9496
         }
9597
     }
@@ -320,7 +322,7 @@ impl Pass for StrengthReduce {
320322
                         let span = func.blocks[bi].insts[ii].span;
321323
                         func.blocks[bi].insts.insert(ii, Inst {
322324
                             id: kid,
323
-                            kind: InstKind::ConstInt(k as i64, int_w),
325
+                            kind: InstKind::ConstInt(k as i128, int_w),
324326
                             ty: IrType::Int(int_w),
325327
                             span,
326328
                         });
src/opt/unroll.rsmodified
@@ -583,7 +583,7 @@ fn do_unroll(func: &mut Function, shape: LoopShape) {
583583
                 if bi == 0 {
584584
                     let iv_inst = Inst {
585585
                         id: iv_const_id,
586
-                        kind: InstKind::ConstInt(iv_val, iv_width),
586
+                        kind: InstKind::ConstInt(iv_val as i128, iv_width),
587587
                         ty: shape.iv_ty.clone(),
588588
                         span: dummy_span(),
589589
                     };
@@ -798,7 +798,7 @@ mod tests {
798798
         let lo_val = f.next_value_id();
799799
         f.block_mut(entry_id).insts.push(Inst {
800800
             id: lo_val, ty: IrType::Int(IntWidth::I64), span: span(),
801
-            kind: InstKind::ConstInt(lo, IntWidth::I64),
801
+            kind: InstKind::ConstInt(lo as i128, IntWidth::I64),
802802
         });
803803
         // alloca for the "array" (just a slot we store into)
804804
         let alloca_val = f.next_value_id();
@@ -819,7 +819,7 @@ mod tests {
819819
         let hi_val = f.next_value_id();
820820
         f.block_mut(header_id).insts.push(Inst {
821821
             id: hi_val, ty: IrType::Int(IntWidth::I64), span: span(),
822
-            kind: InstKind::ConstInt(hi, IntWidth::I64),
822
+            kind: InstKind::ConstInt(hi as i128, IntWidth::I64),
823823
         });
824824
         // %cmp = icmp.sle %i, hi
825825
         let cmp_val = f.next_value_id();
@@ -885,7 +885,7 @@ mod tests {
885885
         assert_eq!(f.blocks.len(), 6, "expected entry + 4 iter blocks + exit");
886886
 
887887
         // Each iteration block has a ConstInt for that iteration's IV value.
888
-        let all_iv_consts: Vec<i64> = f.blocks.iter()
888
+        let all_iv_consts: Vec<i128> = f.blocks.iter()
889889
             .flat_map(|b| b.insts.iter())
890890
             .filter_map(|i| if let InstKind::ConstInt(v, _) = i.kind { Some(v) } else { None })
891891
             .collect();
src/opt/vectorize.rsmodified
@@ -512,7 +512,7 @@ fn ensure_i64_const(
512512
     func.register_type(id, ty.clone());
513513
     func.block_mut(block_id).insts.push(Inst {
514514
         id,
515
-        kind: InstKind::ConstInt(value, IntWidth::I64),
515
+        kind: InstKind::ConstInt(value as i128, IntWidth::I64),
516516
         ty,
517517
         span,
518518
     });
tests/fixtures/integer16_wide_values.f90added
@@ -0,0 +1,12 @@
1
+module integer16_wide_values_mod
2
+  implicit none
3
+  integer(16), save :: big_global = 9223372036854775808_16
4
+end module integer16_wide_values_mod
5
+
6
+program integer16_wide_values
7
+  use integer16_wide_values_mod
8
+  implicit none
9
+  integer(16) :: big_local
10
+
11
+  big_local = 170141183460469231731687303715884105727_16
12
+end program integer16_wide_values
tests/i128_ir.rsmodified
@@ -41,3 +41,31 @@ fn integer16_lowers_to_i128_in_raw_ir() {
4141
         ir
4242
     );
4343
 }
44
+
45
+#[test]
46
+fn integer16_preserves_values_beyond_i64_in_ir_and_globals() {
47
+    let ir = capture_text(
48
+        CaptureRequest {
49
+            input: fixture("integer16_wide_values.f90"),
50
+            requested: BTreeSet::from([Stage::Ir]),
51
+            opt_level: OptLevel::O0,
52
+        },
53
+        Stage::Ir,
54
+    );
55
+
56
+    assert!(
57
+        ir.contains("9223372036854775808"),
58
+        "raw IR should preserve the wide kind-16 global initializer:\n{}",
59
+        ir
60
+    );
61
+    assert!(
62
+        ir.contains("170141183460469231731687303715884105727"),
63
+        "raw IR should preserve the wide kind-16 local constant:\n{}",
64
+        ir
65
+    );
66
+    assert!(
67
+        ir.contains("const_int 170141183460469231731687303715884105727 : i128"),
68
+        "raw IR should materialize wide local literals as i128 constants:\n{}",
69
+        ir
70
+    );
71
+}