fix(std): render integer formatter extremes — i64::MIN and unsigned all-ones [F0.8]

Resolves issue 0090. The `{}` integer formatter mis-rendered both ends of
the 64-bit range:

- `int_to_string` computed the magnitude as `0 - n`, which overflows for
  `s64::MIN` (its magnitude is unrepresentable as a positive s64) — the
  value stayed negative, the digit loop ran zero times, so only `-`
  printed. It now extracts digits straight from `n` (per-digit
  `|n % 10|`, `n` truncating toward zero), never negating MIN.

- `any_to_string`'s `case int:` formatted every integer as s64, so a u64
  all-ones value printed as `-1`. There was no `uint` type-category to
  distinguish signedness. Added an additive `type_is_unsigned(T)`
  reflection builtin (static fold + dynamic interp/LLVM paths, mirroring
  `type_name`), backed by the new `TypeTable.isUnsignedInt` predicate, and
  a `uint_to_string` formatter (unsigned decimal via long-division over
  four 16-bit limbs). `case int:` routes through `type_is_unsigned(type)`.

The 16-bit-limb split is factored into a shared `decompose_u16x4`, now
reused by `int_to_hex_string` (no second unsigned-math routine).

Regression: examples/0046-basic-int-formatter-extremes pins both extremes
plus a width spread; unit tests cover `isUnsignedInt`. Docs (specs.md
representation note, readme std API) updated for unsigned/extreme `{}`
behavior. IR snapshots refreshed for the two new std functions.
This commit is contained in:
agra
2026-06-05 09:05:37 +03:00
parent 5ef74a15f3
commit 64f77e9779
54 changed files with 36282 additions and 30161 deletions

View File

