1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[globalisel][legalizerinfo] Introduce dedicated extending loads and add lowerings for them

Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
  registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
  extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
  improve optimization of extends and truncates, this legality requirement
  would spread without considerable care w.r.t when certain combines were
  permitted.
* The SelectionDAG importer required some ugly and fragile pattern
  rewriting to translate patterns into this style.

This patch begins changing the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.

This patch introduces the new generic instructions and new variation on
G_LOAD and adds lowering for them to convert back to the existing
representations.

Depends on D45466

Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, aemerson, javed.absar

Reviewed By: aemerson

Subscribers: aemerson, kristof.beyls, javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D45540

llvm-svn: 331115
This commit is contained in:
Daniel Sanders 2018-04-28 18:14:50 +00:00
parent 4a25b275bb
commit 491fd6384e
9 changed files with 167 additions and 6 deletions

View File

@ -521,6 +521,18 @@ public:
MachineInstrBuilder buildLoad(unsigned Res, unsigned Addr,
MachineMemOperand &MMO);
/// Build and insert `Res = <opcode> Addr, MMO`.
///
/// Loads the value stored at \p Addr. Puts the result in \p Res.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p Res must be a generic virtual register.
/// \pre \p Addr must be a generic virtual register with pointer type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, unsigned Res,
unsigned Addr, MachineMemOperand &MMO);
/// Build and insert `G_STORE Val, Addr, MMO`.
///
/// Stores the value \p Val to \p Addr.

View File

@ -265,9 +265,15 @@ HANDLE_TARGET_OPCODE(G_INTTOPTR)
/// COPY is the relevant instruction.
HANDLE_TARGET_OPCODE(G_BITCAST)
/// Generic load.
/// Generic load (including anyext load)
HANDLE_TARGET_OPCODE(G_LOAD)
/// Generic signext load
HANDLE_TARGET_OPCODE(G_SEXTLOAD)
/// Generic zeroext load
HANDLE_TARGET_OPCODE(G_ZEXTLOAD)
/// Generic store.
HANDLE_TARGET_OPCODE(G_STORE)

View File

@ -482,6 +482,22 @@ def G_LOAD : GenericInstruction {
let mayLoad = 1;
}
// Generic sign-extended load. Expects a MachineMemOperand in addition to explicit operands.
def G_SEXTLOAD : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins ptype1:$addr);
let hasSideEffects = 0;
let mayLoad = 1;
}
// Generic zero-extended load. Expects a MachineMemOperand in addition to explicit operands.
def G_ZEXTLOAD : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins ptype1:$addr);
let hasSideEffects = 0;
let mayLoad = 1;
}
// Generic store. Expects a MachineMemOperand in addition to explicit operands.
def G_STORE : GenericInstruction {
let OutOperandList = (outs);

View File

@ -732,17 +732,19 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
MI.eraseFromParent();
return Legalized;
}
case TargetOpcode::G_LOAD: {
case TargetOpcode::G_LOAD:
// For some types like i24, we might try to widen to i32. To properly handle
// this we should be using a dedicated extending load, until then avoid
// trying to legalize.
if (alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) !=
WideTy.getSizeInBits())
return UnableToLegalize;
LLVM_FALLTHROUGH;
case TargetOpcode::G_SEXTLOAD:
case TargetOpcode::G_ZEXTLOAD: {
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(),
**MI.memoperands_begin());
MIRBuilder.buildLoadInstr(MI.getOpcode(), DstExt, MI.getOperand(1).getReg(),
**MI.memoperands_begin());
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
MI.eraseFromParent();
return Legalized;
@ -1030,6 +1032,44 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
MI.eraseFromParent();
return Legalized;
}
case TargetOpcode::G_LOAD:
case TargetOpcode::G_SEXTLOAD:
case TargetOpcode::G_ZEXTLOAD: {
// Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
unsigned DstReg = MI.getOperand(0).getReg();
unsigned PtrReg = MI.getOperand(1).getReg();
LLT DstTy = MRI.getType(DstReg);
auto &MMO = **MI.memoperands_begin();
if (DstTy.getSizeInBits() == MMO.getSize() /* in bytes */ * 8) {
MIRBuilder.buildLoad(DstReg, PtrReg, MMO);
MI.eraseFromParent();
return Legalized;
}
if (DstTy.isScalar()) {
unsigned TmpReg = MRI.createGenericVirtualRegister(
LLT::scalar(MMO.getSize() /* in bytes */ * 8));
MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
switch (MI.getOpcode()) {
default:
llvm_unreachable("Unexpected opcode");
case TargetOpcode::G_LOAD:
MIRBuilder.buildAnyExt(DstReg, TmpReg);
break;
case TargetOpcode::G_SEXTLOAD:
MIRBuilder.buildSExt(DstReg, TmpReg);
break;
case TargetOpcode::G_ZEXTLOAD:
MIRBuilder.buildZExt(DstReg, TmpReg);
break;
}
MI.eraseFromParent();
return Legalized;
}
return UnableToLegalize;
}
}
}

