diff --git a/llvm/test/TableGen/GlobalISelEmitter-multi-output.td b/llvm/test/TableGen/GlobalISelEmitter-multi-output.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/GlobalISelEmitter-multi-output.td @@ -0,0 +1,32 @@ +// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -I %p/../../include -I %p/Common %s -o - < %s | FileCheck %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +def NormalInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>; + +let Defs = [R0] in +def MultiOutInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>; + +// CHECK: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// CHECK-NEXT: // MIs[0] dst +// 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] src +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: // MIs[0] src +// CHECK-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1, +// CHECK-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src, i32:{ *:[i32] }:$src) => (NormalInstr:{ *:[i32] } (MultiOutInstr:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$src)) +// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32, +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::MultiOutInstr, +// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1, +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::NormalInstr, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +def : Pat<(i32 (add i32:$src, i32:$src)), + (NormalInstr (MultiOutInstr GPR32:$src))>; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -3467,9 +3467,11 @@ static Expected getInstResultType(const TreePatternNode *Dst) { ArrayRef ChildTypes = Dst->getExtTypes(); - if (ChildTypes.size() != 1) - return failedImport("Dst pattern child has multiple results"); + if (ChildTypes.size() < 1) + return failedImport("Dst pattern child has no result"); + // If there are multiple results, just take the first one (this is how + // SelectionIDAG does it). Optional MaybeOpTy; if (ChildTypes.front().isMachineValueType()) { MaybeOpTy = @@ -4924,8 +4926,9 @@ // We don't have a leaf node, so we have to try and infer something. Check // that we have an instruction that we an infer something from. - // Only handle things that produce a single type. - if (N->getNumTypes() != 1) + // Only handle things that produce at least one value (if multiple values, + // just take the first one). + if (N->getNumTypes() < 1) return None; Record *OpRec = N->getOperator();