Inadvertent bank-drop fixed.

This commit is contained in:
Scott Duensing 2026-06-26 21:00:32 -05:00
parent 0643479903
commit 7f0c50304a

View file

@ -815,9 +815,17 @@ void W65816AsmPrinter::emitInstruction(const MachineInstr *MI) {
IsLong = IsLong || isFarGlobalOperand(AddrMO);
MCOperand Addr = lowerOperand(AddrMO, MCInstLowering);
if (IsLong && Addr.isImm()) {
// 16-bit pointer sign-extended into i32 imm — mask back to 16 bits
// so the encoded bank byte is 0. See STA8long for the rationale.
Addr = MCOperand::createImm(Addr.getImm() & 0xFFFFu);
// Sign-extended 16-bit pointer -> low 16 (bank 0); genuine 24-bit
// constant address -> keep low 24 (bank preserved). See STA8long.
int64_t Imm = Addr.getImm();
int16_t Lo16 = static_cast<int16_t>(Imm);
bool IsSext16 =
(Imm == static_cast<int64_t>(Lo16)) ||
(static_cast<uint64_t>(Imm) ==
static_cast<uint64_t>(static_cast<uint32_t>(static_cast<int32_t>(Lo16))));
Addr = MCOperand::createImm(
IsSext16 ? (static_cast<uint64_t>(Imm) & 0xFFFFu)
: (static_cast<uint64_t>(Imm) & 0xFFFFFFu));
}
emitSepM();
EmitToStreamer(*OutStreamer,
@ -878,15 +886,28 @@ void W65816AsmPrinter::emitInstruction(const MachineInstr *MI) {
emitSepM();
}
MCOperand Addr = lowerOperand(MI->getOperand(1), MCInstLowering);
// STA_Long takes a 24-bit absolute address. When the input is a
// const-int cast through a 16-bit pointer, TableGen sign-extends
// the 16-bit value into the i32 imm operand: 0xC035 (i16) becomes
// 0xFFFFC035 (i64). Mask to 16 bits to recover the original
// pointer; the resulting encoding has bank=0 explicit. Users who
// need a banked address should construct a far pointer rather than
// casting an int.
// STA_Long takes a 24-bit absolute address. Two cases reach here as
// an immediate:
// (a) a const-int cast through a 16-bit pointer, which TableGen
// SIGN-EXTENDS into the wider imm (0xC035 -> ...FFFFC035); the
// intended bank is 0, so recover the low 16 bits.
// (b) a genuine >16-bit constant address such as 0xE12000 (a fixed
// hardware register in bank $E1); this MUST keep its bank byte.
// Distinguish by the sign-extension round-trip: if the value equals
// the sign-extension of its low 16 bits it is case (a) -> low 16;
// otherwise it is case (b) -> keep the low 24 (bank included), dropping
// any above-bit-23 garbage. The check tolerates both i32-in-i64 and
// full-i64 sign-extended representations of the immediate.
if (IsLong && Addr.isImm()) {
Addr = MCOperand::createImm(Addr.getImm() & 0xFFFFu);
int64_t Imm = Addr.getImm();
int16_t Lo16 = static_cast<int16_t>(Imm);
bool IsSext16 =
(Imm == static_cast<int64_t>(Lo16)) ||
(static_cast<uint64_t>(Imm) ==
static_cast<uint64_t>(static_cast<uint32_t>(static_cast<int32_t>(Lo16))));
Addr = MCOperand::createImm(
IsSext16 ? (static_cast<uint64_t>(Imm) & 0xFFFFu)
: (static_cast<uint64_t>(Imm) & 0xFFFFFFu));
}
EmitToStreamer(*OutStreamer,
MCInstBuilder(IsLong ? W65816::STA_Long : W65816::STA_Abs)