diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-20 10:56:30 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-08-20 10:56:30 -0700 |
| commit | 3568f3deed586327f885ac98b73d07ae3ade6e57 (patch) | |
| tree | fce7865468dc9e2beabeb68342f23bfea5bdae1a /chapter25/src/main/smp/sys | |
| parent | 1cb8279a64f4f79615ac8358927b11237df29bf2 (diff) | |
| download | Simple-3568f3deed586327f885ac98b73d07ae3ade6e57.tar.gz Simple-3568f3deed586327f885ac98b73d07ae3ade6e57.zip | |
Squashed commit of the following:
commit c05d7df4f9c90984d2c04126772be3fee1d81fd1
Author: Cliff Click <cliffc@acm.org>
Date: Thu Aug 20 10:52:58 2026 -0700
Fix local frefs, deferred inlining, and sys FileIO support
- Defer non-trivial inlining out of CallEnd idealization and run it from IterPeeps after normal peepholes reach a fixed point.
- Keep forward refs local to their lexical scope, promote them outward on scope pop, and track created FRefNodes directly for dependency discovery.
- Preserve loop scope shape when frefs are first seen inside loop bodies.
- Treat frefs as final constants from creation and force lazy self lookups before implicit calls.
- Reset imported pointer/struct types conservatively for post-parse Iter.
- Pin Start-owned global machine value chains and clone global constants per function during GCM.
- Improve late ASM printing before encoding and namespace constant-pool symbols.
- Add optional regalloc function-local edge verifier and improve empty-mask splitting for multi-def/fixed-register LRGs.
- Add sys array compare, safer array copy bounds, libc open/creat/close/unlink bindings, aryu8.str0, and higher-level sys.io file operations.
- Add docs/examples/FileIO.smp and a Chapter25 FileIO test.
- Update spill/code-size goldens after the allocator and scheduling changes.
commit ef5316979732ac118612d310b75923c8f59ecdc1
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 16:29:56 2026 -0700
Dijkstra uses bitset.
TestC.exec for repeated test runs with different stdins.
Support &= and |= op-update forms.
commit 728a527587f19bb49860f02ae5ac5968ab01ae33
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 12:13:28 2026 -0700
Fix live demo
commit e4c069b9ef2cbfafe28d8edfcbff55396cde085e
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 09:52:24 2026 -0700
Update Dijkstra.smp
commit b8015739b4056e3f7a715a030e846a441021a9f1
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 09:41:17 2026 -0700
Better looking Dijkstra
commit 7cce587804c6169b24829e0b5bdc10be94357a31
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 09:33:33 2026 -0700
Fix CmpMemX86 encoding
Use sys.aryu8 for number printing
commit 310b5d8c9978a3b09622a4b89dac97f0e5e6f3fb
Author: Cliff Click <cliffc@acm.org>
Date: Fri Aug 14 09:04:58 2026 -0700
Progress dijlstra
Fix NotX86 encoding. Allow Not-sinking through Phis; the Nots both take Scalar and might take different types (ptr vs int). Better guard installing during && || opers.
Drop the csv parse flavor in sys lib.
commit 5917d5322521dd5e762c4698d34e5d7ac9b3a37f
Author: Cliff Click <cliffc@acm.org>
Date: Thu Aug 13 14:44:12 2026 -0700
missed
commit da35ad4d8a330559a21c04ae6326536e0fd62c48
Author: Cliff Click <cliffc@acm.org>
Date: Thu Aug 13 14:43:42 2026 -0700
Major cleanup of allocation
All the graph-gen is moved to the <ctor> declaration and not at the alloc site.
commit c4223216099ccbc526d282bb263972532d48c5b2
Author: Cliff Click <cliffc@acm.org>
Date: Thu Aug 13 13:26:01 2026 -0700
Some work from Dykstra (more coming)
commit a03bc567f61dc7e4355e453ee4be16ac2528d1ab
Author: Cliff Click <cliffc@acm.org>
Date: Thu Aug 13 09:32:55 2026 -0700
Spill correctness and improvements
Had the callee-save pick-risky backwards vs cloneables.
commit 2d306e4430225f916cb7fb999f4926e52f6fb70a
Author: Cliff Click <cliffc@acm.org>
Date: Wed Aug 12 19:40:04 2026 -0700
Tighter parser handling of missing fields
Bug fix add libc.errno, read can return -1, sys.ary exists
commit b7eeefda4cafa1e86153170dca6f13d45ef63f69
Author: Cliff Click <cliffc@acm.org>
Date: Wed Aug 12 16:22:48 2026 -0700
Printer improvements
commit 8b9112226f1d2d1c843b080eecefe0d5ddc1f8cf
Author: Cliff Click <cliffc@acm.org>
Date: Wed Aug 12 15:30:46 2026 -0700
Remove GLB
commit ae566f5c610b9c30831906d3f024901d8930a227
Author: Cliff Click <cliffc@acm.org>
Date: Wed Aug 12 14:38:51 2026 -0700
Add Capitalize example
Rename Ary to ary.
Fix bug || carrying state along.
Fix bug load-array removing control.
Add sys.char tolower/upper
Diffstat (limited to 'chapter25/src/main/smp/sys')
| -rw-r--r-- | chapter25/src/main/smp/sys/Ary.smp | 10 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/adt.smp | 4 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/adt/bitset.smp | 58 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/ary.smp | 25 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/aryi64.smp | 26 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/aryu8.smp | 38 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/char.smp | 9 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/io.smp | 65 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/libc.smp | 28 | ||||
| -rw-r--r-- | chapter25/src/main/smp/sys/scan.smp (renamed from chapter25/src/main/smp/sys/Scan.smp) | 8 |
10 files changed, 218 insertions, 53 deletions
diff --git a/chapter25/src/main/smp/sys/Ary.smp b/chapter25/src/main/smp/sys/Ary.smp deleted file mode 100644 index 0f667695..00000000 --- a/chapter25/src/main/smp/sys/Ary.smp +++ /dev/null @@ -1,10 +0,0 @@ -// -*- mode: java; -*- - -// Array utilities - -// Copy byte array contents -val copy = { u8[] dst, int doff, u8[~] src, int soff, int len -> - for( int i=0; i<len; i++ ) - dst[i+doff] = src[i+soff]; - return dst; -}; diff --git a/chapter25/src/main/smp/sys/adt.smp b/chapter25/src/main/smp/sys/adt.smp new file mode 100644 index 00000000..efdad395 --- /dev/null +++ b/chapter25/src/main/smp/sys/adt.smp @@ -0,0 +1,4 @@ +// -*- mode: java; -*- + +// Abstract data types. +val bitset = bitset; diff --git a/chapter25/src/main/smp/sys/adt/bitset.smp b/chapter25/src/main/smp/sys/adt/bitset.smp new file mode 100644 index 00000000..f56f1cce --- /dev/null +++ b/chapter25/src/main/smp/sys/adt/bitset.smp @@ -0,0 +1,58 @@ +// -*- mode: java; -*- + +// A set of non-negative integers, represented one bit per value. +struct bitset { + i64[] !_bits; + + new bitset = { -> + _bits = new i64[1]; + }; + + // Return 0 for missing, non-zero for true + val get = { int bit -> + if( (bit >> 6) >= _bits# ) return false; + i64 mask = 1 << (bit & 63); + return (_bits[bit >> 6] & mask); + }; + + val _grow = { int bit -> + int x = bit >> 6; + int len = _bits#; + if( x < len ) return self; + while( x >= len ) len *= 2; + var bits = new i64[len]; + for( int i=0; i<_bits#; i++ ) + bits[i] = _bits[i]; + _bits = bits; + return self; + }; + + // Set + val set = { int bit -> + i64 mask = 1 << (bit & 63); + _grow(bit)._bits[bit >> 6] |= mask; + return self; + }; + + // Test and set + val tset = { int bit -> + int idx = bit >> 6; + i64 mask = 1 << (bit & 63); + if( _grow(bit)._bits[idx] & mask ) + return true; // Already set + _bits[idx] |= mask; + return false; // Was false (and now set) + }; + + val clr = { int bit -> + if( (bit >> 6) >= _bits# ) return self; + i64 mask = 1 << (bit & 63); + _bits[bit >> 6] &= (mask ^ -1); + return self; + }; + + val clear = { -> + for( int i=0; i<_bits#; i++ ) _bits[i] = 0; + return self; + }; +}; diff --git a/chapter25/src/main/smp/sys/ary.smp b/chapter25/src/main/smp/sys/ary.smp new file mode 100644 index 00000000..feade0f5 --- /dev/null +++ b/chapter25/src/main/smp/sys/ary.smp @@ -0,0 +1,25 @@ +// -*- mode: java; -*- + +// Array utilities + +// Copy byte array contents. Copies the shorter of the buffers and len +val copy = { u8[] dst, int doff, u8[~] src, int soff, int len -> + if( len > dst# - doff ) len = dst# - doff; + if( len > src# - soff ) len = src# - soff; + for( int i=0; i<len; i++ ) + dst[i+doff] = src[i+soff]; + return dst; +}; + +// Compare lexigraphically array contents. Compares up to shorter array or +// len. Returns <0 or >0 for first non-matching byte. Returns <0 or >0 for +// the larger array after that, or 0 if both arrays are fully equal. +val cmp = { u8[~] src1, u32 off1, u8[~] src2, u32 off2, u32 len -> + u32 len1 = len > src1# - off1 ? src1# - off1 : len; + u32 len2 = len > src2# - off2 ? src2# - off2 : len; + u32 max = len1 > len2 ? len2 : len1; + for( int i=0; i<max; i++ ) + if( src1[off1+i] != src2[off2+i] ) + return src1[off1+i] - src2[off2+i]; // Bytes determine compare + return len1 - len2; // Length determines compare +}; diff --git a/chapter25/src/main/smp/sys/aryi64.smp b/chapter25/src/main/smp/sys/aryi64.smp index c2bc394f..e4c39ac3 100644 --- a/chapter25/src/main/smp/sys/aryi64.smp +++ b/chapter25/src/main/smp/sys/aryi64.smp @@ -27,21 +27,16 @@ struct aryi64 { self; }; - // Write to aryu8 + val get = { int index -> return buf[index]; }; + + // Write the bracketed array-list form to aryu8. val str = { -> // TODO: clunky default constructor syntax - var str = new aryu8(new u8[1]).add('['); - for( int i=0; i<len; i++ ) - str.num(buf[i]).add(',').add(' '); - str.undo(2).add(']'); - }; - - // Comma-separated form used by command-line examples. - val csv = { -> - var str = new aryu8(new u8[1]); + var str = new aryu8().add('['); for( int i=0; i<len; i++ ) str.num(buf[i]).add(',').add(' '); - str.undo(2).add('\n'); + if( len ) str.undo(2); + return str.add(']'); }; val swap = { int i, int j -> @@ -53,12 +48,13 @@ struct aryi64 { }; + // Parse a comma-separated list of numbers, wrapped with square brackets, // with optional whitespace e.g. "[ -17, 0,99,12456789 ] ". // parseAryI64 & aryi64.str are bijections modulo whitespace. // Returns null if the parse failed, without giving a clue as to why. val parseAryI64 = { u8[~] str -> - Scan !s = new Scan(str); + scan !s = new scan(str); if( !s.match('[') ) return null; // Array of parsed results var nums = new aryi64(new i64[1]); @@ -79,3 +75,9 @@ val parseAryI64 = { u8[~] str -> s.skip(); return s.x == s.buf# ? nums : null; }; + +val copy = { i64[] dst, int doff, i64[~] src, int soff, int len -> + for( int i=0; i<len; i++ ) + dst[i+doff] = src[i+soff]; + return dst; +}; diff --git a/chapter25/src/main/smp/sys/aryu8.smp b/chapter25/src/main/smp/sys/aryu8.smp index 0ce4bd23..186a45a3 100644 --- a/chapter25/src/main/smp/sys/aryu8.smp +++ b/chapter25/src/main/smp/sys/aryu8.smp @@ -5,9 +5,7 @@ struct aryu8 { u32 !len = 0; u8[] !buf; - new aryu8 = { u8[] b -> - buf = b; - }; + new aryu8 = { -> buf = new u8[1]; }; // Grow as needed val _grow = { int len2 -> @@ -15,7 +13,7 @@ struct aryu8 { int newlen = buf# * 2; while( len+len2 >= newlen ) newlen *= 2; u8[] !buf2 = new u8[newlen]; - Ary.copy(buf2,0,buf,0,buf#); + ary.copy(buf2,0,buf,0,buf#); buf = buf2; self; }; @@ -29,10 +27,10 @@ struct aryu8 { }; // Add all of a plain array to the aryu8 - val addAry = { u8[~] ary -> - _grow(ary#); - Ary.copy(buf,len,ary,0,ary#); - len += ary#; + val addAry = { u8[~] xs -> + _grow(xs#); + ary.copy(buf,len,xs,0,xs#); + len += xs#; self; }; @@ -64,3 +62,27 @@ struct aryu8 { libc.write(fd,ptr,len); }; }; + + +// Parse one integer, ignore trailing data; returns 0 with an empty string. +// If you want a more robust parsing, use the `scan` class +val atoi = { u8[~] str -> + int x = 0; + while( x < str# && str[x] <= ' ' ) x++; + if( x == str# ) return 0; + bool neg = false; + if( str[x]=='-' ) { neg=true; x++; } + i64 n = 0; + while( x < str# && '0' <= str[x] <= '9' ) + n = n*10 + str[x++]-'0'; + return neg ? -n : n; +}; + +// Zero-terminate string for libc strings. No error checking, just copies and +// appends a zero. +{ u8[~] -> u8[] } str0 = { u8[~] str -> + u8[] !strz = new u8[str#+1]; + ary.copy(strz,0,str,0,str#); + strz[str#] = '\0'; + strz; +}; diff --git a/chapter25/src/main/smp/sys/char.smp b/chapter25/src/main/smp/sys/char.smp new file mode 100644 index 00000000..de37968e --- /dev/null +++ b/chapter25/src/main/smp/sys/char.smp @@ -0,0 +1,9 @@ +// -*- mode: java; -*- + +val toupper = { u8 c -> + return c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c; +}; + +val tolower = { u8 c -> + return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; +}; diff --git a/chapter25/src/main/smp/sys/io.smp b/chapter25/src/main/smp/sys/io.smp index b94e89fa..3d6be512 100644 --- a/chapter25/src/main/smp/sys/io.smp +++ b/chapter25/src/main/smp/sys/io.smp @@ -3,30 +3,63 @@ // Simple I/O Library // Write byte array to stdout -val p = { u8[~] str -> - i64 ptr = str; // cast array base to i64 - return libc.write(1,ptr,str#); -}; - -val p_noInline = { u8[~] str -> - i64 ptr = str; // cast array base to i64 - return libc.write(1,ptr,str#); -}; +val p = { u8[~] str -> write(1,str); }; +val p_noInline = { u8[~] str -> write(1,str); }; -// Return stdin as a u8[]. -val stdin = { -> +// Return fd contents as a u8[]. +val read = { i32 fd -> var buf = new u8[8*1024]; i64 ptr = buf; int len = 0; while( true ) { - int rez = libc.read(0,ptr,buf#); - if( rez < 0 ) libc._exit(libc.errno); + i32 rez = libc.read(fd,ptr,buf#); + if( rez > buf# ) libc._exit(libc.errno); len += rez; if( rez < buf# ) break; libc._exit(-2); // Need to implement for more than 8K input } - // Compress - var dst = new u8[len]; - return Ary.copy(dst,0,buf,0,len); + var out = new u8[len]; + ary.copy(out,0,buf,0,len); +}; + +// Write all of str to fd. +val write = { i32 fd, u8[~] str -> + i64 ptr = str; // Convert array pointer to a i64 for the native call + libc.write(fd,ptr,str#); +}; + +// Write all of str to fd. +val writeOff = { i32 fd, u8[~] str, u32 off, u32 len -> + i64 ptr = str; // Convert array pointer to a i64 for the native call + ptr += off; // Skip offset + // Cap at available length + if( len > str# - off ) len = str# - off; + // Do the write + libc.write(fd,ptr,len); +}; + +// Return stdin as a u8[]. +val stdin = { -> read(0); }; + +// Create file for writing. Return fd, or -1 and errno has the error code +val create = { u8[~] str -> + i64 ptr = sys.aryu8.str0(str); + i32 perms = 6*64 + 6*8 + 6; // 0666 + return libc.creat(ptr, perms); +}; + +// Open file for reading. Return fd, or -1 and errno has the error code +val open = { u8[~] str -> + i64 ptr = sys.aryu8.str0(str); + return libc.open(ptr, sys.libc.O_RDONLY, 0); +}; + +// Close an open fd. Return 0, or -1 and errno has the error code +val close = { i32 fd -> return libc.close(fd); }; + +// Remove a file. Return 0, or -1 and errno has the error code +val remove = { u8[~] str -> + i64 ptr = sys.aryu8.str0(str); + return libc.unlink(ptr); }; diff --git a/chapter25/src/main/smp/sys/libc.smp b/chapter25/src/main/smp/sys/libc.smp index 42fc7313..6d750f7b 100644 --- a/chapter25/src/main/smp/sys/libc.smp +++ b/chapter25/src/main/smp/sys/libc.smp @@ -3,12 +3,36 @@ // libc bindings: // https://www.man7.org/linux/man-pages/man2/<libc call>.2.html +// The buffers are int-versions of zero-terminated strings. +// int buf = aryu8.str0("some_file"); +// buf mode perm-> fd +{ i64 i32 i32 -> i32 } open = "C"; +// buf perm -> fd +{ i64 i32 -> i32 } creat = "C"; + // fd buf len -> len -{ i32 i64 u32 -> u32 } write = "C"; +{ i32 i64 u32 -> i32 } write = "C"; // fd buf len -> len -{ i32 i64 u32 -> u32 } read = "C"; +{ i32 i64 u32 -> i32 } read = "C"; +// fd -> err +{ i32 -> i32 } close = "C"; +// path -> err +{ i64 -> i32 } unlink = "C"; + +i32 O_RDONLY = 0; +i32 O_WRONLY = 1; +i32 O_RDWR = 2; +i32 O_CREAT = 512; // 02000 on x86_64-pc-cygwin +i32 O_TRUNC = 1024; // 04000 on x86_64-pc-cygwin + +i32 STDIN = 0; +i32 STDOUT = 1; +i32 STDERR = 2; + // status { i32 -> i32 } _exit = "C"; +// Error return from many native calls +i32 errno = "C"; // addr len prot flags fd off -> void* { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; // mmap flags diff --git a/chapter25/src/main/smp/sys/Scan.smp b/chapter25/src/main/smp/sys/scan.smp index acf9fbb8..ba91003e 100644 --- a/chapter25/src/main/smp/sys/Scan.smp +++ b/chapter25/src/main/smp/sys/scan.smp @@ -1,14 +1,12 @@ // -*- mode: java; -*- // Scanner; a simple string parser. -struct Scan { +struct scan { int !x; // Cursor bool !bad; // True after a malformed token - u8[~] buf; // Immutable byte array, must be set in 2nd constructor + u8[~] buf; // Buffer to parse - new Scan = { u8[~] b -> - buf = b; - }; + new scan = { u8[~] b -> buf = b; }; // Skip whitespace val skip = { -> |
