i1-load fixed

This commit is contained in:
Scott Duensing 2026-06-25 01:36:27 -05:00
parent 09c99937e7
commit b56de5888e
3 changed files with 34 additions and 10 deletions

View file

@ -530,8 +530,6 @@ typedef struct FreeBlk {
static FreeBlk *freeList = (FreeBlk *)0; static FreeBlk *freeList = (FreeBlk *)0;
static char *bumpPtr = (char *)0; static char *bumpPtr = (char *)0;
static char *heapEnd = (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) { static void mallocInitOnce(void) {
if (bumpPtr) return; if (bumpPtr) return;
bumpPtr = __heap_start ? __heap_start : HEAP_DEFAULT_START; 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). // span days. CLOCKS_PER_SEC is 60 (defined in time.h).
// Toolbox-init flag, set by iigsToolboxInit(). time() guards on it. // Toolbox-init flag, set by iigsToolboxInit(). time() guards on it.
// volatile to dodge the i1-narrowing isel bug on bool flag globals. static unsigned short __toolboxInited = 0;
static volatile unsigned short __toolboxInited = 0;
void iigsToolboxInit(void) { void iigsToolboxInit(void) {
if (__toolboxInited) return; if (__toolboxInited) return;

View file

@ -58,10 +58,7 @@ typedef struct {
// --- State --- // --- State ---
// Declared volatile to defeat the GlobalOpt i1-narrowing pass that static int gResourceReady = 0;
// 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 ResourceFileT gFiles[IIGS_RES_MAX_FILES]; static ResourceFileT gFiles[IIGS_RES_MAX_FILES];
static HandleSlotT gHandles[IIGS_RES_MAX_HANDLES]; static HandleSlotT gHandles[IIGS_RES_MAX_HANDLES];

View file

@ -151,8 +151,13 @@ W65816TargetLowering::W65816TargetLowering(const TargetMachine &TM,
// every assignment is 0 or 1. Custom-lower so LowerLoad rewrites // every assignment is 0 or 1. Custom-lower so LowerLoad rewrites
// `zext/sext/anyext from i1` into a plain byte load + appropriate // `zext/sext/anyext from i1` into a plain byte load + appropriate
// mask. Both i16 and i8 result widths can appear, depending on // mask. Both i16 and i8 result widths can appear, depending on
// whether the consumer wants the value as `short` or `bool`. // whether the consumer wants the value as `short` or `bool`. Also
for (MVT ResVT : {MVT::i8, MVT::i16}) { // 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::ZEXTLOAD, ResVT, MVT::i1, Custom);
setLoadExtAction(ISD::SEXTLOAD, ResVT, MVT::i1, Custom); setLoadExtAction(ISD::SEXTLOAD, ResVT, MVT::i1, Custom);
setLoadExtAction(ISD::EXTLOAD, 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 // slot, global) or i32 (ptr32 deref); the recursive ADD handles
// address arithmetic correctly via LowerI32Bin. // address arithmetic correctly via LowerI32Bin.
if (VT == MVT::i32) { 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(); EVT PtrVT = Ptr.getValueType();
SDValue Two = DAG.getConstant(2, DL, PtrVT); SDValue Two = DAG.getConstant(2, DL, PtrVT);
SDValue Ptr2 = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, Two); SDValue Ptr2 = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, Two);