Skip to content

Commit e5c6e42

Browse files
committed
[AMDGPU][True16][CodeGen] AND/OR/XOR and LDEXP support in true/fake16 format.
Added RA hint for 16 bit registers
1 parent ae059a1 commit e5c6e42

12 files changed

+799
-299
lines changed

llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,34 @@ bool AMDGPUInstructionSelector::selectCOPY(MachineInstr &I) const {
161161

162162
// TODO: Skip masking high bits if def is known boolean.
163163

164-
bool IsSGPR = TRI.isSGPRClass(SrcRC);
165-
unsigned AndOpc =
166-
IsSGPR ? AMDGPU::S_AND_B32 : AMDGPU::V_AND_B32_e32;
167-
auto And = BuildMI(*BB, &I, DL, TII.get(AndOpc), MaskedReg)
168-
.addImm(1)
169-
.addReg(SrcReg);
170-
if (IsSGPR)
171-
And.setOperandDead(3); // Dead scc
172-
173-
BuildMI(*BB, &I, DL, TII.get(AMDGPU::V_CMP_NE_U32_e64), DstReg)
174-
.addImm(0)
175-
.addReg(MaskedReg);
164+
if (AMDGPU::getRegBitWidth(SrcRC->getID()) == 16) {
165+
assert(Subtarget->useRealTrue16Insts());
166+
const int64_t NoMods = 0;
167+
BuildMI(*BB, &I, DL, TII.get(AMDGPU::V_AND_B16_t16_e64), MaskedReg)
168+
.addImm(NoMods)
169+
.addImm(1)
170+
.addImm(NoMods)
171+
.addReg(SrcReg)
172+
.addImm(NoMods);
173+
BuildMI(*BB, &I, DL, TII.get(AMDGPU::V_CMP_NE_U16_t16_e64), DstReg)
174+
.addImm(NoMods)
175+
.addImm(0)
176+
.addImm(NoMods)
177+
.addReg(MaskedReg)
178+
.addImm(NoMods);
179+
} else {
180+
bool IsSGPR = TRI.isSGPRClass(SrcRC);
181+
unsigned AndOpc = IsSGPR ? AMDGPU::S_AND_B32 : AMDGPU::V_AND_B32_e32;
182+
auto And = BuildMI(*BB, &I, DL, TII.get(AndOpc), MaskedReg)
183+
.addImm(1)
184+
.addReg(SrcReg);
185+
if (IsSGPR)
186+
And.setOperandDead(3); // Dead scc
187+
188+
BuildMI(*BB, &I, DL, TII.get(AMDGPU::V_CMP_NE_U32_e64), DstReg)
189+
.addImm(0)
190+
.addReg(MaskedReg);
191+
}
176192
}
177193

178194
if (!MRI->getRegClassOrNull(SrcReg))
@@ -2206,6 +2222,16 @@ bool AMDGPUInstructionSelector::selectG_TRUNC(MachineInstr &I) const {
22062222
return false;
22072223
}
22082224

