[globalisel][tablegen] Correct matching of intrinsic ID's.

TreePatternNode considers them to be plain integers but MachineInstr considers
them to be a distinct kind of operand.

The tweak to AArch64InstrInfo.td to produce a simple test case is a NFC for
everything except GlobalISelEmitter (confirmed by diffing the tablegenerated
files). GlobalISelEmitter is currently unable to infer the type of operands in
the Dst pattern from the operands in the Src pattern.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307634 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2017-07-11 08:57:29 +00:00
parent 6845427d1b
commit ec48fd1277
6 changed files with 84 additions and 12 deletions

View File

@ -107,6 +107,11 @@ enum {
/// - OpIdx - Operand index
/// - Expected integer
GIM_CheckLiteralInt,
/// Check the operand is a specific intrinsic ID
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
/// - Expected Intrinsic ID
GIM_CheckIntrinsicID,
/// Check the specified operand is an MBB
/// - InsnID - Instruction ID
/// - OpIdx - Operand index

View File

@ -156,6 +156,18 @@ bool InstructionSelector::executeMatchTable(
return false;
break;
}
case GIM_CheckIntrinsicID: {
int64_t InsnID = *Command++;
int64_t OpIdx = *Command++;
int64_t Value = *Command++;
DEBUG(dbgs() << "GIM_CheckIntrinsicID(MIs[" << InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &OM = State.MIs[InsnID]->getOperand(OpIdx);
if (!OM.isIntrinsicID() || OM.getIntrinsicID() != Value)
return false;
break;
}
case GIM_CheckIsMBB: {
int64_t InsnID = *Command++;
int64_t OpIdx = *Command++;

View File

@ -714,10 +714,10 @@ def : InstAlias<"negs $dst, $src$shift",
defm UDIV : Div<0, "udiv", udiv>;
defm SDIV : Div<1, "sdiv", sdiv>;
def : Pat<(int_aarch64_udiv GPR32:$Rn, GPR32:$Rm), (UDIVWr $Rn, $Rm)>;
def : Pat<(int_aarch64_udiv GPR64:$Rn, GPR64:$Rm), (UDIVXr $Rn, $Rm)>;
def : Pat<(int_aarch64_sdiv GPR32:$Rn, GPR32:$Rm), (SDIVWr $Rn, $Rm)>;
def : Pat<(int_aarch64_sdiv GPR64:$Rn, GPR64:$Rm), (SDIVXr $Rn, $Rm)>;
def : Pat<(int_aarch64_udiv GPR32:$Rn, GPR32:$Rm), (UDIVWr GPR32:$Rn, GPR32:$Rm)>;
def : Pat<(int_aarch64_udiv GPR64:$Rn, GPR64:$Rm), (UDIVXr GPR64:$Rn, GPR64:$Rm)>;
def : Pat<(int_aarch64_sdiv GPR32:$Rn, GPR32:$Rm), (SDIVWr GPR32:$Rn, GPR32:$Rm)>;
def : Pat<(int_aarch64_sdiv GPR64:$Rn, GPR64:$Rm), (SDIVXr GPR64:$Rn, GPR64:$Rm)>;
// Variable shift
defm ASRV : Shift<0b10, "asr", sra>;

View File

@ -0,0 +1,38 @@
# RUN: llc -mtriple=aarch64-- -run-pass=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
define void @sdiv_s32_gpr() { ret void }
...
---
# Check that we select a 32-bit GPR sdiv intrinsic into SDIVWrr for GPR32.
# Also check that we constrain the register class of the COPY to GPR32.
# CHECK-LABEL: name: sdiv_s32_gpr
name: sdiv_s32_gpr
legalized: true
regBankSelected: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr32, preferred-register: '' }
# CHECK-NEXT: - { id: 1, class: gpr32, preferred-register: '' }
# CHECK-NEXT: - { id: 2, class: gpr32, preferred-register: '' }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
# CHECK: body:
# CHECK: %0 = COPY %w0
# CHECK: %1 = COPY %w1
# CHECK: %2 = SDIVWr %0, %1
body: |
bb.0:
liveins: %w0, %w1
%0(s32) = COPY %w0
%1(s32) = COPY %w1
%2(s32) = G_INTRINSIC intrinsic(@llvm.aarch64.sdiv.i32), %0, %1
%w0 = COPY %2(s32)
...

View File

@ -170,11 +170,11 @@ def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // MIs[0] Operand 1
// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/1, [[ID:[0-9]+]],
// CHECK-NEXT: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/1, Intrinsic::mytarget_nop,
// CHECK-NEXT: // MIs[0] src1
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // (intrinsic_wo_chain:i32 [[ID]]:iPTR, GPR32:i32:$src1) => (MOV:i32 GPR32:i32:$src1)
// CHECK-NEXT: // (intrinsic_wo_chain:i32 [[ID:[0-9]+]]:iPTR, GPR32:i32:$src1) => (MOV:i32 GPR32:i32:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst

View File

@ -338,6 +338,7 @@ public:
enum PredicateKind {
OPM_ComplexPattern,
OPM_Instruction,
OPM_IntrinsicID,
OPM_Int,
OPM_LiteralInt,
OPM_LLT,
@ -519,6 +520,26 @@ public:
}
};
/// Generates code to check that an operand is an intrinsic ID.
class IntrinsicIDOperandMatcher : public OperandPredicateMatcher {
protected:
const CodeGenIntrinsic *II;
public:
IntrinsicIDOperandMatcher(const CodeGenIntrinsic *II)
: OperandPredicateMatcher(OPM_IntrinsicID), II(II) {}
static bool classof(const OperandPredicateMatcher *P) {
return P->getKind() == OPM_IntrinsicID;
}
void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule,
unsigned InsnVarID, unsigned OpIdx) const override {
OS << " GIM_CheckIntrinsicID, /*MI*/" << InsnVarID << ", /*Op*/"
<< OpIdx << ", Intrinsic::" << II->EnumName << ",\n";
}
};
/// Generates code to check that a set of predicates match for a particular
/// operand.
class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
@ -1513,14 +1534,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
// For G_INTRINSIC, the operand immediately following the defs is an
// intrinsic ID.
if (SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" && i == 0) {
if (!SrcChild->isLeaf())
return failedImport("Expected IntInit containing intrinsic ID");
if (IntInit *SrcChildIntInit =
dyn_cast<IntInit>(SrcChild->getLeafValue())) {
if (const CodeGenIntrinsic *II = Src->getIntrinsicInfo(CGP)) {
OperandMatcher &OM =
InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx);
OM.addPredicate<LiteralIntOperandMatcher>(SrcChildIntInit->getValue());
OM.addPredicate<IntrinsicIDOperandMatcher>(II);
continue;
}