Skip to content

Commit d189354

Browse files
adriwebcodex
andcommitted
[Z80] Handle byte-aligned extracts from wide eZ80 tuple registers.
Fix GlobalISel instruction selection for byte-aligned G_EXTRACT operations from R32_24, R48_24, and R64_24 tuple registers in eZ80 mode. At higher optimization levels, some code paths materialize 24-bit-mode wide tuples and then extract an 8-bit value at offset 24. The selector handled direct subregister extracts and a spill/reload fallback for smaller source classes, but it had no fallback for wide tuple classes, which caused instruction selection to abort on cases like: G_EXTRACT %src:r64_24(s64), 24 Teach selectExtract() to spill the tuple components of R32_24/R48_24/R64_24 to a temporary stack slot and reload the requested byte-aligned slice. Add a MIR regression test covering extraction of an 8-bit value from an R64_24 source at offset 24. Co-Authored-By: Codex CLI <codex@openai.com>
1 parent 9ccb15e commit d189354

2 files changed

Lines changed: 84 additions & 2 deletions

File tree

llvm/lib/Target/Z80/GISel/Z80InstructionSelector.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,8 +1952,56 @@ bool Z80InstructionSelector::selectExtract(MachineInstr &I,
19521952
const TargetRegisterClass *WideSrcRC = SrcRC;
19531953
unsigned Opc;
19541954
MachineIRBuilder MIB(I);
1955+
auto BuildStore = [&](unsigned StoreOpc, Register Reg, int FI,
1956+
unsigned ByteOffset,
1957+
unsigned SubReg = Z80::NoSubRegister) {
1958+
auto Store = MIB.buildInstr(StoreOpc).addFrameIndex(FI).addImm(ByteOffset);
1959+
if (SubReg == Z80::NoSubRegister)
1960+
Store.addReg(Reg);
1961+
else
1962+
Store.addReg(Reg, 0, SubReg);
1963+
return constrainSelectedInstRegOperands(*Store, TII, TRI, RBI);
1964+
};
1965+
auto BuildLoad = [&](unsigned LoadOpc, Register Reg, int FI,
1966+
unsigned ByteOffset) {
1967+
auto Load = MIB.buildInstr(LoadOpc, {Reg}, {})
1968+
.addFrameIndex(FI)
1969+
.addImm(ByteOffset);
1970+
return constrainSelectedInstRegOperands(*Load, TII, TRI, RBI);
1971+
};
19551972
int FI = MF.getFrameInfo().CreateStackObject(
19561973
TRI.getSpillSize(*SrcRC), TRI.getSpillAlign(*SrcRC), false);
1974+
if (STI.is24Bit() &&
1975+
(SrcRC == &Z80::R32_24RegClass || SrcRC == &Z80::R48_24RegClass ||
1976+
SrcRC == &Z80::R64_24RegClass)) {
1977+
if (!BuildStore(Z80::LD24or, SrcReg, FI, 0, Z80::sub_low24))
1978+
return false;
1979+
if (SrcRC == &Z80::R32_24RegClass) {
1980+
if (!BuildStore(Z80::LD8or, SrcReg, FI, 3, Z80::sub_high8))
1981+
return false;
1982+
} else {
1983+
if (!BuildStore(Z80::LD24or, SrcReg, FI, 3, Z80::sub_mid24))
1984+
return false;
1985+
if (SrcRC == &Z80::R64_24RegClass &&
1986+
!BuildStore(STI.has16BitEZ80Ops() ? Z80::LD16or : Z80::LD88or,
1987+
SrcReg, FI, 6, Z80::sub_word3))
1988+
return false;
1989+
}
1990+
1991+
if (DstRC == &Z80::R8RegClass)
1992+
Opc = Z80::LD8ro;
1993+
else if (DstRC == &Z80::R16RegClass)
1994+
Opc = STI.has16BitEZ80Ops() ? Z80::LD16ro : Z80::LD88ro;
1995+
else if (DstRC == &Z80::R24RegClass)
1996+
Opc = Z80::LD24ro;
1997+
else
1998+
return false;
1999+
2000+
if (!BuildLoad(Opc, DstReg, FI, Offset / 8))
2001+
return false;
2002+
I.eraseFromParent();
2003+
return true;
2004+
}
19572005
if (STI.is24Bit() && SrcRC == &Z80::R16RegClass) {
19582006
WideSrcRC = &Z80::R24RegClass;
19592007
if (SrcReg.isPhysical())
@@ -1973,7 +2021,8 @@ bool Z80InstructionSelector::selectExtract(MachineInstr &I,
19732021
Opc = Z80::LD24or;
19742022
else
19752023
return false;
1976-
MIB.buildInstr(Opc).addFrameIndex(FI).addImm(0).addReg(WideSrcReg);
2024+
if (!BuildStore(Opc, WideSrcReg, FI, 0))
2025+
return false;
19772026
if (STI.is24Bit() && DstRC == &Z80::R16RegClass) {
19782027
WideDstRC = &Z80::R24RegClass;
19792028
if (DstReg.isPhysical())
@@ -1990,7 +2039,8 @@ bool Z80InstructionSelector::selectExtract(MachineInstr &I,
19902039
Opc = Z80::LD24ro;
19912040
else
19922041
return false;
1993-
MIB.buildInstr(Opc, {WideDstReg}, {}).addFrameIndex(FI).addImm(Offset / 8);
2042+
if (!BuildLoad(Opc, WideDstReg, FI, Offset / 8))
2043+
return false;
19942044
if (WideDstReg != DstReg) {
19952045
if (!select(*MIB.buildTrunc(DstReg, WideDstReg)) ||
19962046
!RBI.constrainGenericRegister(WideDstReg, *WideDstRC, MRI))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# RUN: llc -O0 -mtriple=ez80-none-elf -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
2+
3+
--- |
4+
define i8 @extract_mid_byte() { entry: ret i8 0 }
5+
...
6+
7+
---
8+
name: extract_mid_byte
9+
alignment: 1
10+
legalized: true
11+
regBankSelected: true
12+
tracksRegLiveness: true
13+
body: |
14+
bb.0.entry:
15+
; CHECK-LABEL: name: extract_mid_byte
16+
; CHECK: LD24or
17+
; CHECK: LD24or
18+
; CHECK: LD{{16|88}}or
19+
; CHECK: LD8ro
20+
%0:gpr(s8) = G_CONSTANT i8 1
21+
%1:gpr(s8) = G_CONSTANT i8 0
22+
%2:gpr(s24) = G_MERGE_VALUES %0(s8), %1(s8), %1(s8)
23+
%3:gpr(s24) = G_CONSTANT i24 0
24+
%4:gpr(s16) = G_EXTRACT %3(s24), 0
25+
%5:gpr(s64) = G_IMPLICIT_DEF
26+
%6:gpr(s64) = G_INSERT %5, %2(s24), 0
27+
%7:gpr(s64) = G_INSERT %6, %3(s24), 24
28+
%8:gpr(s64) = G_INSERT %7, %4(s16), 48
29+
%9:gpr(s8) = G_EXTRACT %8(s64), 24
30+
$a = COPY %9(s8)
31+
RET24 implicit-def $spl, implicit $spl
32+
...

0 commit comments

Comments
 (0)