More carry flag bugs fixed.
This commit is contained in:
parent
e139f2b3b8
commit
12de7c8a57
5 changed files with 260 additions and 36 deletions
Binary file not shown.
|
|
@ -1700,33 +1700,40 @@ FILE *fopen(const char *path, const char *mode) {
|
||||||
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
if (!stream) return 0;
|
if (!stream) return 0;
|
||||||
if (size == 0 || nmemb == 0) return 0;
|
if (size == 0 || nmemb == 0) return 0;
|
||||||
// size_t is u32 here, so the multiply itself can't overflow. The
|
// size_t is u32 here, so the multiply itself can't overflow.
|
||||||
// 0xFFFE cap is a "single 64KB bank" limit -- the underlying
|
|
||||||
// mem/GSOS backends address by 16-bit offset, so any single fread
|
|
||||||
// must fit in one bank.
|
|
||||||
if (nmemb > (size_t)0xFFFE / size) nmemb = (size_t)0xFFFE / size;
|
|
||||||
if (stream->kind == FILE_KIND_GSOS) {
|
if (stream->kind == FILE_KIND_GSOS) {
|
||||||
// Drain unget byte first if present.
|
// Drain unget byte first if present.
|
||||||
char *out = (char *)ptr;
|
char *out = (char *)ptr;
|
||||||
unsigned long total = (unsigned long)size * (unsigned long)nmemb;
|
unsigned long total = (unsigned long)size * (unsigned long)nmemb;
|
||||||
unsigned long offset = 0;
|
unsigned long offset = 0;
|
||||||
if (stream->unget >= 0 && total > 0) {
|
if (stream->unget >= 0 && total > 0) {
|
||||||
*out++ = (char)stream->unget;
|
*out = (char)stream->unget;
|
||||||
stream->unget = -1;
|
stream->unget = -1;
|
||||||
offset = 1;
|
offset = 1;
|
||||||
}
|
}
|
||||||
if (offset >= total) return offset / size;
|
// GS/OS Read in pieces of at most 0xFFFE bytes (one bank's worth,
|
||||||
__GsosIORecGS r = {
|
// as the stream layer has always asked for), until the whole
|
||||||
4, stream->refNum, out, total - offset, 0
|
// request is in or a read comes back short: one capped call used
|
||||||
};
|
// to return a short count for any request past 64 KB, which a
|
||||||
u16 rc = gsosRead(&r);
|
// caller reads as the end of the file.
|
||||||
unsigned long got = offset + r.transferCount;
|
while (offset < total) {
|
||||||
if (rc != 0 || r.transferCount < total - offset) {
|
unsigned long want = total - offset;
|
||||||
stream->eof = 1;
|
if (want > 0xFFFEul) want = 0xFFFEul;
|
||||||
if (rc != 0 && rc != 0x4C) { stream->err = 1; __gsosLatch(3, rc, stream->refNum, total - offset, r.transferCount); }
|
__GsosIORecGS r = {
|
||||||
|
4, stream->refNum, out + offset, want, 0
|
||||||
|
};
|
||||||
|
u16 rc = gsosRead(&r);
|
||||||
|
offset += r.transferCount;
|
||||||
|
if (rc != 0 || r.transferCount < want) {
|
||||||
|
stream->eof = 1;
|
||||||
|
if (rc != 0 && rc != 0x4C) { stream->err = 1; __gsosLatch(3, rc, stream->refNum, want, r.transferCount); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (size_t)(got / size);
|
return (size_t)(offset / size);
|
||||||
}
|
}
|
||||||
|
// The memory stream addresses its buffer by 16-bit offset: one bank.
|
||||||
|
if (nmemb > (size_t)0xFFFE / size) nmemb = (size_t)0xFFFE / size;
|
||||||
if (stream->kind != FILE_KIND_MEM) return 0;
|
if (stream->kind != FILE_KIND_MEM) return 0;
|
||||||
char *out = (char *)ptr;
|
char *out = (char *)ptr;
|
||||||
size_t items = 0;
|
size_t items = 0;
|
||||||
|
|
@ -1753,11 +1760,7 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
if (!stream) return 0;
|
if (!stream) return 0;
|
||||||
if (size == 0 || nmemb == 0) return 0;
|
if (size == 0 || nmemb == 0) return 0;
|
||||||
// size_t is u32 here, so the multiply itself can't overflow. The
|
// size_t is u32 here, so the multiply itself can't overflow.
|
||||||
// 0xFFFE cap is a "single 64KB bank" limit -- the underlying
|
|
||||||
// mem/GSOS backends address by 16-bit offset, so any single fwrite
|
|
||||||
// must fit in one bank.
|
|
||||||
if (nmemb > (size_t)0xFFFE / size) nmemb = (size_t)0xFFFE / size;
|
|
||||||
const char *in = (const char *)ptr;
|
const char *in = (const char *)ptr;
|
||||||
if (stream->kind == FILE_KIND_STDOUT || stream->kind == FILE_KIND_STDERR) {
|
if (stream->kind == FILE_KIND_STDOUT || stream->kind == FILE_KIND_STDERR) {
|
||||||
size_t items = 0;
|
size_t items = 0;
|
||||||
|
|
@ -1770,18 +1773,29 @@ size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
|
||||||
if (stream->kind == FILE_KIND_GSOS) {
|
if (stream->kind == FILE_KIND_GSOS) {
|
||||||
if (!stream->writable) { stream->err = 1; return 0; }
|
if (!stream->writable) { stream->err = 1; return 0; }
|
||||||
unsigned long total = (unsigned long)size * (unsigned long)nmemb;
|
unsigned long total = (unsigned long)size * (unsigned long)nmemb;
|
||||||
__GsosIORecGS r = { 4, stream->refNum, (void *)in, total, 0 };
|
unsigned long done = 0;
|
||||||
u16 wrc = gsosWrite(&r);
|
// GS/OS Write in pieces of at most 0xFFFE bytes, until the whole
|
||||||
if (wrc != 0) {
|
// request is out or a write comes back short (see fread).
|
||||||
stream->err = 1;
|
while (done < total) {
|
||||||
__gsosLatch(4, wrc, stream->refNum, total, r.transferCount);
|
unsigned long want = total - done;
|
||||||
return (size_t)(r.transferCount / size);
|
if (want > 0xFFFEul) want = 0xFFFEul;
|
||||||
|
__GsosIORecGS r = { 4, stream->refNum, (void *)(in + done), want, 0 };
|
||||||
|
u16 wrc = gsosWrite(&r);
|
||||||
|
done += r.transferCount;
|
||||||
|
if (wrc != 0) {
|
||||||
|
stream->err = 1;
|
||||||
|
__gsosLatch(4, wrc, stream->refNum, want, r.transferCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r.transferCount < want) {
|
||||||
|
__gsosLatch(4, 0, stream->refNum, want, r.transferCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (r.transferCount < total) {
|
return (size_t)(done / size);
|
||||||
__gsosLatch(4, 0, stream->refNum, total, r.transferCount);
|
|
||||||
}
|
|
||||||
return (size_t)(r.transferCount / size);
|
|
||||||
}
|
}
|
||||||
|
// The memory stream addresses its buffer by 16-bit offset: one bank.
|
||||||
|
if (nmemb > (size_t)0xFFFE / size) nmemb = (size_t)0xFFFE / size;
|
||||||
if (stream->kind != FILE_KIND_MEM) return 0;
|
if (stream->kind != FILE_KIND_MEM) return 0;
|
||||||
if (!stream->writable) { stream->err = 1; return 0; }
|
if (!stream->writable) { stream->err = 1; return 0; }
|
||||||
size_t items = 0;
|
size_t items = 0;
|
||||||
|
|
|
||||||
|
|
@ -9350,6 +9350,94 @@ EOF
|
||||||
rm -rf "$bbDir"
|
rm -rf "$bbDir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# GS/OS fwrite and fread move a request past 64 KB in one call: libc issues
|
||||||
|
# GS/OS Write / Read in pieces of at most 0xFFFE bytes until the whole
|
||||||
|
# request is done. It used to cap the request itself at 0xFFFE bytes, so
|
||||||
|
# one fwrite of 66 KB wrote 65534 bytes and returned short (JoeyLib's
|
||||||
|
# jlSaveWrite of anything past 64 KB failed). 66 KB puts 2050 bytes in the
|
||||||
|
# second piece and keeps the run inside runViaFinder's 90 s check (an
|
||||||
|
# 80 KB one with a multiply per byte did not finish). $70 = 0x55 the
|
||||||
|
# write returned the full count, $71 = 0x66 the read did and the bytes
|
||||||
|
# match. Skips under SMOKE_SKIP_GSOSBIGIO=1.
|
||||||
|
if [ "${SMOKE_SKIP_GSOSBIGIO:-0}" != "1" ] \
|
||||||
|
&& [ -x "$CLANG" ] && [ -x "$CADIUS" ] && [ -f "$SYSDISK" ] \
|
||||||
|
&& command -v mame >/dev/null 2>&1; then
|
||||||
|
log "check: GS/OS fwrite/fread of 66 KB in one call"
|
||||||
|
bioDir="$(mktemp -d)"
|
||||||
|
cat > "$bioDir/bigIo.c" <<'EOF'
|
||||||
|
// One fwrite and one fread of 66 KB to a GS/OS file, from Memory Manager
|
||||||
|
// blocks. $70 = 0x55 the write returned the full count, $71 = 0x66 the
|
||||||
|
// read did and the bytes match what was written.
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <iigs/toolbox.h>
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned long u32;
|
||||||
|
#define MB ((volatile u8 *)0x70)
|
||||||
|
#define FILE_LEN 0x10800UL
|
||||||
|
#define NH_LOCKED 0x8000u
|
||||||
|
|
||||||
|
|
||||||
|
static u8 pat(u32 i) {
|
||||||
|
return (u8)((u8)i * 7u + (u8)(i >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
u16 id = MMStartUp();
|
||||||
|
void **hw = (void **)NewHandle(FILE_LEN, id, NH_LOCKED, 0);
|
||||||
|
void **hr = (void **)NewHandle(FILE_LEN, id, NH_LOCKED, 0);
|
||||||
|
u8 *wr;
|
||||||
|
u8 *rd;
|
||||||
|
u32 i;
|
||||||
|
FILE *f;
|
||||||
|
if (!hw || !hr || !*hw || !*hr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
wr = (u8 *)*hw;
|
||||||
|
rd = (u8 *)*hr;
|
||||||
|
for (i = 0; i < FILE_LEN; i++) {
|
||||||
|
wr[i] = pat(i);
|
||||||
|
rd[i] = 0;
|
||||||
|
}
|
||||||
|
f = fopen("/DATA/BIGIO", "w");
|
||||||
|
if (f && fwrite(wr, 1u, FILE_LEN, f) == FILE_LEN && fclose(f) == 0) {
|
||||||
|
MB[0] = 0x55u;
|
||||||
|
f = fopen("/DATA/BIGIO", "r");
|
||||||
|
if (f && fread(rd, 1u, FILE_LEN, f) == FILE_LEN && fclose(f) == 0 &&
|
||||||
|
memcmp(rd, wr, FILE_LEN) == 0) {
|
||||||
|
MB[1] = 0x66u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
"$CLANG" --target=w65816 -I"$PROJECT_ROOT/runtime/include" -O2 -ffunction-sections \
|
||||||
|
-c "$bioDir/bigIo.c" -o "$bioDir/bigIo.o"
|
||||||
|
"$PROJECT_ROOT/tools/link816" -o "$bioDir/bigIo.bin" --text-base 0x1000 --full-bank \
|
||||||
|
--map "$bioDir/bigIo.map" --reloc-out "$bioDir/bigIo.reloc" \
|
||||||
|
"$PROJECT_ROOT/runtime/crt0Gsos.o" "$bioDir/bigIo.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/libc.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/snprintf.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/extras.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/softFloat.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/softDouble.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/iigsGsos.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/iigsToolbox.o" "$PROJECT_ROOT/runtime/iigsToolboxExtra.o" \
|
||||||
|
"$PROJECT_ROOT/runtime/libgcc.o" >/dev/null \
|
||||||
|
|| die "GS/OS 66 KB I/O smoke: link failed"
|
||||||
|
"$PROJECT_ROOT/tools/omfEmit" --input "$bioDir/bigIo.bin" --map "$bioDir/bigIo.map" \
|
||||||
|
--base 0x1000 --entry __start --output "$bioDir/bigIo.omf" \
|
||||||
|
--name HELLO --expressload --relocs "$bioDir/bigIo.reloc" >/dev/null 2>&1
|
||||||
|
[ -s "$bioDir/bigIo.omf" ] || die "GS/OS 66 KB I/O smoke: omfEmit produced no OMF"
|
||||||
|
if ! bash "$PROJECT_ROOT/scripts/runViaFinder.sh" "$bioDir/bigIo.omf" \
|
||||||
|
--check 0x70=0x55 0x71=0x66 >/dev/null 2>&1; then
|
||||||
|
die "GS/OS 66 KB I/O smoke FAILED (\$70 fwrite count, \$71 fread count + bytes)"
|
||||||
|
fi
|
||||||
|
rm -rf "$bioDir"
|
||||||
|
fi
|
||||||
|
|
||||||
# GS/OS program exit: returning from main is exit(main's value), which must
|
# GS/OS program exit: returning from main is exit(main's value), which must
|
||||||
# run the atexit handlers (last registered first), then the C++ dtors, then
|
# run the atexit handlers (last registered first), then the C++ dtors, then
|
||||||
# QUIT back to the Finder. crt0Gsos used to issue QUIT with the pointer
|
# QUIT back to the Finder. crt0Gsos used to issue QUIT with the pointer
|
||||||
|
|
|
||||||
|
|
@ -956,8 +956,8 @@ bool W65816StackSlotCleanup::runOnMachineFunction(MachineFunction &MF) {
|
||||||
// real CMP. NOTE: the *fi variants (ANDfi/ORAfi/EORfi) and
|
// real CMP. NOTE: the *fi variants (ANDfi/ORAfi/EORfi) and
|
||||||
// ADC/SBC DO model Defs=[P] and can legitimately be the branch's
|
// ADC/SBC DO model Defs=[P] and can legitimately be the branch's
|
||||||
// flag source, so they are handled by $p liveness and are NOT
|
// flag source, so they are handled by $p liveness and are NOT
|
||||||
// listed here; same for the shifts, which the shift-carry idiom
|
// listed here. (The one-bit shift pseudos are listed below:
|
||||||
// reads directly.
|
// they model no Defs=[P] either.)
|
||||||
Opc == W65816::EORi16imm || Opc == W65816::EORabs ||
|
Opc == W65816::EORi16imm || Opc == W65816::EORabs ||
|
||||||
// INC/DEC in every form. None of them models Defs=[P] either,
|
// INC/DEC in every form. None of them models Defs=[P] either,
|
||||||
// so at this pass's point no branch can take its flags from
|
// so at this pass's point no branch can take its flags from
|
||||||
|
|
@ -1015,6 +1015,22 @@ bool W65816StackSlotCleanup::runOnMachineFunction(MachineFunction &MF) {
|
||||||
// the BNE read the last AND's Z, so the break never fired
|
// the BNE read the last AND's Z, so the break never fired
|
||||||
// (JoeyLib's IIgs serial-loss probe, 2026-09-28).
|
// (JoeyLib's IIgs serial-loss probe, 2026-09-28).
|
||||||
Opc == W65816::SRL8A || Opc == W65816::SHL8A ||
|
Opc == W65816::SRL8A || Opc == W65816::SHL8A ||
|
||||||
|
// The shift pseudos, which lower in the AsmPrinter to ASL A /
|
||||||
|
// LSR A (ASRA16: CMP #$8000 ; ROR A; the *15A forms: a shift,
|
||||||
|
// LDA #0 and a rotate). They rewrite N, Z and C, model no
|
||||||
|
// Defs=[P], and are cheap, so Machine CSE's PRE hoists one to
|
||||||
|
// the end of a dominating block -- between its CMP and the
|
||||||
|
// terminator. Live symptom: `for (row = 0; row < h; row++)`
|
||||||
|
// after `dstByteStart = dx >> 1` lowered to
|
||||||
|
// `cmp #$8001 ; lda n,s ; lsr a ; sta m,s ; bcc exit`; the BCC
|
||||||
|
// read bit 0 of dx, so every even-x interpreted sprite draw
|
||||||
|
// skipped its rows (JoeyLib's IIgs sprite interpreter,
|
||||||
|
// 2026-10-13). They are carry corrupters too (below).
|
||||||
|
Opc == W65816::ASLA16 || Opc == W65816::LSRA16 ||
|
||||||
|
Opc == W65816::ASLA8 || Opc == W65816::LSRA8 ||
|
||||||
|
Opc == W65816::ASRA16 ||
|
||||||
|
Opc == W65816::SRL15A || Opc == W65816::SHL15A ||
|
||||||
|
Opc == W65816::SRA15A ||
|
||||||
Opc == W65816::XBA || Opc == W65816::XBA16 ||
|
Opc == W65816::XBA || Opc == W65816::XBA16 ||
|
||||||
Opc == W65816::NEGA16 || Opc == W65816::NEGA8 ||
|
Opc == W65816::NEGA16 || Opc == W65816::NEGA8 ||
|
||||||
// Every other load, pseudo or already lowered: a load is never
|
// Every other load, pseudo or already lowered: a load is never
|
||||||
|
|
@ -1051,10 +1067,16 @@ bool W65816StackSlotCleanup::runOnMachineFunction(MachineFunction &MF) {
|
||||||
Opc == W65816::CMP_StackRel;
|
Opc == W65816::CMP_StackRel;
|
||||||
};
|
};
|
||||||
// The subset of corrupters that also rewrite C/V, and so must be
|
// The subset of corrupters that also rewrite C/V, and so must be
|
||||||
// wrapped even for a BCC/BCS/BVC/BVS. Only ADDframe today: every
|
// wrapped even for a BCC/BCS/BVC/BVS: ADDframe (TSC ; CLC ; ADC) and
|
||||||
// other entry in isLdaLike touches N/Z alone.
|
// the shift pseudos (see isLdaLike). Every other entry in isLdaLike
|
||||||
|
// touches N/Z alone.
|
||||||
auto isCarryCorrupting = [](unsigned Opc) {
|
auto isCarryCorrupting = [](unsigned Opc) {
|
||||||
return Opc == W65816::ADDframe;
|
return Opc == W65816::ADDframe ||
|
||||||
|
Opc == W65816::ASLA16 || Opc == W65816::LSRA16 ||
|
||||||
|
Opc == W65816::ASLA8 || Opc == W65816::LSRA8 ||
|
||||||
|
Opc == W65816::ASRA16 ||
|
||||||
|
Opc == W65816::SRL15A || Opc == W65816::SHL15A ||
|
||||||
|
Opc == W65816::SRA15A;
|
||||||
};
|
};
|
||||||
for (MachineInstr *Br : Branches) {
|
for (MachineInstr *Br : Branches) {
|
||||||
unsigned BrOpc = Br->getOpcode();
|
unsigned BrOpc = Br->getOpcode();
|
||||||
|
|
|
||||||
100
src/llvm/test/CodeGen/W65816/shift-flag-corrupt-wrap.mir
Normal file
100
src/llvm/test/CodeGen/W65816/shift-flag-corrupt-wrap.mir
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
# Pin: the shift pseudos (ASLA16 / LSRA16 / ASLA8 / LSRA8 / ASRA16 and the
|
||||||
|
# *15A forms) count as flag CORRUPTION -- of N/Z and of C -- in the PHP/PLP
|
||||||
|
# wrap (W65816StackSlotCleanup Pass -2.5), not as the flag-defining test.
|
||||||
|
#
|
||||||
|
# They lower in the AsmPrinter to ASL A / LSR A (ASRA16: CMP #$8000 ; ROR A;
|
||||||
|
# the *15A forms: a shift, LDA #0 and a rotate), which rewrite N, Z and C,
|
||||||
|
# but model no Defs=[P]. Being cheap, Machine CSE's PRE hoisted one to the
|
||||||
|
# end of a dominating block -- between its CMP and the terminator -- and
|
||||||
|
# isFlagDefining's default then took the shift for THE test: the walk
|
||||||
|
# stopped there and the pass declined to wrap.
|
||||||
|
#
|
||||||
|
# Live symptom (JoeyLib's IIgs sprite interpreter, 2026-10-13): a loop guard
|
||||||
|
# `row < h` after `dstByteStart = dx >> 1` lowered to
|
||||||
|
# cmp #$8001 ; lda n,s ; lsr a ; sta m,s ; bcc exit
|
||||||
|
# so the BCC read bit 0 of dx and every even-x draw skipped its rows.
|
||||||
|
#
|
||||||
|
# lsra16_carry: the reported shape under a BCC. The reload in front of the
|
||||||
|
# shift only corrupts N/Z, harmless to a carry branch, so the
|
||||||
|
# wrap covers the shift alone; the spill after it stays outside.
|
||||||
|
# asla16_nz: an ASLA16 under a BNE: the reload corrupts Z too, so the wrap
|
||||||
|
# starts at it.
|
||||||
|
#
|
||||||
|
# Each case reads %stack.2 after the branch so its store survives the pass's
|
||||||
|
# never-read slot sweep, and the branch targets take X live in, so the wrap
|
||||||
|
# cannot be replaced by the TAX ... CPX #k form (cmp-via-x.mir).
|
||||||
|
#
|
||||||
|
# RUN: llc -mtriple=w65816 -run-pass=w65816-stack-slot-cleanup -o - %s | FileCheck %s
|
||||||
|
--- |
|
||||||
|
target triple = "w65816"
|
||||||
|
define void @lsra16_carry() { ret void }
|
||||||
|
define void @asla16_nz() { ret void }
|
||||||
|
...
|
||||||
|
---
|
||||||
|
# CHECK-LABEL: name: lsra16_carry
|
||||||
|
# CHECK: CMPi16imm killed $a, 32769, implicit-def $p
|
||||||
|
# CHECK-NEXT: $a = LDAfi %stack.1, 0
|
||||||
|
# CHECK-NEXT: PHP
|
||||||
|
# CHECK-NEXT: $a = LSRA16 killed $a
|
||||||
|
# CHECK-NEXT: PLP
|
||||||
|
# CHECK-NEXT: STAfi killed $a, %stack.2, 0
|
||||||
|
# CHECK-NEXT: BCC %bb.1, implicit $p
|
||||||
|
name: lsra16_carry
|
||||||
|
tracksRegLiveness: false
|
||||||
|
stack:
|
||||||
|
- { id: 0, size: 2, alignment: 1 }
|
||||||
|
- { id: 1, size: 2, alignment: 1 }
|
||||||
|
- { id: 2, size: 2, alignment: 1 }
|
||||||
|
body: |
|
||||||
|
bb.0:
|
||||||
|
successors: %bb.1, %bb.2
|
||||||
|
$a = LDAfi %stack.0, 0
|
||||||
|
CMPi16imm killed $a, 32769, implicit-def $p
|
||||||
|
$a = LDAfi %stack.1, 0
|
||||||
|
$a = LSRA16 killed $a
|
||||||
|
STAfi killed $a, %stack.2, 0, implicit-def $a
|
||||||
|
BCC %bb.1, implicit $p
|
||||||
|
BRA %bb.2
|
||||||
|
bb.1:
|
||||||
|
liveins: $x
|
||||||
|
$a = LDAfi %stack.2, 0
|
||||||
|
RTL
|
||||||
|
bb.2:
|
||||||
|
liveins: $x
|
||||||
|
$a = LDAfi %stack.2, 0
|
||||||
|
RTL
|
||||||
|
...
|
||||||
|
---
|
||||||
|
# CHECK-LABEL: name: asla16_nz
|
||||||
|
# CHECK: CMPi16imm killed $a, 3, implicit-def $p
|
||||||
|
# CHECK-NEXT: PHP
|
||||||
|
# CHECK-NEXT: $a = LDAfi %stack.1, 0
|
||||||
|
# CHECK-NEXT: $a = ASLA16 killed $a
|
||||||
|
# CHECK-NEXT: PLP
|
||||||
|
# CHECK-NEXT: STAfi killed $a, %stack.2, 0
|
||||||
|
# CHECK-NEXT: BNE %bb.1, implicit $p
|
||||||
|
name: asla16_nz
|
||||||
|
tracksRegLiveness: false
|
||||||
|
stack:
|
||||||
|
- { id: 0, size: 2, alignment: 1 }
|
||||||
|
- { id: 1, size: 2, alignment: 1 }
|
||||||
|
- { id: 2, size: 2, alignment: 1 }
|
||||||
|
body: |
|
||||||
|
bb.0:
|
||||||
|
successors: %bb.1, %bb.2
|
||||||
|
$a = LDAfi %stack.0, 0
|
||||||
|
CMPi16imm killed $a, 3, implicit-def $p
|
||||||
|
$a = LDAfi %stack.1, 0
|
||||||
|
$a = ASLA16 killed $a
|
||||||
|
STAfi killed $a, %stack.2, 0, implicit-def $a
|
||||||
|
BNE %bb.1, implicit $p
|
||||||
|
BRA %bb.2
|
||||||
|
bb.1:
|
||||||
|
liveins: $x
|
||||||
|
$a = LDAfi %stack.2, 0
|
||||||
|
RTL
|
||||||
|
bb.2:
|
||||||
|
liveins: $x
|
||||||
|
$a = LDAfi %stack.2, 0
|
||||||
|
RTL
|
||||||
|
...
|
||||||
Loading…
Add table
Reference in a new issue