2225+
if (DstRC == &AMDGPU::VGPR_16RegClass && SrcSize == 32) {
2226+
assert(STI.useRealTrue16Insts());
2227+
const DebugLoc &DL = I.getDebugLoc();
2228+
MachineBasicBlock *MBB = I.getParent();
2229+
BuildMI(*MBB, I, DL, TII.get(AMDGPU::COPY), DstReg)
2230+
.addReg(SrcReg, 0, AMDGPU::lo16);
2231+
I.eraseFromParent();
2232+
return true;
2233+
}
2234+
22092235
if (DstTy == LLT::fixed_vector(2, 16) && SrcTy == LLT::fixed_vector(2, 32)) {
22102236
MachineBasicBlock *MBB = I.getParent();
22112237
const DebugLoc &DL = I.getDebugLoc();

llvm/lib/Target/AMDGPU/GCNPreRAOptimizations.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@
2222
/// although the same shall be possible with other register classes and
2323
/// instructions if necessary.
2424
///
25+
/// This pass also adds register allocation hints to COPY.
26+
/// The hints will be post-processed by SIRegisterInfo::getRegAllocationHints.
27+
/// When using True16, we often see COPY moving a 16-bit value between a VGPR_32
28+
/// and a VGPR_16. If we use the VGPR_16 that corresponds to the lo16 bits of
29+
/// the VGPR_32, the COPY can be completely eliminated.
30+
2531
//===----------------------------------------------------------------------===//
2632

2733
#include "AMDGPU.h"
2834
#include "GCNSubtarget.h"
2935
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
36+
#include "SIRegisterInfo.h"
3037
#include "llvm/CodeGen/LiveIntervals.h"
3138
#include "llvm/CodeGen/MachineFunctionPass.h"
3239
#include "llvm/InitializePasses.h"
@@ -236,5 +243,38 @@ bool GCNPreRAOptimizations::runOnMachineFunction(MachineFunction &MF) {
236243
Changed |= processReg(Reg);
237244
}
238245

246+
if (!ST.useRealTrue16Insts())
247+
return Changed;
248+
249+
// Add RA hints to improve True16 COPY elimination.
250+
for (const MachineBasicBlock &MBB : MF) {
251+
for (const MachineInstr &MI : MBB) {
252+
if (MI.getOpcode() != AMDGPU::COPY)
253+
continue;
254+
Register Dst = MI.getOperand(0).getReg();
255+
Register Src = MI.getOperand(1).getReg();
256+
if (Dst.isVirtual() &&
257+
MRI->getRegClass(Dst) == &AMDGPU::VGPR_16RegClass &&
258+
Src.isPhysical() &&
259+
TRI->getRegClassForReg(*MRI, Src) == &AMDGPU::VGPR_32RegClass)
260+
MRI->setRegAllocationHint(Dst, 0, TRI->getSubReg(Src, AMDGPU::lo16));
261+
if (Src.isVirtual() &&
262+
MRI->getRegClass(Src) == &AMDGPU::VGPR_16RegClass &&
263+
Dst.isPhysical() &&
264+
TRI->getRegClassForReg(*MRI, Dst) == &AMDGPU::VGPR_32RegClass)
265+
MRI->setRegAllocationHint(Src, 0, TRI->getSubReg(Dst, AMDGPU::lo16));
266+
if (!Dst.isVirtual() || !Src.isVirtual())
267+
continue;
268+
if (MRI->getRegClass(Dst) == &AMDGPU::VGPR_32RegClass &&
269+
MRI->getRegClass(Src) == &AMDGPU::VGPR_16RegClass) {
270+
MRI->setRegAllocationHint(Dst, AMDGPURI::Size32, Src);
271+
MRI->setRegAllocationHint(Src, AMDGPURI::Size16, Dst);
272+
}
273+
if (MRI->getRegClass(Dst) == &AMDGPU::VGPR_16RegClass &&
274+
MRI->getRegClass(Src) == &AMDGPU::VGPR_32RegClass)
275+
MRI->setRegAllocationHint(Dst, AMDGPURI::Size16, Src);
276+
}
277+
}
278+
239279
return Changed;
240280
}

llvm/lib/Target/AMDGPU/SIInstructions.td

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,8 @@ def : GCNPat <
20302030
>;
20312031

20322032
foreach fp16vt = [f16, bf16] in {
2033+
foreach p = [NotHasTrue16BitInsts, UseFakeTrue16Insts] in
2034+
let SubtargetPredicate = p in {
20332035
def : GCNPat <
20342036
(fabs (fp16vt VGPR_32:$src)),
20352037
(V_AND_B32_e64 (S_MOV_B32 (i32 0x00007fff)), VGPR_32:$src)
@@ -2044,6 +2046,24 @@ def : GCNPat <
20442046
(fneg (fabs (fp16vt VGPR_32:$src))),
20452047
(V_OR_B32_e64 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src) // Set sign bit
20462048
>;
2049+
}
2050+
2051+
let SubtargetPredicate = UseRealTrue16Insts in {
2052+
def : GCNPat <
2053+
(fabs (fp16vt VGPR_16:$src)),
2054+
(V_AND_B16_t16_e64 (i32 0), (i16 0x7fff), (i32 0), VGPR_16:$src)
2055+
>;
2056+
2057+
def : GCNPat <
2058+
(fneg (fp16vt VGPR_16:$src)),
2059+
(V_XOR_B16_t16_e64 (i32 0), (i16 0x8000), (i32 0), VGPR_16:$src)
2060+
>;
2061+
2062+
def : GCNPat <
2063+
(fneg (fabs (fp16vt VGPR_16:$src))),
2064+
(V_OR_B16_t16_e64 (i32 0), (i16 0x8000), (i32 0), VGPR_16:$src) // Set sign bit
2065+
>;
2066+
} // End SubtargetPredicate = UseRealTrue16Insts
20472067
} // End foreach fp16vt = ...
20482068

20492069
def : GCNPat <

llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3327,6 +3327,73 @@ const int *SIRegisterInfo::getRegUnitPressureSets(unsigned RegUnit) const {
33273327
return AMDGPUGenRegisterInfo::getRegUnitPressureSets(RegUnit);
33283328
}
33293329

3330+
bool SIRegisterInfo::getRegAllocationHints(Register VirtReg,
3331+
ArrayRef<MCPhysReg> Order,
3332+
SmallVectorImpl<MCPhysReg> &Hints,
3333+
const MachineFunction &MF,
3334+
const VirtRegMap *VRM,
3335+
const LiveRegMatrix *Matrix) const {
3336+
3337+
const MachineRegisterInfo &MRI = MF.getRegInfo();
3338+
const SIRegisterInfo *TRI = ST.getRegisterInfo();
3339+
3340+
std::pair<unsigned, Register> Hint = MRI.getRegAllocationHint(VirtReg);
3341+
3342+
switch (Hint.first) {
3343+
case AMDGPURI::Size32: {
3344+
Register Paired = Hint.second;
3345+
assert(Paired);
3346+
Register PairedPhys;
3347+
if (Paired.isPhysical()) {
3348+
PairedPhys =
3349+
getMatchingSuperReg(Paired, AMDGPU::lo16, &AMDGPU::VGPR_32RegClass);
3350+
} else if (VRM && VRM->hasPhys(Paired)) {
3351+
PairedPhys = getMatchingSuperReg(VRM->getPhys(Paired), AMDGPU::lo16,
3352+
&AMDGPU::VGPR_32RegClass);
3353+
}
3354+
3355+
// Prefer the paired physreg.
3356+
if (PairedPhys)
3357+
// isLo(Paired) is implicitly true here from the API of
3358+
// getMatchingSuperReg.
3359+
Hints.push_back(PairedPhys);
3360+
return false;
3361+
}
3362+
case AMDGPURI::Size16: {
3363+
Register Paired = Hint.second;
3364+
assert(Paired);
3365+
Register PairedPhys;
3366+
if (Paired.isPhysical()) {
3367+
PairedPhys = TRI->getSubReg(Paired, AMDGPU::lo16);
3368+
} else if (VRM && VRM->hasPhys(Paired)) {
3369+
PairedPhys = TRI->getSubReg(VRM->getPhys(Paired), AMDGPU::lo16);
3370+
}
3371+
3372+
// First prefer the paired physreg.
3373+
if (PairedPhys)
3374+
Hints.push_back(PairedPhys);
3375+
else {
3376+
// Add all the lo16 physregs.
3377+
// When the Paired operand has not yet been assigned a physreg it is
3378+
// better to try putting VirtReg in a lo16 register, because possibly
3379+
// later Paired can be assigned to the overlapping register and the COPY
3380+
// can be eliminated.
3381+
for (MCPhysReg PhysReg : Order) {
3382+
if (PhysReg == PairedPhys || AMDGPU::isHi(PhysReg, *this))
3383+
continue;
3384+
if (AMDGPU::VGPR_16RegClass.contains(PhysReg) &&
3385+
!MRI.isReserved(PhysReg))
3386+
Hints.push_back(PhysReg);
3387+
}
3388+
}
3389+
return false;
3390+
}
3391+
default:
3392+
return TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF,
3393+
VRM);
3394+
}
3395+
}
3396+
33303397
MCRegister SIRegisterInfo::getReturnAddressReg(const MachineFunction &MF) const {
33313398
// Not a callee saved register.
33323399
return AMDGPU::SGPR30_SGPR31;

llvm/lib/Target/AMDGPU/SIRegisterInfo.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ class LiveRegUnits;
2929
class RegisterBank;
3030
struct SGPRSpillBuilder;
3131

32+
/// Register allocation hint types. Helps eliminate unneeded COPY with True16
33+
namespace AMDGPURI {
34+
35+
enum { Size16 = 1, Size32 = 2 };
36+
37+
} // end namespace AMDGPURI
38+
3239
class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
3340
private:
3441
const GCNSubtarget &ST;
@@ -326,6 +333,11 @@ class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
326333
unsigned getRegPressureSetLimit(const MachineFunction &MF,
327334
unsigned Idx) const override;
328335

336+
bool getRegAllocationHints(Register VirtReg, ArrayRef<MCPhysReg> Order,
337+
SmallVectorImpl<MCPhysReg> &Hints,
338+
const MachineFunction &MF, const VirtRegMap *VRM,
339+
const LiveRegMatrix *Matrix) const override;
340+
329341
const int *getRegUnitPressureSets(unsigned RegUnit) const override;
330342

331343
MCRegister getReturnAddressReg(const MachineFunction &MF) const;

llvm/lib/Target/AMDGPU/VOP1Instructions.td

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,8 @@ def : GCNPat <
13971397

13981398
} // End OtherPredicates = [isGFX8Plus]
13991399