@@ -189,38 +189,43 @@ if.merge.17: ; preds = %entry
%icmpN = icmp slt i64 %loadN, 0
%allocaN = alloca i1, align 1
store i1 %icmpN, ptr %allocaN, align 1
%loadN = load i1, ptr %allocaN, align 1
br i1 %loadN, label %if.then.18, label %if.else.19
if.then.18: ; preds = %if.merge.17
%loadN = load i64, ptr %alloca, align 8
%sub = sub i64 0, %loadN
br label %if.merge.20
if.else.19: ; preds = %if.merge.17
%loadN = load i64, ptr %alloca, align 8
br label %if.merge.20
if.merge.20: ; preds = %if.else.19, %if.then.18
%bp = phi i64 [ %sub, %if.then.18 ], [ %loadN, %if.else.19 ]
%allocaN = alloca i64, align 8
store i64 %bp, ptr %allocaN, align 8
%call = call { ptr, i64 } @cstring(ptr %0, i64 20)
%allocaN = alloca { ptr, i64 }, align 8
store { ptr, i64 } %call, ptr %allocaN, align 8
%allocaN = alloca i64, align 8
store i64 19, ptr %allocaN, align 8
br label %while.hdr.21
%loadN = load i64, ptr %alloca, align 8
%allocaN = alloca i64, align 8
store i64 %loadN, ptr %allocaN, align 8
br label %while.hdr.18
while.hdr.21: ; preds = %while.body.22, %if.merge.20
while.hdr.18: ; preds = %if.merge.22, %if.merge.17
%loadN = load i64, ptr %allocaN, align 8
%icmpN = icmp sgt i64 %loadN, 0
br i1 %icmpN, label %while.body.22, label %while.exit.23
%icmpN = icmp ne i64 %loadN, 0
br i1 %icmpN, label %while.body.19, label %while.exit.20
while.body.22: ; preds = %while.hdr.21
while.body.19: ; preds = %while.hdr.18
%loadN = load i64, ptr %allocaN, align 8
%srem = srem i64 %loadN, 10
%add = add i64 %srem, 48
%allocaN = alloca i64, align 8
store i64 %srem, ptr %allocaN, align 8
%loadN = load i64, ptr %allocaN, align 8
%icmpN = icmp slt i64 %loadN, 0
br i1 %icmpN, label %if.then.21, label %if.merge.22
while.exit.20: ; preds = %while.hdr.18
%loadN = load i1, ptr %allocaN, align 1
br i1 %loadN, label %if.then.23, label %if.merge.24
if.then.21: ; preds = %while.body.19
%loadN = load i64, ptr %allocaN, align 8
%sub = sub i64 0, %loadN
store i64 %sub, ptr %allocaN, align 8
br label %if.merge.22
if.merge.22: ; preds = %if.then.21, %while.body.19
%loadN = load i64, ptr %allocaN, align 8
%add = add i64 %loadN, 48
%loadN = load i64, ptr %allocaN, align 8
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%igp.data = extractvalue { ptr, i64 } %loadN, 0
@@ -233,34 +238,32 @@ while.body.22: ; preds = %while.hdr.21
%loadN = load i64, ptr %allocaN, align 8
%subN = sub i64 %loadN, 1
store i64 %subN, ptr %allocaN, align 8
br label %while.hdr.21
br label %while.hdr.18
while.exit.23: ; preds = %while.hdr.21
%loadN = load i1, ptr %allocaN, align 1
br i1 %loadN, label %if.then.24, label %if.merge.25
if.then.24: ; preds = %while.exit.23
if.then.23: ; preds = %while.exit.20
%loadN = load i64, ptr %allocaN, align 8
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%igp.data21 = extractvalue { ptr, i64 } %loadN, 0
%igp.ptr22 = getelementptr i8, ptr %igp.data21, i64 %loadN
store i8 45, ptr %igp.ptr22, align 1
%igp.data24 = extractvalue { ptr, i64 } %loadN, 0
%igp.ptr25 = getelementptr i8, ptr %igp.data24, i64 %loadN
store i8 45, ptr %igp.ptr25, align 1
%loadN = load i64, ptr %allocaN, align 8
%subN = sub i64 %loadN, 1
store i64 %subN, ptr %allocaN, align 8
br label %if.merge.25
br label %if.merge.24
if.merge.25: ; preds = %if.then.24, %while.exit.23
if.merge.24: ; preds = %if.then.23, %while.exit.20
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
%loadN = load i64, ptr %allocaN, align 8
%subN = sub i64 20, %loadN
%subN = sub i64 %subN, 1
%subN = sub i64 19, %loadN
%callN = call { ptr, i64 } @substr(ptr %0, { ptr, i64 } %loadN, i64 %addN, i64 %subN)
ret { ptr, i64 } %callN
}
; Function Attrs: nounwind
declare ptr @uint_to_string(ptr, i64) #0
; Function Attrs: nounwind
declare ptr @bool_to_string(ptr, i1) #0
@@ -270,6 +273,9 @@ declare ptr @float_to_string(ptr, double) #0
; Function Attrs: nounwind
declare void @hex_group(ptr, ptr, i64, i64) #0
; Function Attrs: nounwind
declare [4 x i64] @decompose_u16x4(ptr, i64) #0
; Function Attrs: nounwind
declare ptr @int_to_hex_string(ptr, i64) #0
@@ -383,7 +389,7 @@ while.exit.4: ; preds = %while.hdr.2
%loadN = load { ptr, i64 }, ptr %alloca, align 8
%lenN = extractvalue { ptr, i64 } %loadN, 1
%icmpN = icmp slt i64 %loadN, %lenN
br i1 %icmpN, label %if.then.38, label %if.merge.39
br i1 %icmpN, label %if.then.37, label %if.merge.38
if.then.5: ; preds = %while.body.3
%loadN = load i64, ptr %allocaN, align 8
@@ -401,9 +407,9 @@ if.else.6: ; preds = %while.body.3
%ig.val21 = load i8, ptr %ig.ptr20, align 1
%cmp.ext22 = zext i8 %ig.val21 to i64
%icmpN = icmp eq i64 %cmp.ext22, 125
br i1 %icmpN, label %if.then.29, label %if.else.30
br i1 %icmpN, label %if.then.28, label %if.else.29
if.merge.7: ; preds = %if.merge.31, %if.merge.10
if.merge.7: ; preds = %if.merge.30, %if.merge.10
br label %while.hdr.2
if.then.8: ; preds = %if.then.5
@@ -441,9 +447,9 @@ if.else.12: ; preds = %if.then.8
%ig.val42 = load i8, ptr %ig.ptr41, align 1
%cmp.ext43 = zext i8 %ig.val42 to i64
%icmpN = icmp eq i64 %cmp.ext43, 123
br i1 %icmpN, label %if.then.26, label %if.else.27
br i1 %icmpN, label %if.then.25, label %if.else.26
if.merge.13: ; preds = %if.merge.28, %if.merge.15
if.merge.13: ; preds = %if.merge.27, %if.merge.15
br label %if.merge.10
if.then.14: ; preds = %if.then.11
@@ -492,7 +498,7 @@ if.merge.15: ; preds = %if.then.14, %if.the
store i64 %loadN, ptr %allocaN, align 8
br label %if.merge.13
if.then.26: ; preds = %if.else.12
if.then.25: ; preds = %if.else.12
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%callN = call { ptr, i64 } @concat(ptr %0, { ptr, i64 } %loadN, { ptr, i64 } { ptr @str.7, i64 36 })
store { ptr, i64 } %callN, ptr %allocaN, align 8
@@ -520,35 +526,35 @@ if.then.26: ; preds = %if.else.12
store i64 %addN, ptr %allocaN, align 8
%loadN = load i64, ptr %allocaN, align 8
store i64 %loadN, ptr %allocaN, align 8
br label %if.merge.28
br label %if.merge.27
if.else.27: ; preds = %if.else.12
if.else.26: ; preds = %if.else.12
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
store i64 %addN, ptr %allocaN, align 8
br label %if.merge.28
br label %if.merge.27
if.merge.28: ; preds = %if.else.27, %if.then.26
if.merge.27: ; preds = %if.else.26, %if.then.25
br label %if.merge.13
if.then.29: ; preds = %if.else.6
if.then.28: ; preds = %if.else.6
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
%loadN = load { ptr, i64 }, ptr %alloca, align 8
%lenN = extractvalue { ptr, i64 } %loadN, 1
%icmpN = icmp slt i64 %addN, %lenN
br i1 %icmpN, label %if.then.32, label %if.else.33
br i1 %icmpN, label %if.then.31, label %if.else.32
if.else.30: ; preds = %if.else.6
if.else.29: ; preds = %if.else.6
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
store i64 %addN, ptr %allocaN, align 8
br label %if.merge.31
br label %if.merge.30
if.merge.31: ; preds = %if.merge.34, %if.else.30
if.merge.30: ; preds = %if.merge.33, %if.else.29
br label %if.merge.7
if.then.32: ; preds = %if.then.29
if.then.31: ; preds = %if.then.28
%loadN = load { ptr, i64 }, ptr %alloca, align 8
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
@@ -557,18 +563,18 @@ if.then.32: ; preds = %if.then.29
%ig.val106 = load i8, ptr %ig.ptr105, align 1
%cmp.ext107 = zext i8 %ig.val106 to i64
%icmpN = icmp eq i64 %cmp.ext107, 125
br i1 %icmpN, label %if.then.35, label %if.else.36
br i1 %icmpN, label %if.then.34, label %if.else.35
if.else.33: ; preds = %if.then.29
if.else.32: ; preds = %if.then.28
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
store i64 %addN, ptr %allocaN, align 8
br label %if.merge.34
br label %if.merge.33
if.merge.34: ; preds = %if.merge.37, %if.else.33
br label %if.merge.31
if.merge.33: ; preds = %if.merge.36, %if.else.32
br label %if.merge.30
if.then.35: ; preds = %if.then.32
if.then.34: ; preds = %if.then.31
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%callN = call { ptr, i64 } @concat(ptr %0, { ptr, i64 } %loadN, { ptr, i64 } { ptr @str.10, i64 36 })
store { ptr, i64 } %callN, ptr %allocaN, align 8
@@ -596,18 +602,18 @@ if.then.35: ; preds = %if.then.32
store i64 %addN, ptr %allocaN, align 8
%loadN = load i64, ptr %allocaN, align 8
store i64 %loadN, ptr %allocaN, align 8
br label %if.merge.37
br label %if.merge.36
if.else.36: ; preds = %if.then.32
if.else.35: ; preds = %if.then.31
%loadN = load i64, ptr %allocaN, align 8
%addN = add i64 %loadN, 1
store i64 %addN, ptr %allocaN, align 8
br label %if.merge.37
br label %if.merge.36
if.merge.37: ; preds = %if.else.36, %if.then.35
br label %if.merge.34
if.merge.36: ; preds = %if.else.35, %if.then.34
br label %if.merge.33
if.then.38: ; preds = %while.exit.4
if.then.37: ; preds = %while.exit.4
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%callN = call { ptr, i64 } @concat(ptr %0, { ptr, i64 } %loadN, { ptr, i64 } { ptr @str.13, i64 36 })
store { ptr, i64 } %callN, ptr %allocaN, align 8
@@ -630,9 +636,9 @@ if.then.38: ; preds = %while.exit.4
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
%callN = call { ptr, i64 } @concat(ptr %0, { ptr, i64 } %loadN, { ptr, i64 } { ptr @str.15, i64 4 })
store { ptr, i64 } %callN, ptr %allocaN, align 8
br label %if.merge.39
br label %if.merge.38
if.merge.39: ; preds = %if.then.38, %while.exit.4
if.merge.38: ; preds = %if.then.37, %while.exit.4
%loadN = load { ptr, i64 }, ptr %allocaN, align 8
ret { ptr, i64 } %loadN
}
@@ -846,13 +852,13 @@ if.merge.1: ; preds = %entry
store ptr %callN, ptr %allocaN, align 8
%loadN = load ptr, ptr %allocaN, align 8
%icmpN = icmp eq ptr %loadN, null
br i1 %icmpN, label %if.then.40, label %if.merge.41
br i1 %icmpN, label %if.then.39, label %if.merge.40
if.then.40: ; preds = %if.merge.1
if.then.39: ; preds = %if.merge.1
call void @print__ct_sfe783e2b27a4beff__pack(ptr @__sx_default_context)
ret i32 1
if.merge.41: ; preds = %if.merge.1
if.merge.40: ; preds = %if.merge.1
%allocaN = alloca ptr, align 8
%callN = call ptr @sel_registerName(ptr @str.18)
store ptr %callN, ptr %allocaN, align 8
@@ -866,13 +872,13 @@ if.merge.41: ; preds = %if.merge.1
store ptr %icall, ptr %allocaN, align 8
%loadN = load ptr, ptr %allocaN, align 8
%icmpN = icmp eq ptr %loadN, null
br i1 %icmpN, label %if.then.42, label %if.merge.43
br i1 %icmpN, label %if.then.41, label %if.merge.42
if.then.42: ; preds = %if.merge.41
if.then.41: ; preds = %if.merge.40
call void @print__ct_scaebdbbd10c81716__pack(ptr @__sx_default_context)
ret i32 1
if.merge.43: ; preds = %if.merge.41
if.merge.42: ; preds = %if.merge.40
%allocaN = alloca ptr, align 8
%callN = call ptr @sel_registerName(ptr @str.19)
store ptr %callN, ptr %allocaN, align 8
@@ -890,13 +896,13 @@ if.merge.43: ; preds = %if.merge.41
store ptr %icallN, ptr %allocaN, align 8
%loadN = load ptr, ptr %allocaN, align 8
%icmpN = icmp eq ptr %loadN, null
br i1 %icmpN, label %if.then.44, label %if.merge.45
br i1 %icmpN, label %if.then.43, label %if.merge.44
if.then.44: ; preds = %if.merge.43
if.then.43: ; preds = %if.merge.42
call void @print__ct_s7c1052877b8cc801__pack(ptr @__sx_default_context)
ret i32 1
if.merge.45: ; preds = %if.merge.43
if.merge.44: ; preds = %if.merge.42
%loadN = load ptr, ptr %allocaN, align 8
%loadN = load ptr, ptr %allocaN, align 8
%loadN = load ptr, ptr %allocaN, align 8