View File

@ -278,10 +278,16 @@ MachineInstrBuilder MachineIRBuilderBase::buildBrCond(unsigned Tst,
MachineInstrBuilder MachineIRBuilderBase::buildLoad(unsigned Res, unsigned Addr,
MachineMemOperand &MMO) {
return buildLoadInstr(TargetOpcode::G_LOAD, Res, Addr, MMO);
}
MachineInstrBuilder
MachineIRBuilderBase::buildLoadInstr(unsigned Opcode, unsigned Res,
unsigned Addr, MachineMemOperand &MMO) {
assert(getMRI()->getType(Res).isValid() && "invalid operand type");
assert(getMRI()->getType(Addr).isPointer() && "invalid operand type");
return buildInstr(TargetOpcode::G_LOAD)
return buildInstr(Opcode)
.addDef(Res)
.addUse(Addr)
.addMemOperand(&MMO);

View File

@ -135,6 +135,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
.maxScalarIf(typeInSet(1, {s64}), 0, s32)
.widenScalarToNextPow2(0);
getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
.lower();
getActionDefinitionsBuilder({G_LOAD, G_STORE})
.legalForTypesWithMemSize({{s8, p0, 8},
{s16, p0, 16},
@ -147,6 +150,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
.unsupportedIfMemSizeNotPow2()
.clampScalar(0, s8, s64)
.widenScalarToNextPow2(0)
.lowerIf([=](const LegalityQuery &Query) {
return Query.Types[0].getSizeInBits() != Query.MMODescrs[0].Size * 8;
})
.clampNumElements(0, v2s32, v2s32);
// Constants

View File

@ -0,0 +1,25 @@
# RUN: llc -O0 -run-pass=legalizer -global-isel %s -o - -verify-machineinstrs | FileCheck %s
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--"
define void @test_extload(i8* %addr) {
entry:
ret void
}
...
---
name: test_extload
body: |
bb.0.entry:
liveins: $x0
; CHECK-LABEL: name: test_extload
; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr)
; CHECK: [[T2:%[0-9]+]]:_(s32) = G_ANYEXT [[T1]](s8)
; CHECK: $w0 = COPY [[T2]](s32)
%0:_(p0) = COPY $x0
%1:_(s32) = G_LOAD %0 :: (load 1 from %ir.addr)
$w0 = COPY %1
...

View File

@ -0,0 +1,25 @@
# RUN: llc -O0 -run-pass=legalizer -global-isel %s -o - -verify-machineinstrs | FileCheck %s
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--"
define void @test_zextload(i8* %addr) {
entry:
ret void
}
...
---
name: test_zextload
body: |
bb.0.entry:
liveins: $x0
; CHECK-LABEL: name: test_zextload
; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr)
; CHECK: [[T2:%[0-9]+]]:_(s32) = G_SEXT [[T1]](s8)
; CHECK: $w0 = COPY [[T2]](s32)
%0:_(p0) = COPY $x0
%1:_(s32) = G_SEXTLOAD %0 :: (load 1 from %ir.addr)
$w0 = COPY %1
...

View File

@ -0,0 +1,25 @@
# RUN: llc -O0 -run-pass=legalizer -global-isel %s -o - -verify-machineinstrs | FileCheck %s
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--"
define void @test_sextload(i8* %addr) {
entry:
ret void
}
...
---
name: test_sextload
body: |
bb.0.entry:
liveins: $x0
; CHECK-LABEL: name: test_sextload
; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr)
; CHECK: [[T2:%[0-9]+]]:_(s32) = G_ZEXT [[T1]](s8)
; CHECK: $w0 = COPY [[T2]](s32)
%0:_(p0) = COPY $x0
%1:_(s32) = G_ZEXTLOAD %0 :: (load 1 from %ir.addr)
$w0 = COPY %1
...