1400-
let OtherPredicates = [isGFX8Plus] in {
1400+
foreach p = [NotHasTrue16BitInsts, UseFakeTrue16Insts] in
1401+
let OtherPredicates = [isGFX8Plus, p] in {
14011402
def : GCNPat<
14021403
(i32 (anyext i16:$src)),
14031404
(COPY $src)
@@ -1420,7 +1421,43 @@ def : GCNPat <
14201421
(EXTRACT_SUBREG $src, sub0)
14211422
>;
14221423

1423-
} // End OtherPredicates = [isGFX8Plus]
1424+
} // End OtherPredicates = [isGFX8Plus, p]
1425+
1426+
let OtherPredicates = [UseFakeTrue16Insts] in {
1427+
def : GCNPat<
1428+
(i32 (DivergentUnaryFrag<anyext> i16:$src)),
1429+
(COPY $src)
1430+
>;
1431+
} // End OtherPredicates = [UseFakeTrue16Insts]
1432+
1433+
1434+
let OtherPredicates = [UseRealTrue16Insts] in {
1435+
def : GCNPat<
1436+
(i32 (UniformUnaryFrag<anyext> (i16 SReg_32:$src))),
1437+
(COPY $src)
1438+
>;
1439+
1440+
def : GCNPat<
1441+
(i32 (DivergentUnaryFrag<anyext> i16:$src)),
1442+
(REG_SEQUENCE VGPR_32, $src, lo16, (i16 (IMPLICIT_DEF)), hi16)
1443+
>;
1444+
1445+
def : GCNPat<
1446+
(i64 (anyext i16:$src)),
1447+
(REG_SEQUENCE VReg_64, $src, lo16, (i16 (IMPLICIT_DEF)), hi16, (i32 (IMPLICIT_DEF)), sub1)
1448+
>;
1449+
1450+
def : GCNPat<
1451+
(i16 (trunc i32:$src)),
1452+
(EXTRACT_SUBREG $src, lo16)
1453+
>;
1454+
1455+
def : GCNPat <
1456+
(i16 (trunc i64:$src)),
1457+
(EXTRACT_SUBREG $src, lo16)
1458+
>;
1459+
1460+
} // End OtherPredicates = [UseRealTrue16Insts]
14241461

14251462
//===----------------------------------------------------------------------===//
14261463
// GFX9

