Index: llvm/trunk/include/llvm/Target/Target.td =================================================================== --- llvm/trunk/include/llvm/Target/Target.td +++ llvm/trunk/include/llvm/Target/Target.td @@ -568,6 +568,12 @@ /// can be queried via the getNamedOperandIdx() function which is generated /// by TableGen. bit UseNamedOperandTable = 0; + + /// Should FastISel ignore this instruction. For certain ISAs, they have + /// instructions which map to the same ISD Opcode, value type operands and + /// instruction selection predicates. FastISel cannot handle such cases, but + /// SelectionDAG can. + bit FastISelShouldIgnore = 0; } /// PseudoInstExpansion - Expansion information for a pseudo-instruction. Index: llvm/trunk/test/TableGen/FastISelEmitter.td =================================================================== --- llvm/trunk/test/TableGen/FastISelEmitter.td +++ llvm/trunk/test/TableGen/FastISelEmitter.td @@ -0,0 +1,37 @@ +// RUN: llvm-tblgen --gen-fast-isel -I %p/../../include %s 2>&1 | FileCheck %s + +include "llvm/Target/Target.td" + +//===- Define the necessary boilerplate for our test target. --------------===// + +def MyTargetISA : InstrInfo; +def MyTarget : Target { let InstructionSet = MyTargetISA; } + +def R0 : Register<"r0"> { let Namespace = "MyTarget"; } +def R1 : Register<"r0"> { let Namespace = "MyTarget"; } +def GPR32M : RegisterClass<"MyTarget", [i32], 32, (add R0)>; +def GPR32MOp : RegisterOperand; + +def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0, R1)>; +def GPR32Op : RegisterOperand; + +class I Pat> : Instruction { + let Namespace = "MyTarget"; + let OutOperandList = OOps; + let InOperandList = IOps; + let Pattern = Pat; +} + +def HasA : Predicate<"Subtarget->hasA()">; + +let Predicates = [HasA] in { + + def ADD : I<(outs GPR32Op:$rd), (ins GPR32Op:$rs, GPR32Op:$rt), + [(set GPR32Op:$rd, (add GPR32Op:$rs, GPR32Op:$rt))]>; + + let FastISelShouldIgnore = 1 in + def ADD_M : I<(outs GPR32MOp:$rd), (ins GPR32MOp:$rs, GPR32MOp:$rt), + [(set GPR32MOp:$rd, (add GPR32MOp:$rs, GPR32MOp:$rt))]>; +} + +// CHECK-NOT: error: Duplicate predicate in FastISel table! Index: llvm/trunk/utils/TableGen/CodeGenInstruction.h =================================================================== --- llvm/trunk/utils/TableGen/CodeGenInstruction.h +++ llvm/trunk/utils/TableGen/CodeGenInstruction.h @@ -258,6 +258,7 @@ bool isInsertSubreg : 1; bool isConvergent : 1; bool hasNoSchedulingInfo : 1; + bool FastISelShouldIgnore : 1; std::string DeprecatedReason; bool HasComplexDeprecationPredicate; Index: llvm/trunk/utils/TableGen/CodeGenInstruction.cpp =================================================================== --- llvm/trunk/utils/TableGen/CodeGenInstruction.cpp +++ llvm/trunk/utils/TableGen/CodeGenInstruction.cpp @@ -327,6 +327,7 @@ isInsertSubreg = R->getValueAsBit("isInsertSubreg"); isConvergent = R->getValueAsBit("isConvergent"); hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo"); + FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore"); bool Unset; mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset); Index: llvm/trunk/utils/TableGen/FastISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/FastISelEmitter.cpp +++ llvm/trunk/utils/TableGen/FastISelEmitter.cpp @@ -453,6 +453,13 @@ if (II.Operands.empty()) continue; + // Allow instructions to be marked as unavailable for FastISel for + // certain cases, i.e. an ISA has two 'and' instruction which differ + // by what registers they can use but are otherwise identical for + // codegen purposes. + if (II.FastISelShouldIgnore) + continue; + // For now, ignore multi-instruction patterns. bool MultiInsts = false; for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) {