forked from OSchip/llvm-project
GlobalISel: Add target pre-isel instructions
Allows targets to introduce regbankselectable pseudo-instructions. Currently the closet feature to this is an intrinsic. However this requires creating a public intrinsic declaration. This litters the public intrinsic namespace with operations we don't necessarily want to expose to IR producers, and would rather leave as private to the backend. Use a new instruction bit. A previous attempt tried to keep using enum value ranges, but it turned into a mess. llvm-svn: 373937
This commit is contained in:
parent
cdbeaf548f
commit
27269054d2
|
@ -618,6 +618,12 @@ public:
|
|||
return hasPropertyInBundle(1ULL << MCFlag, Type);
|
||||
}
|
||||
|
||||
/// Return true if this is an instruction that should go through the usual
|
||||
/// legalization steps.
|
||||
bool isPreISelOpcode(QueryType Type = IgnoreBundle) const {
|
||||
return hasProperty(MCID::PreISelOpcode, Type);
|
||||
}
|
||||
|
||||
/// Return true if this instruction can have a variable number of operands.
|
||||
/// In this case, the variable operands will be after the normal
|
||||
/// operands but before the implicit definitions and uses (if any are
|
||||
|
|
|
@ -129,7 +129,8 @@ namespace MCID {
|
|||
/// not use these directly. These all correspond to bitfields in the
|
||||
/// MCInstrDesc::Flags field.
|
||||
enum Flag {
|
||||
Variadic = 0,
|
||||
PreISelOpcode = 0,
|
||||
Variadic,
|
||||
HasOptionalDef,
|
||||
Pseudo,
|
||||
Return,
|
||||
|
@ -242,6 +243,10 @@ public:
|
|||
/// Return flags of this instruction.
|
||||
uint64_t getFlags() const { return Flags; }
|
||||
|
||||
/// \returns true if this instruction is emitted before instruction selection
|
||||
/// and should be legalized/regbankselected/selected.
|
||||
bool isPreISelOpcode() const { return Flags & (1ULL << MCID::PreISelOpcode); }
|
||||
|
||||
/// Return true if this instruction can have a variable number of
|
||||
/// operands. In this case, the variable operands will be after the normal
|
||||
/// operands but before the implicit definitions and uses (if any are
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
// Unary ops.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GenericInstruction : StandardPseudoInstruction;
|
||||
class GenericInstruction : StandardPseudoInstruction {
|
||||
let isPreISelOpcode = 1;
|
||||
}
|
||||
|
||||
// Extend the underlying scalar type of an operation, leaving the high bits
|
||||
// unspecified.
|
||||
|
|
|
@ -492,6 +492,10 @@ class Instruction : InstructionEncoding {
|
|||
// Added complexity passed onto matching pattern.
|
||||
int AddedComplexity = 0;
|
||||
|
||||
// Indicates if this is a pre-isel opcode that should be
|
||||
// legalized/regbankselected/selected.
|
||||
bit isPreISelOpcode = 0;
|
||||
|
||||
// These bits capture information about the high-level semantics of the
|
||||
// instruction.
|
||||
bit isReturn = 0; // Is this instruction a return instruction?
|
||||
|
|
|
@ -687,8 +687,9 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) {
|
|||
// iterator before hand.
|
||||
MachineInstr &MI = *MII++;
|
||||
|
||||
// Ignore target-specific instructions: they should use proper regclasses.
|
||||
if (isTargetSpecificOpcode(MI.getOpcode()))
|
||||
// Ignore target-specific post-isel instructions: they should use proper
|
||||
// regclasses.
|
||||
if (isTargetSpecificOpcode(MI.getOpcode()) && !MI.isPreISelOpcode())
|
||||
continue;
|
||||
|
||||
if (!assignInstr(MI)) {
|
||||
|
|
|
@ -116,6 +116,7 @@ def : GINodeEquiv<G_ATOMICRMW_UMIN, atomic_load_umin_glue>;
|
|||
def : GINodeEquiv<G_ATOMICRMW_UMAX, atomic_load_umax_glue>;
|
||||
def : GINodeEquiv<G_ATOMICRMW_FADD, atomic_load_fadd_glue>;
|
||||
|
||||
def : GINodeEquiv<G_AMDGPU_FFBH_U32, AMDGPUffbh_u32>;
|
||||
|
||||
class GISelSop2Pat <
|
||||
SDPatternOperator node,
|
||||
|
|
|
@ -1650,7 +1650,7 @@ bool AMDGPUInstructionSelector::select(MachineInstr &I) {
|
|||
if (I.isPHI())
|
||||
return selectPHI(I);
|
||||
|
||||
if (!isPreISelGenericOpcode(I.getOpcode())) {
|
||||
if (!I.isPreISelOpcode()) {
|
||||
if (I.isCopy())
|
||||
return selectCOPY(I);
|
||||
return true;
|
||||
|
|
|
@ -2305,6 +2305,7 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
|||
case AMDGPU::G_FCANONICALIZE:
|
||||
case AMDGPU::G_INTRINSIC_TRUNC:
|
||||
case AMDGPU::G_INTRINSIC_ROUND:
|
||||
case AMDGPU::G_AMDGPU_FFBH_U32:
|
||||
return getDefaultMappingVOP(MI);
|
||||
case AMDGPU::G_UMULH:
|
||||
case AMDGPU::G_SMULH: {
|
||||
|
|
|
@ -3117,7 +3117,8 @@ static bool shouldReadExec(const MachineInstr &MI) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (SIInstrInfo::isGenericOpcode(MI.getOpcode()) ||
|
||||
if (MI.isPreISelOpcode() ||
|
||||
SIInstrInfo::isGenericOpcode(MI.getOpcode()) ||
|
||||
SIInstrInfo::isSALU(MI) ||
|
||||
SIInstrInfo::isSMRD(MI))
|
||||
return false;
|
||||
|
|
|
@ -1982,3 +1982,13 @@ def : FP16Med3Pat<f16, V_MED3_F16>;
|
|||
defm : Int16Med3Pat<V_MED3_I16, smin, smax, smax_oneuse, smin_oneuse>;
|
||||
defm : Int16Med3Pat<V_MED3_U16, umin, umax, umax_oneuse, umin_oneuse>;
|
||||
} // End Predicates = [isGFX9Plus]
|
||||
|
||||
class AMDGPUGenericInstruction : GenericInstruction {
|
||||
let Namespace = "AMDGPU";
|
||||
}
|
||||
|
||||
def G_AMDGPU_FFBH_U32 : AMDGPUGenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst);
|
||||
let InOperandList = (ins type1:$src);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -march=amdgcn -run-pass=instruction-select -verify-machineinstrs -global-isel-abort=0 %s -o - | FileCheck %s
|
||||
|
||||
---
|
||||
|
||||
name: ffbh_u32_s32_s_s
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
tracksRegLiveness: true
|
||||
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $sgpr0
|
||||
|
||||
; CHECK-LABEL: name: ffbh_u32_s32_s_s
|
||||
; CHECK: liveins: $sgpr0
|
||||
; CHECK: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0
|
||||
; CHECK: [[S_FLBIT_I32_B32_:%[0-9]+]]:sreg_32 = S_FLBIT_I32_B32 [[COPY]]
|
||||
; CHECK: S_ENDPGM 0, implicit [[S_FLBIT_I32_B32_]]
|
||||
%0:sgpr(s32) = COPY $sgpr0
|
||||
%1:sgpr(s32) = G_AMDGPU_FFBH_U32 %0
|
||||
S_ENDPGM 0, implicit %1
|
||||
|
||||
...
|
||||
|
||||
---
|
||||
|
||||
name: ffbh_u32_s32_v_v
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
tracksRegLiveness: true
|
||||
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $vgpr0
|
||||
|
||||
; CHECK-LABEL: name: ffbh_u32_s32_v_v
|
||||
; CHECK: liveins: $vgpr0
|
||||
; CHECK: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0
|
||||
; CHECK: [[AMDGPU_FFBH_U32_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FFBH_U32 [[COPY]](s32)
|
||||
; CHECK: S_ENDPGM 0, implicit [[AMDGPU_FFBH_U32_]](s32)
|
||||
%0:vgpr(s32) = COPY $vgpr0
|
||||
%1:vgpr(s32) = G_AMDGPU_FFBH_U32 %0
|
||||
S_ENDPGM 0, implicit %1
|
||||
|
||||
...
|
||||
|
||||
---
|
||||
|
||||
name: ffbh_u32_v_s
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
tracksRegLiveness: true
|
||||
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $sgpr0
|
||||
|
||||
; CHECK-LABEL: name: ffbh_u32_v_s
|
||||
; CHECK: liveins: $sgpr0
|
||||
; CHECK: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0
|
||||
; CHECK: [[AMDGPU_FFBH_U32_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FFBH_U32 [[COPY]](s32)
|
||||
; CHECK: S_ENDPGM 0, implicit [[AMDGPU_FFBH_U32_]](s32)
|
||||
%0:sgpr(s32) = COPY $sgpr0
|
||||
%1:vgpr(s32) = G_AMDGPU_FFBH_U32 %0
|
||||
S_ENDPGM 0, implicit %1
|
||||
|
||||
...
|
|
@ -0,0 +1,32 @@
|
|||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -march=amdgcn -mcpu=fiji -run-pass=regbankselect %s -verify-machineinstrs -o - -regbankselect-fast | FileCheck %s
|
||||
# RUN: llc -march=amdgcn -mcpu=fiji -run-pass=regbankselect %s -verify-machineinstrs -o - -regbankselect-greedy | FileCheck %s
|
||||
|
||||
---
|
||||
name: ffbh_u32_s
|
||||
legalized: true
|
||||
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $sgpr0
|
||||
|
||||
; CHECK-LABEL: name: ffbh_u32_s
|
||||
; CHECK: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0
|
||||
; CHECK: [[AMDGPU_FFBH_U32_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FFBH_U32 [[COPY]](s32)
|
||||
%0:_(s32) = COPY $sgpr0
|
||||
%1:_(s32) = G_AMDGPU_FFBH_U32 %0
|
||||
...
|
||||
|
||||
---
|
||||
name: ffbh_u32_v
|
||||
legalized: true
|
||||
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $vgpr0_vgpr1
|
||||
; CHECK-LABEL: name: ffbh_u32_v
|
||||
; CHECK: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0
|
||||
; CHECK: [[AMDGPU_FFBH_U32_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FFBH_U32 [[COPY]](s32)
|
||||
%0:_(s32) = COPY $vgpr0
|
||||
%1:_(s32) = G_AMDGPU_FFBH_U32 %0
|
||||
...
|
|
@ -363,6 +363,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
|||
Namespace = R->getValueAsString("Namespace");
|
||||
AsmString = R->getValueAsString("AsmString");
|
||||
|
||||
isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");
|
||||
isReturn = R->getValueAsBit("isReturn");
|
||||
isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");
|
||||
isBranch = R->getValueAsBit("isBranch");
|
||||
|
|
|
@ -231,6 +231,7 @@ template <typename T> class ArrayRef;
|
|||
std::vector<Record*> ImplicitDefs, ImplicitUses;
|
||||
|
||||
// Various boolean values we track for the instruction.
|
||||
bool isPreISelOpcode : 1;
|
||||
bool isReturn : 1;
|
||||
bool isEHScopeReturn : 1;
|
||||
bool isBranch : 1;
|
||||
|
|
|
@ -662,6 +662,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
|
|||
CodeGenTarget &Target = CDP.getTargetInfo();
|
||||
|
||||
// Emit all of the target independent flags...
|
||||
if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)";
|
||||
if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)";
|
||||
if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)";
|
||||
if (Inst.isEHScopeReturn) OS << "|(1ULL<<MCID::EHScopeReturn)";
|
||||
|
|
Loading…
Reference in New Issue