llvm/lib/Target/AMDGPU/VOP2Instructions.td

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -922,18 +922,25 @@ def LDEXP_F16_VOPProfile : VOPProfile <[f16, f16, f16, untyped]> {
922922
let HasSrc1FloatMods = 0;
923923
let Src1ModSDWA = Int16SDWAInputMods;
924924
}
925-
def LDEXP_F16_VOPProfile_True16 : VOPProfile_Fake16<VOP_F16_F16_F16> {
925+
def LDEXP_F16_VOPProfile_True16 : VOPProfile_True16<VOP_F16_F16_F16> {
926+
let Src1RC32 = RegisterOperand<VGPR_16_Lo128>;
927+
let Src1DPP = RegisterOperand<VGPR_16_Lo128>;
928+
let Src1ModDPP = IntT16VRegInputMods<0/*IsFake16*/>;
929+
}
930+
def LDEXP_F16_VOPProfile_Fake16 : VOPProfile_Fake16<VOP_F16_F16_F16> {
926931
let Src1RC32 = RegisterOperand<VGPR_32_Lo128>;
927932
let Src1DPP = RegisterOperand<VGPR_32_Lo128>;
928-
let Src1ModDPP = IntT16VRegInputMods</* IsFake16= */ 1>;
933+
let Src1ModDPP = IntT16VRegInputMods<1/*IsFake16*/>;
929934
}
930935

931936
let isReMaterializable = 1 in {
932937
let FPDPRounding = 1 in {
933938
let OtherPredicates = [Has16BitInsts], True16Predicate = NotHasTrue16BitInsts in
934939
defm V_LDEXP_F16 : VOP2Inst <"v_ldexp_f16", LDEXP_F16_VOPProfile>;
935-
let SubtargetPredicate = HasTrue16BitInsts in
940+
let SubtargetPredicate = UseRealTrue16Insts in
936941
defm V_LDEXP_F16_t16 : VOP2Inst <"v_ldexp_f16_t16", LDEXP_F16_VOPProfile_True16>;
942+
let SubtargetPredicate = UseFakeTrue16Insts in
943+
defm V_LDEXP_F16_fake16 : VOP2Inst <"v_ldexp_f16_fake16", LDEXP_F16_VOPProfile_Fake16, null_frag, "v_ldexp_f16_fake16">;
937944
} // End FPDPRounding = 1
938945
// FIXME VOP3 Only instructions. NFC using VOPProfile_True16 for these until a planned change to use a new register class for VOP3 encoded True16 instuctions
939946
defm V_LSHLREV_B16 : VOP2Inst_e64_t16 <"v_lshlrev_b16", VOP_I16_I16_I16, clshl_rev_16>;
@@ -968,14 +975,27 @@ class LDEXP_F16_Pat <SDPatternOperator op, VOP_Pseudo inst, VOPProfile P = inst.
968975
let OtherPredicates = [NotHasTrue16BitInsts] in
969976
def : LDEXP_F16_Pat<any_fldexp, V_LDEXP_F16_e64>;
970977

971-
let OtherPredicates = [HasTrue16BitInsts] in
972-
def : LDEXP_F16_Pat<any_fldexp, V_LDEXP_F16_t16_e64>;
978+
class LDEXP_F16_t16_Pat <SDPatternOperator op, VOP_Pseudo inst, VOPProfile P = inst.Pfl> : GCNPat <
979+
(P.DstVT (op (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
980+
(i16 (VOP3Mods0 P.Src1VT:$src1, i32:$src1_modifiers)))),
981+
(inst $src0_modifiers, $src0,
982+
$src1_modifiers, $src1,
983+
$clamp, /* clamp */
984+
$omod, /* omod */
985+
0) /* op_sel */
986+
>;
987+
988+
let OtherPredicates = [UseRealTrue16Insts] in
989+
def : LDEXP_F16_t16_Pat<any_fldexp, V_LDEXP_F16_t16_e64>;
990+
991+
let OtherPredicates = [UseFakeTrue16Insts] in
992+
def : LDEXP_F16_Pat<any_fldexp, V_LDEXP_F16_fake16_e64>;
973993

974994
let SubtargetPredicate = isGFX11Plus in {
975995
let isCommutable = 1 in {
976-
defm V_AND_B16_t16 : VOP2Inst_e64 <"v_and_b16_t16", VOPProfile_Fake16<VOP_I16_I16_I16>, and>;
977-
defm V_OR_B16_t16 : VOP2Inst_e64 <"v_or_b16_t16", VOPProfile_Fake16<VOP_I16_I16_I16>, or>;
978-
defm V_XOR_B16_t16 : VOP2Inst_e64 <"v_xor_b16_t16", VOPProfile_Fake16<VOP_I16_I16_I16>, xor>;
996+
defm V_AND_B16_t16 : VOP2Inst_e64 <"v_and_b16_t16", VOPProfile_True16<VOP_I16_I16_I16>, and>;
997+
defm V_OR_B16_t16 : VOP2Inst_e64 <"v_or_b16_t16", VOPProfile_True16<VOP_I16_I16_I16>, or>;
998+
defm V_XOR_B16_t16 : VOP2Inst_e64 <"v_xor_b16_t16", VOPProfile_True16<VOP_I16_I16_I16>, xor>;
979999
} // End isCommutable = 1
9801000
} // End SubtargetPredicate = isGFX11Plus
9811001

@@ -1714,6 +1734,7 @@ defm V_MUL_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x035, "v_mul_f16">;
17141734
defm V_MUL_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x035, "v_mul_f16">;
17151735
defm V_FMAC_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x036, "v_fmac_f16">;
17161736
defm V_LDEXP_F16_t16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x03b, "v_ldexp_f16">;
1737+
defm V_LDEXP_F16_fake16 : VOP2_Real_FULL_t16_gfx11_gfx12<0x03b, "v_ldexp_f16">;
17171738
defm V_MAX_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x039, "v_max_f16">;
17181739
defm V_MAX_F16_fake16 : VOP2_Real_FULL_t16_gfx11<0x039, "v_max_f16">;
17191740
defm V_MIN_F16_t16 : VOP2_Real_FULL_t16_gfx11<0x03a, "v_min_f16">;

0 commit comments

Comments
 (0)