From b56de5888e0bcd4361349413066f30552da1673c Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 25 Jun 2026 01:36:27 -0500 Subject: [PATCH] i1-load fixed --- runtime/src/libc.c | 5 +-- runtime/src/resource.c | 5 +-- .../lib/Target/W65816/W65816ISelLowering.cpp | 34 +++++++++++++++++-- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/runtime/src/libc.c b/runtime/src/libc.c index 104a8df..68b1f1d 100644 --- a/runtime/src/libc.c +++ b/runtime/src/libc.c @@ -530,8 +530,6 @@ typedef struct FreeBlk { static FreeBlk *freeList = (FreeBlk *)0; static char *bumpPtr = (char *)0; static char *heapEnd = (char *)0; -// Use the bumpPtr nonzero-ness as the "initialized" flag — sidesteps -// an i1-narrowing isel bug on a dedicated bool flag. static void mallocInitOnce(void) { if (bumpPtr) return; bumpPtr = __heap_start ? __heap_start : HEAP_DEFAULT_START; @@ -782,8 +780,7 @@ void perror(const char *prefix) { // span days. CLOCKS_PER_SEC is 60 (defined in time.h). // Toolbox-init flag, set by iigsToolboxInit(). time() guards on it. -// volatile to dodge the i1-narrowing isel bug on bool flag globals. -static volatile unsigned short __toolboxInited = 0; +static unsigned short __toolboxInited = 0; void iigsToolboxInit(void) { if (__toolboxInited) return; diff --git a/runtime/src/resource.c b/runtime/src/resource.c index c31a523..f3e4ac6 100644 --- a/runtime/src/resource.c +++ b/runtime/src/resource.c @@ -58,10 +58,7 @@ typedef struct { // --- State --- -// Declared volatile to defeat the GlobalOpt i1-narrowing pass that -// otherwise produces an `i1, zext` load the W65816 backend can't select. -// (See MEMORY.md: feedback_i1_load_custom.md.) -static volatile int gResourceReady = 0; +static int gResourceReady = 0; static ResourceFileT gFiles[IIGS_RES_MAX_FILES]; static HandleSlotT gHandles[IIGS_RES_MAX_HANDLES]; diff --git a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp index cfd323d..cb3c042 100644 --- a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp +++ b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp @@ -151,8 +151,13 @@ W65816TargetLowering::W65816TargetLowering(const TargetMachine &TM, // every assignment is 0 or 1. Custom-lower so LowerLoad rewrites // `zext/sext/anyext from i1` into a plain byte load + appropriate // mask. Both i16 and i8 result widths can appear, depending on - // whether the consumer wants the value as `short` or `bool`. - for (MVT ResVT : {MVT::i8, MVT::i16}) { + // whether the consumer wants the value as `short` or `bool`. Also + // i32 result widths under ptr32: an `if (!g)` guard against a + // narrowed-to-i1 global feeds an i32 comparison, so the legalizer + // requests ZEXTLOAD/SEXTLOAD/EXTLOAD i32 ← i1. Without Custom action + // for the i32 result the legalizer leaves the load alone, isel has + // no matching pattern, and we get a "Cannot select" fatal at -O2. + for (MVT ResVT : {MVT::i8, MVT::i16, MVT::i32}) { setLoadExtAction(ISD::ZEXTLOAD, ResVT, MVT::i1, Custom); setLoadExtAction(ISD::SEXTLOAD, ResVT, MVT::i1, Custom); setLoadExtAction(ISD::EXTLOAD, ResVT, MVT::i1, Custom); @@ -1029,6 +1034,31 @@ SDValue W65816TargetLowering::LowerLoad(SDValue Op, // slot, global) or i32 (ptr32 deref); the recursive ADD handles // address arithmetic correctly via LowerI32Bin. if (VT == MVT::i32) { + EVT MemVT = Ld->getMemoryVT(); + // ZEXTLOAD/SEXTLOAD/EXTLOAD from i1 memory — GlobalOpt narrowed a + // byte global to i1 because every assignment is 0/1. The under- + // lying storage is still 1 byte: do ONE byte load, mask to a + // single bit, then zero/sign-extend to i32. Splitting into two + // i16 loads would over-read the global. + if (MemVT == MVT::i1) { + SDValue ByteLd = DAG.getExtLoad(ISD::ZEXTLOAD, DL, MVT::i16, Chain, + Ptr, MVT::i8, Ld->getMemOperand()); + SDValue Bit = DAG.getNode(ISD::AND, DL, MVT::i16, ByteLd, + DAG.getConstant(1, DL, MVT::i16)); + SDValue Lo, Hi; + if (Ld->getExtensionType() == ISD::SEXTLOAD) { + // i1 sign-extend: bit 0 -> -1 (= 0xFFFF in i16) -> {0xFFFF, + // 0xFFFF} in i32. bit 0 = 0 -> 0 -> {0, 0}. + Lo = DAG.getNode(ISD::SUB, DL, MVT::i16, + DAG.getConstant(0, DL, MVT::i16), Bit); + Hi = Lo; + } else { + Lo = Bit; + Hi = DAG.getConstant(0, DL, MVT::i16); + } + SDValue Wide = buildWide32(DAG, DL, Lo, Hi); + return DAG.getMergeValues({Wide, ByteLd.getValue(1)}, DL); + } EVT PtrVT = Ptr.getValueType(); SDValue Two = DAG.getConstant(2, DL, PtrVT); SDValue Ptr2 = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, Two);