Skip to content

Commit b58e0a1

Browse files
author
Vasileios Porpodas
committed
[Spill2Reg] Adds code generation for 8/16bit spill/reloads in x86
This patch adds support for 8/16 bit values in x86. Original review: https://reviews.llvm.org/D118305
1 parent b2910a5 commit b58e0a1

File tree

7 files changed

+144
-16
lines changed

7 files changed

+144
-16
lines changed

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11020,6 +11020,8 @@ bool X86InstrInfo::isSpill2RegProfitable(const MachineInstr *MI,
1102011020

1102111021
static unsigned getInsertOrExtractOpcode(unsigned Bits, bool Insert) {
1102211022
switch (Bits) {
11023+
case 8:
11024+
case 16:
1102311025
case 32:
1102411026
return Insert ? X86::MOVDI2PDIrr : X86::MOVPDI2DIrr;
1102511027
case 64:
@@ -11029,6 +11031,36 @@ static unsigned getInsertOrExtractOpcode(unsigned Bits, bool Insert) {
1102911031
}
1103011032
}
1103111033

11034+
/// \Returns the subreg index for a getting a subregister of \p SubregBits from
11035+
/// a register of \p RegBits.
11036+
static unsigned spill2RegGetSubregIdx(unsigned RegBits, unsigned SubregBits) {
11037+
assert(RegBits > SubregBits && "From expected to cover To");
11038+
switch (SubregBits) {
11039+
case 32:
11040+
return X86::sub_32bit;
11041+
case 16:
11042+
return X86::sub_16bit;
11043+
case 8:
11044+
return X86::sub_8bit;
11045+
default:
11046+
llvm_unreachable("FIXME");
11047+
}
11048+
}
11049+
11050+
std::optional<MCRegister>
11051+
X86InstrInfo::getMovdCompatibleReg(MCRegister OldReg, uint32_t OldRegBits,
11052+
const TargetRegisterInfo *TRI) const {
11053+
if (OldRegBits != 8 && OldRegBits != 16)
11054+
return std::nullopt;
11055+
// The register class of the register that movd can handle.
11056+
const TargetRegisterClass *NewRegClass =
11057+
TRI->getRegClass(X86::GR32RegClassID);
11058+
unsigned NewRegBits = TRI->getRegSizeInBits(*NewRegClass);
11059+
unsigned SubIdx = spill2RegGetSubregIdx(NewRegBits, OldRegBits);
11060+
MCRegister NewReg = TRI->getMatchingSuperReg(OldReg, SubIdx, NewRegClass);
11061+
return NewReg;
11062+
}
11063+
1103211064
MachineInstr *X86InstrInfo::spill2RegInsertToS2RReg(
1103311065
Register S2RReg, Register SrcReg, int OperationBits, MachineBasicBlock *MBB,
1103411066
MachineBasicBlock::iterator InsertBeforeIt,
@@ -11037,6 +11069,12 @@ MachineInstr *X86InstrInfo::spill2RegInsertToS2RReg(
1103711069
unsigned InsertOpcode =
1103811070
getInsertOrExtractOpcode(OperationBits, true /*insert*/);
1103911071
const MCInstrDesc &InsertMCID = get(InsertOpcode);
11072+
// `movd` does not support 8/16 bit operands. Instead, we use a 32-bit
11073+
// register. For example:
11074+
// $al = ...
11075+
// $xmm0 = MOVPDI2DIrr $eax
11076+
if (auto NewReg = getMovdCompatibleReg(SrcReg, OperationBits, TRI))
11077+
SrcReg = *NewReg;
1104011078
MachineInstr *InsertMI =
1104111079
BuildMI(*MBB, InsertBeforeIt, DL, InsertMCID, S2RReg).addReg(SrcReg);
1104211080
return InsertMI;
@@ -11050,6 +11088,12 @@ MachineInstr *X86InstrInfo::spill2RegExtractFromS2RReg(
1105011088
unsigned ExtractOpcode =
1105111089
getInsertOrExtractOpcode(OperationBits, false /*extract*/);
1105211090
const MCInstrDesc &ExtractMCID = get(ExtractOpcode);
11091+
// `movd` does not support 8/16 bit operands. Instead, we use a 32-bit
11092+
// register. For example:
11093+
// $eax = MOVPDI2DIrr $xmm0
11094+
// ... = $al
11095+
if (auto NewReg = getMovdCompatibleReg(DstReg, OperationBits, TRI))
11096+
DstReg = *NewReg;
1105311097
MachineInstr *ExtractMI =
1105411098
BuildMI(*InsertMBB, InsertBeforeIt, DL, ExtractMCID, DstReg)
1105511099
.addReg(S2RReg);

llvm/lib/Target/X86/X86InstrInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,10 @@ class X86InstrInfo final : public X86GenInstrInfo {
744744
const TargetRegisterInfo *TRI,
745745
const MachineRegisterInfo *MRI) const override;
746746

747+
std::optional<MCRegister>
748+
getMovdCompatibleReg(MCRegister OldReg, uint32_t OldRegBits,
749+
const TargetRegisterInfo *TRI) const;
750+
747751
MachineInstr *
748752
spill2RegInsertToS2RReg(Register S2RReg, Register SrcReg, int OperationBits,
749753
MachineBasicBlock *MBB,

llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ bool X86RegisterInfo::isLegalToSpill2Reg(Register Reg,
12661266
switch (TRI->getRegSizeInBits(Reg, *MRI)) {
12671267
case 64:
12681268
case 32:
1269+
case 16:
1270+
case 8:
12691271
return true;
12701272
}
12711273
return false;

llvm/test/CodeGen/X86/spill2reg_end_to_end_16bit.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
6767
; CHECK-NEXT: .cfi_offset %r14, -32
6868
; CHECK-NEXT: .cfi_offset %r15, -24
6969
; CHECK-NEXT: .cfi_offset %rbp, -16
70-
; CHECK-NEXT: movzwl D0(%rip), %eax
70+
; CHECK-NEXT: movw D0(%rip), %ax
7171
; CHECK-NEXT: movw %ax, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
7272
; CHECK-NEXT: movzwl D1(%rip), %ecx
7373
; CHECK-NEXT: movzwl D2(%rip), %edx
@@ -83,12 +83,12 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
8383
; CHECK-NEXT: movzwl D12(%rip), %r15d
8484
; CHECK-NEXT: movzwl D13(%rip), %r12d
8585
; CHECK-NEXT: movzwl D14(%rip), %r13d
86-
; CHECK-NEXT: movzwl D15(%rip), %eax
87-
; CHECK-NEXT: movw %ax, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
88-
; CHECK-NEXT: movzwl D16(%rip), %eax
89-
; CHECK-NEXT: movw %ax, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
90-
; CHECK-NEXT: movzwl D17(%rip), %eax
86+
; CHECK-NEXT: movw D15(%rip), %ax
87+
; CHECK-NEXT: movd %eax, %xmm0
88+
; CHECK-NEXT: movw D16(%rip), %ax
9189
; CHECK-NEXT: movw %ax, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
90+
; CHECK-NEXT: movw D17(%rip), %ax
91+
; CHECK-NEXT: movd %eax, %xmm1
9292
; CHECK-NEXT: movzwl D18(%rip), %eax
9393
; CHECK-NEXT: movw %ax, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
9494
; CHECK-NEXT: #APP
@@ -109,11 +109,11 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
109109
; CHECK-NEXT: movw %r15w, U12(%rip)
110110
; CHECK-NEXT: movw %r12w, U13(%rip)
111111
; CHECK-NEXT: movw %r13w, U14(%rip)
112-
; CHECK-NEXT: movzwl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 2-byte Folded Reload
112+
; CHECK-NEXT: movd %xmm0, %eax
113113
; CHECK-NEXT: movw %ax, U15(%rip)
114114
; CHECK-NEXT: movzwl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 2-byte Folded Reload
115115
; CHECK-NEXT: movw %ax, U16(%rip)
116-
; CHECK-NEXT: movzwl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 2-byte Folded Reload
116+
; CHECK-NEXT: movd %xmm1, %eax
117117
; CHECK-NEXT: movw %ax, U17(%rip)
118118
; CHECK-NEXT: movzwl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 2-byte Folded Reload
119119
; CHECK-NEXT: movw %ax, U18(%rip)

llvm/test/CodeGen/X86/spill2reg_end_to_end_8bit.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
6767
; CHECK-NEXT: .cfi_offset %r14, -32
6868
; CHECK-NEXT: .cfi_offset %r15, -24
6969
; CHECK-NEXT: .cfi_offset %rbp, -16
70-
; CHECK-NEXT: movzbl D0(%rip), %eax
70+
; CHECK-NEXT: movb D0(%rip), %al
7171
; CHECK-NEXT: movb %al, {{[-0-9]+}}(%r{{[sb]}}p) # 1-byte Spill
7272
; CHECK-NEXT: movzbl D1(%rip), %ecx
7373
; CHECK-NEXT: movzbl D2(%rip), %edx
@@ -83,12 +83,12 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
8383
; CHECK-NEXT: movzbl D12(%rip), %r15d
8484
; CHECK-NEXT: movzbl D13(%rip), %r12d
8585
; CHECK-NEXT: movzbl D14(%rip), %r13d
86-
; CHECK-NEXT: movzbl D15(%rip), %eax
87-
; CHECK-NEXT: movb %al, {{[-0-9]+}}(%r{{[sb]}}p) # 1-byte Spill
88-
; CHECK-NEXT: movzbl D16(%rip), %eax
89-
; CHECK-NEXT: movb %al, {{[-0-9]+}}(%r{{[sb]}}p) # 1-byte Spill
90-
; CHECK-NEXT: movzbl D17(%rip), %eax
86+
; CHECK-NEXT: movb D15(%rip), %al
87+
; CHECK-NEXT: movd %eax, %xmm0
88+
; CHECK-NEXT: movb D16(%rip), %al
9189
; CHECK-NEXT: movb %al, {{[-0-9]+}}(%r{{[sb]}}p) # 1-byte Spill
90+
; CHECK-NEXT: movb D17(%rip), %al
91+
; CHECK-NEXT: movd %eax, %xmm1
9292
; CHECK-NEXT: movzbl D18(%rip), %eax
9393
; CHECK-NEXT: movb %al, {{[-0-9]+}}(%r{{[sb]}}p) # 1-byte Spill
9494
; CHECK-NEXT: #APP
@@ -109,11 +109,11 @@ define dso_local void @_Z5spillv() local_unnamed_addr #0 {
109109
; CHECK-NEXT: movb %r15b, U12(%rip)
110110
; CHECK-NEXT: movb %r12b, U13(%rip)
111111
; CHECK-NEXT: movb %r13b, U14(%rip)
112-
; CHECK-NEXT: movzbl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 1-byte Folded Reload
112+
; CHECK-NEXT: movd %xmm0, %eax
113113
; CHECK-NEXT: movb %al, U15(%rip)
114114
; CHECK-NEXT: movzbl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 1-byte Folded Reload
115115
; CHECK-NEXT: movb %al, U16(%rip)
116-
; CHECK-NEXT: movzbl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 1-byte Folded Reload
116+
; CHECK-NEXT: movd %xmm1, %eax
117117
; CHECK-NEXT: movb %al, U17(%rip)
118118
; CHECK-NEXT: movzbl {{[-0-9]+}}(%r{{[sb]}}p), %eax # 1-byte Folded Reload
119119
; CHECK-NEXT: movb %al, U18(%rip)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc %s -o - -mtriple=x86_64-unknown-linux -enable-spill2reg -mattr=+sse4.1 --run-pass=spill2reg -simplify-mir -spill2reg-mem-instrs=0 -spill2reg-vec-instrs=99999 | FileCheck %s
3+
4+
# Simple test with a single 16-bit spill-reload pair:
5+
# spill stack.0
6+
# reload stack.0
7+
8+
--- |
9+
@D0 = dso_local local_unnamed_addr global i32 0, align 4
10+
@U0 = dso_local local_unnamed_addr global i32 0, align 4
11+
define void @func() { ret void }
12+
...
13+
---
14+
name: func
15+
alignment: 16
16+
tracksRegLiveness: true
17+
tracksDebugUserValues: true
18+
frameInfo:
19+
maxAlignment: 4
20+
stack:
21+
- { id: 0, type: spill-slot, size: 4, alignment: 4 }
22+
machineFunctionInfo: {}
23+
body: |
24+
25+
bb.0:
26+
; spill
27+
; CHECK-LABEL: name: func
28+
; CHECK: $ax = MOV16rm $rip, 1, $noreg, @D0, $noreg :: (dereferenceable load (s16) from @D0)
29+
; CHECK-NEXT: $xmm0 = MOVDI2PDIrr $eax
30+
; CHECK-NEXT: $eax = MOVPDI2DIrr $xmm0
31+
; CHECK-NEXT: MOV16mr $rip, 1, $noreg, @U0, $noreg, killed renamable $ax :: (store (s16) into @U0)
32+
; CHECK-NEXT: RET 0
33+
$ax = MOV16rm $rip, 1, $noreg, @D0, $noreg :: (dereferenceable load (s16) from @D0)
34+
MOV16mr %stack.0, 1, $noreg, 0, $noreg, killed renamable $ax :: (store (s16) into %stack.0)
35+
; reload
36+
$ax = MOV16rm %stack.0, 1, $noreg, 0, $noreg :: (load (s16) from %stack.0)
37+
MOV16mr $rip, 1, $noreg, @U0, $noreg, killed renamable $ax :: (store (s16) into @U0)
38+
RET 0
39+
...
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc %s -o - -mtriple=x86_64-unknown-linux -enable-spill2reg -mattr=+sse4.1 --run-pass=spill2reg -simplify-mir -spill2reg-mem-instrs=0 -spill2reg-vec-instrs=99999 | FileCheck %s
3+
4+
# Simple test with a single 8-bit spill-reload pair:
5+
# spill stack.0
6+
# reload stack.0
7+
8+
--- |
9+
@D0 = dso_local local_unnamed_addr global i32 0, align 4
10+
@U0 = dso_local local_unnamed_addr global i32 0, align 4
11+
define void @func() { ret void }
12+
...
13+
---
14+
name: func
15+
alignment: 16
16+
tracksRegLiveness: true
17+
tracksDebugUserValues: true
18+
frameInfo:
19+
maxAlignment: 4
20+
stack:
21+
- { id: 0, type: spill-slot, size: 4, alignment: 4 }
22+
machineFunctionInfo: {}
23+
body: |
24+
25+
bb.0:
26+
; spill
27+
; CHECK-LABEL: name: func
28+
; CHECK: $al = MOV8rm $rip, 1, $noreg, @D0, $noreg :: (dereferenceable load (s8) from @D0)
29+
; CHECK-NEXT: $xmm0 = MOVDI2PDIrr $eax
30+
; CHECK-NEXT: $eax = MOVPDI2DIrr $xmm0
31+
; CHECK-NEXT: MOV8mr $rip, 1, $noreg, @U0, $noreg, killed renamable $al :: (store (s8) into @U0)
32+
; CHECK-NEXT: RET 0
33+
$al = MOV8rm $rip, 1, $noreg, @D0, $noreg :: (dereferenceable load (s8) from @D0)
34+
MOV8mr %stack.0, 1, $noreg, 0, $noreg, killed renamable $al :: (store (s8) into %stack.0)
35+
; reload
36+
$al = MOV8rm %stack.0, 1, $noreg, 0, $noreg :: (load (s8) from %stack.0)
37+
MOV8mr $rip, 1, $noreg, @U0, $noreg, killed renamable $al :: (store (s8) into @U0)
38+
RET 0
39+
...

0 commit comments

Comments
 (0)