38 changes: 19 additions & 19 deletions llvm/test/TableGen/GlobalISelEmitter.td
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: // MIs[0] src3
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex,
// CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, complex:i32:$src3) => (INSN2:i32 GPR32:i32:$src1, complex:i32:$src3, complex:i32:$src2)
// CHECK-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3) => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -196,7 +196,7 @@ def : Pat<(select GPR32:$src1, complex:$src2, (select GPR32:$src3, complex:$src4
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/3, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/3, /*Renderer*/2, GICP_gi_complex,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, (select:i32 GPR32:i32:$src3, complex:i32:$src4, complex:i32:$src5)) => (INSN3:i32 GPR32:i32:$src1, complex:i32:$src2, GPR32:i32:$src3, complex:i32:$src4, complex:i32:$src5)
// CHECK-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, (select:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, complex:{ *:[i32] }:$src5)) => (INSN3:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, complex:{ *:[i32] }:$src5)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN3,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -230,7 +230,7 @@ def : Pat<(select GPR32:$src1, complex:$src2, complex:$src3),
// CHECK-NEXT: // MIs[0] src2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2)
// CHECK-NEXT: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
Expand All @@ -253,7 +253,7 @@ def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
// 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:[0-9]+]]: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
Expand Down Expand Up @@ -292,7 +292,7 @@ def MOV : I<(outs GPR32:$dst), (ins GPR32:$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: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (mul:i32 (add:i32 GPR32:i32:$src1, GPR32:i32:$src2), GPR32:i32:$src3) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3)
// CHECK-NEXT: // (mul:{ *:[i32] } (add:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2), GPR32:{ *:[i32] }:$src3) => (MULADD:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -328,7 +328,7 @@ def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1),
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (mul:i32 GPR32:i32:$src3, (add:i32 GPR32:i32:$src1, GPR32:i32:$src2)) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3)
// CHECK-NEXT: // (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src3, (add:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2)) => (MULADD:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -359,7 +359,7 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
// CHECK-NEXT: // MIs[0] src2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1)
// CHECK-NEXT: // (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (MUL:{ *:[i32] } GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MUL,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src2
Expand Down Expand Up @@ -410,7 +410,7 @@ def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/2,
// CHECK-NEXT: // (sub:i32 (sub:i32 GPR32:i32:$src1, GPR32:i32:$src2), (sub:i32 GPR32:i32:$src3, GPR32:i32:$src4)) => (INSNBOB:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3, GPR32:i32:$src4)
// CHECK-NEXT: // (sub:{ *:[i32] } (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2), (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)) => (INSNBOB:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSNBOB,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -442,7 +442,7 @@ def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, G
// CHECK-NEXT: // MIs[0] src2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
// CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2)
// CHECK-NEXT: // (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2) => (INSN1:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN1,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
Expand Down Expand Up @@ -470,7 +470,7 @@ def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>;
// CHECK-NEXT: // MIs[0] Operand 2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -2
// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -2:i32) => (XORI:i32 GPR32:i32:$src1)
// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -2:{ *:[i32] }) => (XORI:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORI,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
Expand Down Expand Up @@ -499,7 +499,7 @@ def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
// CHECK-NEXT: // MIs[0] Operand 2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -3
// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -3:i32) => (XOR:i32 GPR32:i32:$src1)
// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -3:{ *:[i32] }) => (XOR:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XOR,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
Expand Down Expand Up @@ -528,7 +528,7 @@ def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1),
// CHECK-NEXT: // MIs[0] Operand 2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -4
// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -4:i32) => (XORlike:i32 GPR32:i32:$src1)
// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -4:{ *:[i32] }) => (XORlike:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORlike,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
Expand Down Expand Up @@ -558,7 +558,7 @@ def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
// CHECK-NEXT: // MIs[0] Operand 2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -5,
// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1)
// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -5:{ *:[i32] }) => (XORManyDefaults:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORManyDefaults,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
Expand Down Expand Up @@ -591,7 +591,7 @@ def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1)
// CHECK-NEXT: // MIs[0] Operand 2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm)
// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$Wm, -1:{ *:[i32] }) => (ORN:{ *:[i32] } R0:{ *:[i32] }, GPR32:{ *:[i32] }:$Wm)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ORN,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
Expand All @@ -616,7 +616,7 @@ def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
// CHECK-NEXT: // MIs[0] src1
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::FPR32RegClassID,
// CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32)
// CHECK-NEXT: // (bitconvert:{ *:[i32] } FPR32:{ *:[f32] }:$src1) => (COPY_TO_REGCLASS:{ *:[i32] } FPR32:{ *:[f32] }:$src1, GPR32:{ *:[i32] })
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1,
// CHECK-NEXT: GIR_Done,
Expand All @@ -635,7 +635,7 @@ def : Pat<(i32 (bitconvert FPR32:$src1)),
// 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, 1,
// CHECK-NEXT: // 1:i32 => (MOV1:i32)
// CHECK-NEXT: // 1:{ *:[i32] } => (MOV1:{ *:[i32] })
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV1,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
Expand All @@ -656,7 +656,7 @@ def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // MIs[0] Operand 1
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: // (imm:i32)<<P:Predicate_simm8>>:$imm => (MOVimm8:i32 (imm:i32):$imm)
// CHECK-NEXT: // (imm:{ *:[i32] })<<P:Predicate_simm8>>:$imm => (MOVimm8:{ *:[i32] } (imm:{ *:[i32] }):$imm)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm8,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
Expand All @@ -678,7 +678,7 @@ def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$i
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: // MIs[0] Operand 1
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: // (imm:i32):$imm => (MOVimm:i32 (imm:i32):$imm)
// CHECK-NEXT: // (imm:{ *:[i32] }):$imm => (MOVimm:{ *:[i32] } (imm:{ *:[i32] }):$imm)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
Expand All @@ -696,7 +696,7 @@ def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR,
// CHECK-NEXT: // MIs[0] target
// CHECK-NEXT: GIM_CheckIsMBB, /*MI*/0, /*Op*/0,
// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target)
// CHECK-NEXT: // (br (bb:{ *:[Other] }):$target) => (BR (bb:{ *:[Other] }):$target)
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
Expand Down
27 changes: 27 additions & 0 deletions llvm/test/TableGen/HwModeSelect.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include %s 2>&1 | FileCheck %s

// The HwModeSelect class is intended to serve as a base class for other
// classes that are then used to select a value based on the HW mode.
// It contains a list of HW modes, and a derived class should provide a
// list of corresponding values.
// These two lists must have the same size. Make sure that a violation of
// this requirement is diagnosed.

include "llvm/Target/Target.td"

def TestTargetInstrInfo : InstrInfo;

def TestTarget : Target {
let InstructionSet = TestTargetInstrInfo;
}

def TestReg : Register<"testreg">;
def TestClass : RegisterClass<"TestTarget", [i32], 32, (add TestReg)>;

def TestMode1 : HwMode<"+feat1">;
def TestMode2 : HwMode<"+feat2">;

def BadDef : ValueTypeByHwMode<[TestMode1, TestMode2, DefaultMode],
[i8, i16, i32, i64]>;

// CHECK: error: in record BadDef derived from HwModeSelect: the lists Modes and Objects should have the same size
2 changes: 2 additions & 0 deletions llvm/utils/TableGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_tablegen(llvm-tblgen LLVM
CallingConvEmitter.cpp
CodeEmitterGen.cpp
CodeGenDAGPatterns.cpp
CodeGenHwModes.cpp
CodeGenInstruction.cpp
CodeGenMapTable.cpp
CodeGenRegisters.cpp
Expand All @@ -23,6 +24,7 @@ add_tablegen(llvm-tblgen LLVM
FastISelEmitter.cpp
FixedLenDecoderEmitter.cpp
GlobalISelEmitter.cpp
InfoByHwMode.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
OptParserEmitter.cpp
Expand Down
1,746 changes: 1,017 additions & 729 deletions llvm/utils/TableGen/CodeGenDAGPatterns.cpp

Large diffs are not rendered by default.

468 changes: 289 additions & 179 deletions llvm/utils/TableGen/CodeGenDAGPatterns.h

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions llvm/utils/TableGen/CodeGenHwModes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//===--- CodeGenHwModes.cpp -----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Classes to parse and store HW mode information for instruction selection
//===----------------------------------------------------------------------===//

#include "CodeGenHwModes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"

using namespace llvm;

StringRef CodeGenHwModes::DefaultModeName = "DefaultMode";

HwMode::HwMode(Record *R) {
Name = R->getName();
Features = R->getValueAsString("Features");
}

LLVM_DUMP_METHOD
void HwMode::dump() const {
dbgs() << Name << ": " << Features << '\n';
}

HwModeSelect::HwModeSelect(Record *R, CodeGenHwModes &CGH) {
std::vector<Record*> Modes = R->getValueAsListOfDefs("Modes");
std::vector<Record*> Objects = R->getValueAsListOfDefs("Objects");
if (Modes.size() != Objects.size()) {
PrintError(R->getLoc(), "in record " + R->getName() +
" derived from HwModeSelect: the lists Modes and Objects should "
"have the same size");
report_fatal_error("error in target description.");
}
for (unsigned i = 0, e = Modes.size(); i != e; ++i) {
unsigned ModeId = CGH.getHwModeId(Modes[i]->getName());
Items.push_back(std::make_pair(ModeId, Objects[i]));
}
}

LLVM_DUMP_METHOD
void HwModeSelect::dump() const {
dbgs() << '{';
for (const PairType &P : Items)
dbgs() << " (" << P.first << ',' << P.second->getName() << ')';
dbgs() << " }\n";
}

CodeGenHwModes::CodeGenHwModes(RecordKeeper &RK) : Records(RK) {
std::vector<Record*> MRs = Records.getAllDerivedDefinitions("HwMode");
// The default mode needs a definition in the .td sources for TableGen
// to accept references to it. We need to ignore the definition here.
for (auto I = MRs.begin(), E = MRs.end(); I != E; ++I) {
if ((*I)->getName() != DefaultModeName)
continue;
MRs.erase(I);
break;
}

for (Record *R : MRs) {
Modes.emplace_back(R);
unsigned NewId = Modes.size();
ModeIds.insert(std::make_pair(Modes[NewId-1].Name, NewId));
}

std::vector<Record*> MSs = Records.getAllDerivedDefinitions("HwModeSelect");
for (Record *R : MSs) {
auto P = ModeSelects.emplace(std::make_pair(R, HwModeSelect(R, *this)));
assert(P.second);
(void)P;
}
}

unsigned CodeGenHwModes::getHwModeId(StringRef Name) const {
if (Name == DefaultModeName)
return DefaultMode;
auto F = ModeIds.find(Name);
assert(F != ModeIds.end() && "Unknown mode name");
return F->second;
}

const HwModeSelect &CodeGenHwModes::getHwModeSelect(Record *R) const {
auto F = ModeSelects.find(R);
assert(F != ModeSelects.end() && "Record is not a \"mode select\"");
return F->second;
}

LLVM_DUMP_METHOD
void CodeGenHwModes::dump() const {
dbgs() << "Modes: {\n";
for (const HwMode &M : Modes) {
dbgs() << " ";
M.dump();
}
dbgs() << "}\n";

dbgs() << "ModeIds: {\n";
for (const auto &P : ModeIds)
dbgs() << " " << P.first() << " -> " << P.second << '\n';
dbgs() << "}\n";

dbgs() << "ModeSelects: {\n";
for (const auto &P : ModeSelects) {
dbgs() << " " << P.first->getName() << " -> ";
P.second.dump();
}
dbgs() << "}\n";
}
64 changes: 64 additions & 0 deletions llvm/utils/TableGen/CodeGenHwModes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===--- CodeGenHwModes.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Classes to parse and store HW mode information for instruction selection.
//===----------------------------------------------------------------------===//

#ifndef LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H
#define LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H

#include "llvm/ADT/StringMap.h"
#include <map>
#include <string>
#include <vector>

// HwModeId -> list of predicates (definition)

namespace llvm {
class Record;
class RecordKeeper;

struct CodeGenHwModes;

struct HwMode {
HwMode(Record *R);
StringRef Name;
std::string Features;
void dump() const;
};

struct HwModeSelect {
HwModeSelect(Record *R, CodeGenHwModes &CGH);
typedef std::pair<unsigned, Record*> PairType;
std::vector<PairType> Items;
void dump() const;
};

struct CodeGenHwModes {
enum : unsigned { DefaultMode = 0 };
static StringRef DefaultModeName;

CodeGenHwModes(RecordKeeper &R);
unsigned getHwModeId(StringRef Name) const;
const HwMode &getMode(unsigned Id) const {
assert(Id != 0 && "Mode id of 0 is reserved for the default mode");
return Modes[Id-1];
}
const HwModeSelect &getHwModeSelect(Record *R) const;
unsigned getNumModeIds() const { return Modes.size()+1; }
void dump() const;

private:
RecordKeeper &Records;
StringMap<unsigned> ModeIds; // HwMode (string) -> HwModeId
std::vector<HwMode> Modes;
std::map<Record*,HwModeSelect> ModeSelects;
};
}

#endif // LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H
6 changes: 3 additions & 3 deletions llvm/utils/TableGen/CodeGenInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
// Check to see if the first implicit def has a resolvable type.
Record *FirstImplicitDef = ImplicitDefs[0];
assert(FirstImplicitDef->isSubClassOf("Register"));
const std::vector<MVT::SimpleValueType> &RegVTs =
const std::vector<ValueTypeByHwMode> &RegVTs =
TargetInfo.getRegisterVTs(FirstImplicitDef);
if (RegVTs.size() == 1)
return RegVTs[0];
if (RegVTs.size() == 1 && RegVTs[0].isSimple())
return RegVTs[0].getSimple().SimpleTy;
return MVT::Other;
}

Expand Down
53 changes: 26 additions & 27 deletions llvm/utils/TableGen/CodeGenRegisters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
if (!Type->isSubClassOf("ValueType"))
PrintFatalError("RegTypes list member '" + Type->getName() +
"' does not derive from the ValueType class!");
VTs.push_back(getValueType(Type));
VTs.push_back(getValueTypeByHwMode(Type, RegBank.getHwModes()));
}
assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");

Expand Down Expand Up @@ -764,12 +764,22 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
}
}

// Allow targets to override the size in bits of the RegisterClass.
Namespace = R->getValueAsString("Namespace");

if (const RecordVal *RV = R->getValue("RegInfos"))
if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue()))
RSI = RegSizeInfoByHwMode(DI->getDef(), RegBank.getHwModes());
unsigned Size = R->getValueAsInt("Size");
assert((RSI.hasDefault() || Size != 0 || VTs[0].isSimple()) &&
"Impossible to determine register size");
if (!RSI.hasDefault()) {
RegSizeInfo RI;
RI.RegSize = RI.SpillSize = Size ? Size
: VTs[0].getSimple().getSizeInBits();
RI.SpillAlignment = R->getValueAsInt("Alignment");
RSI.Map.insert({DefaultMode, RI});
}

Namespace = R->getValueAsString("Namespace");
SpillSize = Size ? Size : MVT(VTs[0]).getSizeInBits();
SpillAlignment = R->getValueAsInt("Alignment");
CopyCost = R->getValueAsInt("CopyCost");
Allocatable = R->getValueAsBit("isAllocatable");
AltOrderSelect = R->getValueAsString("AltOrderSelect");
Expand All @@ -789,8 +799,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
Name(Name),
TopoSigs(RegBank.getNumTopoSigs()),
EnumValue(-1),
SpillSize(Props.SpillSize),
SpillAlignment(Props.SpillAlignment),
RSI(Props.RSI),
CopyCost(0),
Allocatable(true),
AllocationPriority(0) {
Expand Down Expand Up @@ -832,7 +841,7 @@ bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const {
namespace llvm {

raw_ostream &operator<<(raw_ostream &OS, const CodeGenRegisterClass::Key &K) {
OS << "{ S=" << K.SpillSize << ", A=" << K.SpillAlignment;
OS << "{ " << K.RSI.getAsString();
for (const auto R : *K.Members)
OS << ", " << R->getName();
return OS << " }";
Expand All @@ -845,8 +854,7 @@ namespace llvm {
bool CodeGenRegisterClass::Key::
operator<(const CodeGenRegisterClass::Key &B) const {
assert(Members && B.Members);
return std::tie(*Members, SpillSize, SpillAlignment) <
std::tie(*B.Members, B.SpillSize, B.SpillAlignment);
return std::tie(*Members, RSI) < std::tie(*B.Members, B.RSI);
}

// Returns true if RC is a strict subclass.
Expand All @@ -860,8 +868,7 @@ operator<(const CodeGenRegisterClass::Key &B) const {
//
static bool testSubClass(const CodeGenRegisterClass *A,
const CodeGenRegisterClass *B) {
return A->SpillAlignment && B->SpillAlignment % A->SpillAlignment == 0 &&
A->SpillSize <= B->SpillSize &&
return A->RSI.isSubClassOf(B->RSI) &&
std::includes(A->getMembers().begin(), A->getMembers().end(),
B->getMembers().begin(), B->getMembers().end(),
deref<llvm::less>());
Expand All @@ -880,16 +887,9 @@ static bool TopoOrderRC(const CodeGenRegisterClass &PA,
if (A == B)
return false;

// Order by ascending spill size.
if (A->SpillSize < B->SpillSize)
return true;
if (A->SpillSize > B->SpillSize)
return false;

// Order by ascending spill alignment.
if (A->SpillAlignment < B->SpillAlignment)
if (A->RSI < B->RSI)
return true;
if (A->SpillAlignment > B->SpillAlignment)
if (A->RSI != B->RSI)
return false;

// Order by descending set size. Note that the classes' allocation order may
Expand Down Expand Up @@ -1062,7 +1062,8 @@ void CodeGenRegisterClass::buildRegUnitSet(
// CodeGenRegBank
//===----------------------------------------------------------------------===//

CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) {
CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
const CodeGenHwModes &Modes) : CGH(Modes) {
// Configure register Sets to understand register classes and tuples.
Sets.addFieldExpander("RegisterClass", "MemberList");
Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
Expand Down Expand Up @@ -1202,7 +1203,7 @@ CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
const CodeGenRegister::Vec *Members,
StringRef Name) {
// Synthetic sub-class has the same size and alignment as RC.
CodeGenRegisterClass::Key K(Members, RC->SpillSize, RC->SpillAlignment);
CodeGenRegisterClass::Key K(Members, RC->RSI);
RCKeyMap::const_iterator FoundI = Key2RC.find(K);
if (FoundI != Key2RC.end())
return FoundI->second;
Expand Down Expand Up @@ -2050,10 +2051,8 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
continue;

// If RC1 and RC2 have different spill sizes or alignments, use the
// larger size for sub-classing. If they are equal, prefer RC1.
if (RC2->SpillSize > RC1->SpillSize ||
(RC2->SpillSize == RC1->SpillSize &&
RC2->SpillAlignment > RC1->SpillAlignment))
// stricter one for sub-classing. If they are equal, prefer RC1.
if (RC2->RSI.hasStricterSpillThan(RC1->RSI))
std::swap(RC1, RC2);

getOrCreateSubClass(RC1, &Intersection,
Expand Down
32 changes: 15 additions & 17 deletions llvm/utils/TableGen/CodeGenRegisters.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENREGISTERS_H
#define LLVM_UTILS_TABLEGEN_CODEGENREGISTERS_H

#include "InfoByHwMode.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -319,9 +320,8 @@ namespace llvm {
public:
unsigned EnumValue;
StringRef Namespace;
SmallVector<MVT::SimpleValueType, 4> VTs;
unsigned SpillSize;
unsigned SpillAlignment;
SmallVector<ValueTypeByHwMode, 4> VTs;
RegSizeInfoByHwMode RSI;
int CopyCost;
bool Allocatable;
StringRef AltOrderSelect;
Expand All @@ -338,13 +338,10 @@ namespace llvm {

const std::string &getName() const { return Name; }
std::string getQualifiedName() const;
ArrayRef<MVT::SimpleValueType> getValueTypes() const {return VTs;}
bool hasValueType(MVT::SimpleValueType VT) const {
return std::find(VTs.begin(), VTs.end(), VT) != VTs.end();
}
ArrayRef<ValueTypeByHwMode> getValueTypes() const { return VTs; }
unsigned getNumValueTypes() const { return VTs.size(); }

MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const {
ValueTypeByHwMode getValueTypeNum(unsigned VTNum) const {
if (VTNum < VTs.size())
return VTs[VTNum];
llvm_unreachable("VTNum greater than number of ValueTypes in RegClass!");
Expand Down Expand Up @@ -439,18 +436,15 @@ namespace llvm {
// the topological order used for the EnumValues.
struct Key {
const CodeGenRegister::Vec *Members;
unsigned SpillSize;
unsigned SpillAlignment;
RegSizeInfoByHwMode RSI;

Key(const CodeGenRegister::Vec *M, unsigned S = 0, unsigned A = 0)
: Members(M), SpillSize(S), SpillAlignment(A) {}
Key(const CodeGenRegister::Vec *M, const RegSizeInfoByHwMode &I)
: Members(M), RSI(I) {}

Key(const CodeGenRegisterClass &RC)
: Members(&RC.getMembers()),
SpillSize(RC.SpillSize),
SpillAlignment(RC.SpillAlignment) {}
: Members(&RC.getMembers()), RSI(RC.RSI) {}

// Lexicographical order of (Members, SpillSize, SpillAlignment).
// Lexicographical order of (Members, RegSizeInfoByHwMode).
bool operator<(const Key&) const;
};

Expand Down Expand Up @@ -513,6 +507,8 @@ namespace llvm {
class CodeGenRegBank {
SetTheory Sets;

const CodeGenHwModes &CGH;

std::deque<CodeGenSubRegIndex> SubRegIndices;
DenseMap<Record*, CodeGenSubRegIndex*> Def2SubRegIdx;

Expand Down Expand Up @@ -596,10 +592,12 @@ namespace llvm {
void computeRegUnitLaneMasks();

public:
CodeGenRegBank(RecordKeeper&);
CodeGenRegBank(RecordKeeper&, const CodeGenHwModes&);

SetTheory &getSets() { return Sets; }

const CodeGenHwModes &getHwModes() const { return CGH; }

// Sub-register indices. The first NumNamedIndices are defined by the user
// in the .td files. The rest are synthesized such that all sub-registers
// have a unique name.
Expand Down
16 changes: 8 additions & 8 deletions llvm/utils/TableGen/CodeGenTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ std::string llvm::getQualifiedName(const Record *R) {
/// getTarget - Return the current instance of the Target class.
///
CodeGenTarget::CodeGenTarget(RecordKeeper &records)
: Records(records) {
: Records(records), CGH(records) {
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() == 0)
PrintFatalError("ERROR: No 'Target' subclasses defined!");
Expand Down Expand Up @@ -266,7 +266,7 @@ Record *CodeGenTarget::getAsmWriter() const {

CodeGenRegBank &CodeGenTarget::getRegBank() const {
if (!RegBank)
RegBank = llvm::make_unique<CodeGenRegBank>(Records);
RegBank = llvm::make_unique<CodeGenRegBank>(Records, getHwModes());
return *RegBank;
}

Expand All @@ -285,19 +285,19 @@ const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
return I->second;
}

std::vector<MVT::SimpleValueType> CodeGenTarget::
getRegisterVTs(Record *R) const {
std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
const {
const CodeGenRegister *Reg = getRegBank().getReg(R);
std::vector<MVT::SimpleValueType> Result;
std::vector<ValueTypeByHwMode> Result;
for (const auto &RC : getRegBank().getRegClasses()) {
if (RC.contains(Reg)) {
ArrayRef<MVT::SimpleValueType> InVTs = RC.getValueTypes();
ArrayRef<ValueTypeByHwMode> InVTs = RC.getValueTypes();
Result.insert(Result.end(), InVTs.begin(), InVTs.end());
}
}

// Remove duplicates.
array_pod_sort(Result.begin(), Result.end());
std::sort(Result.begin(), Result.end());
Result.erase(std::unique(Result.begin(), Result.end()), Result.end());
return Result;
}
Expand All @@ -308,7 +308,7 @@ void CodeGenTarget::ReadLegalValueTypes() const {
LegalValueTypes.insert(LegalValueTypes.end(), RC.VTs.begin(), RC.VTs.end());

// Remove duplicates.
array_pod_sort(LegalValueTypes.begin(), LegalValueTypes.end());
std::sort(LegalValueTypes.begin(), LegalValueTypes.end());
LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
LegalValueTypes.end()),
LegalValueTypes.end());
Expand Down
21 changes: 10 additions & 11 deletions llvm/utils/TableGen/CodeGenTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENTARGET_H
#define LLVM_UTILS_TABLEGEN_CODEGENTARGET_H

#include "CodeGenHwModes.h"
#include "CodeGenInstruction.h"
#include "CodeGenRegisters.h"
#include "InfoByHwMode.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Record.h"
#include <algorithm>
Expand Down Expand Up @@ -69,7 +71,8 @@ class CodeGenTarget {
std::unique_ptr<CodeGenInstruction>> Instructions;
mutable std::unique_ptr<CodeGenRegBank> RegBank;
mutable std::vector<Record*> RegAltNameIndices;
mutable SmallVector<MVT::SimpleValueType, 8> LegalValueTypes;
mutable SmallVector<ValueTypeByHwMode, 8> LegalValueTypes;
CodeGenHwModes CGH;
void ReadRegAltNameIndices() const;
void ReadInstructions() const;
void ReadLegalValueTypes() const;
Expand Down Expand Up @@ -128,22 +131,18 @@ class CodeGenTarget {

/// getRegisterVTs - Find the union of all possible SimpleValueTypes for the
/// specified physical register.
std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const;
std::vector<ValueTypeByHwMode> getRegisterVTs(Record *R) const;

ArrayRef<MVT::SimpleValueType> getLegalValueTypes() const {
if (LegalValueTypes.empty()) ReadLegalValueTypes();
ArrayRef<ValueTypeByHwMode> getLegalValueTypes() const {
if (LegalValueTypes.empty())
ReadLegalValueTypes();
return LegalValueTypes;
}

/// isLegalValueType - Return true if the specified value type is natively
/// supported by the target (i.e. there are registers that directly hold it).
bool isLegalValueType(MVT::SimpleValueType VT) const {
ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes();
return is_contained(LegalVTs, VT);
}

CodeGenSchedModels &getSchedModels() const;

const CodeGenHwModes &getHwModes() const { return CGH; }

private:
DenseMap<const Record*, std::unique_ptr<CodeGenInstruction>> &
getInstructions() const {
Expand Down
8 changes: 4 additions & 4 deletions llvm/utils/TableGen/DAGISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ struct PatternSortingPredicate {
CodeGenDAGPatterns &CGP;

bool operator()(const PatternToMatch *LHS, const PatternToMatch *RHS) {
const TreePatternNode *LHSSrc = LHS->getSrcPattern();
const TreePatternNode *RHSSrc = RHS->getSrcPattern();
const TreePatternNode *LT = LHS->getSrcPattern();
const TreePatternNode *RT = RHS->getSrcPattern();

MVT LHSVT = (LHSSrc->getNumTypes() != 0 ? LHSSrc->getType(0) : MVT::Other);
MVT RHSVT = (RHSSrc->getNumTypes() != 0 ? RHSSrc->getType(0) : MVT::Other);
MVT LHSVT = LT->getNumTypes() != 0 ? LT->getSimpleType(0) : MVT::Other;
MVT RHSVT = RT->getNumTypes() != 0 ? RT->getSimpleType(0) : MVT::Other;
if (LHSVT.isVector() != RHSVT.isVector())
return RHSVT.isVector();

Expand Down
50 changes: 31 additions & 19 deletions llvm/utils/TableGen/DAGISelMatcherGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ static MVT::SimpleValueType getRegisterValueType(Record *R,

if (!FoundRC) {
FoundRC = true;
VT = RC.getValueTypeNum(0);
ValueTypeByHwMode VVT = RC.getValueTypeNum(0);
if (VVT.isSimple())
VT = VVT.getSimple().SimpleTy;
continue;
}

// If this occurs in multiple register classes, they all have to agree.
assert(VT == RC.getValueTypeNum(0));
#ifndef NDEBUG
ValueTypeByHwMode T = RC.getValueTypeNum(0);
assert((!T.isSimple() || T.getSimple().SimpleTy == VT) &&
"ValueType mismatch between register classes for this register");
#endif
}
return VT;
}
Expand Down Expand Up @@ -105,13 +111,15 @@ namespace {
Matcher *GetMatcher() const { return TheMatcher; }
private:
void AddMatcher(Matcher *NewNode);
void InferPossibleTypes();
void InferPossibleTypes(unsigned ForceMode);

// Matcher Generation.
void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes);
void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes,
unsigned ForceMode);
void EmitLeafMatchCode(const TreePatternNode *N);
void EmitOperatorMatchCode(const TreePatternNode *N,
TreePatternNode *NodeNoTypes);
TreePatternNode *NodeNoTypes,
unsigned ForceMode);

/// If this is the first time a node with unique identifier Name has been
/// seen, record it. Otherwise, emit a check to make sure this is the same
Expand Down Expand Up @@ -164,17 +172,19 @@ MatcherGen::MatcherGen(const PatternToMatch &pattern,
PatWithNoTypes->RemoveAllTypes();

// If there are types that are manifestly known, infer them.
InferPossibleTypes();
InferPossibleTypes(Pattern.ForceMode);
}

/// InferPossibleTypes - As we emit the pattern, we end up generating type
/// checks and applying them to the 'PatWithNoTypes' tree. As we do this, we
/// want to propagate implied types as far throughout the tree as possible so
/// that we avoid doing redundant type checks. This does the type propagation.
void MatcherGen::InferPossibleTypes() {
void MatcherGen::InferPossibleTypes(unsigned ForceMode) {
// TP - Get *SOME* tree pattern, we don't care which. It is only used for
// diagnostics, which we know are impossible at this point.
TreePattern &TP = *CGP.pf_begin()->second;
TP.getInfer().CodeGen = true;
TP.getInfer().ForceMode = ForceMode;

bool MadeChange = true;
while (MadeChange)
Expand Down Expand Up @@ -281,7 +291,8 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
}

void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
TreePatternNode *NodeNoTypes) {
TreePatternNode *NodeNoTypes,
unsigned ForceMode) {
assert(!N->isLeaf() && "Not an operator?");

if (N->getOperator()->isSubClassOf("ComplexPattern")) {
Expand Down Expand Up @@ -334,7 +345,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,

// Match the LHS of the AND as appropriate.
AddMatcher(new MoveChildMatcher(0));
EmitMatchCode(N->getChild(0), NodeNoTypes->getChild(0));
EmitMatchCode(N->getChild(0), NodeNoTypes->getChild(0), ForceMode);
AddMatcher(new MoveParentMatcher());
return;
}
Expand Down Expand Up @@ -433,7 +444,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// Get the code suitable for matching this child. Move to the child, check
// it then move back to the parent.
AddMatcher(new MoveChildMatcher(OpNo));
EmitMatchCode(N->getChild(i), NodeNoTypes->getChild(i));
EmitMatchCode(N->getChild(i), NodeNoTypes->getChild(i), ForceMode);
AddMatcher(new MoveParentMatcher());
}
}
Expand All @@ -456,7 +467,8 @@ bool MatcherGen::recordUniqueNode(const std::string &Name) {
}

void MatcherGen::EmitMatchCode(const TreePatternNode *N,
TreePatternNode *NodeNoTypes) {
TreePatternNode *NodeNoTypes,
unsigned ForceMode) {
// If N and NodeNoTypes don't agree on a type, then this is a case where we
// need to do a type check. Emit the check, apply the type to NodeNoTypes and
// reinfer any correlated types.
Expand All @@ -465,7 +477,7 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) {
if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue;
NodeNoTypes->setType(i, N->getExtType(i));
InferPossibleTypes();
InferPossibleTypes(ForceMode);
ResultsToTypeCheck.push_back(i);
}

Expand All @@ -478,14 +490,14 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
if (N->isLeaf())
EmitLeafMatchCode(N);
else
EmitOperatorMatchCode(N, NodeNoTypes);
EmitOperatorMatchCode(N, NodeNoTypes, ForceMode);

// If there are node predicates for this node, generate their checks.
for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i]));

for (unsigned i = 0, e = ResultsToTypeCheck.size(); i != e; ++i)
AddMatcher(new CheckTypeMatcher(N->getType(ResultsToTypeCheck[i]),
AddMatcher(new CheckTypeMatcher(N->getSimpleType(ResultsToTypeCheck[i]),
ResultsToTypeCheck[i]));
}

Expand All @@ -509,7 +521,7 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
}

// Emit the matcher for the pattern structure and types.
EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes);
EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes, Pattern.ForceMode);

// If the pattern has a predicate on it (e.g. only enabled when a subtarget
// feature is around, do the check).
Expand Down Expand Up @@ -606,7 +618,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
assert(N->isLeaf() && "Must be a leaf");

if (IntInit *II = dyn_cast<IntInit>(N->getLeafValue())) {
AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType(0)));
AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getSimpleType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
Expand All @@ -617,13 +629,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
if (Def->isSubClassOf("Register")) {
const CodeGenRegister *Reg =
CGP.getTargetInfo().getRegBank().getReg(Def);
AddMatcher(new EmitRegisterMatcher(Reg, N->getType(0)));
AddMatcher(new EmitRegisterMatcher(Reg, N->getSimpleType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}

if (Def->getName() == "zero_reg") {
AddMatcher(new EmitRegisterMatcher(nullptr, N->getType(0)));
AddMatcher(new EmitRegisterMatcher(nullptr, N->getSimpleType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
Expand Down Expand Up @@ -834,7 +846,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// Determine the result types.
SmallVector<MVT::SimpleValueType, 4> ResultVTs;
for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i)
ResultVTs.push_back(N->getType(i));
ResultVTs.push_back(N->getSimpleType(i));

// If this is the root instruction of a pattern that has physical registers in
// its result pattern, add output VTs for them. For example, X86 has:
Expand Down
17 changes: 9 additions & 8 deletions llvm/utils/TableGen/FastISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,11 @@ struct OperandsSignature {
TreePredicateFn PredFn = ImmPredicates.getPredicate(Code-1);

// Emit the type check.
OS << "VT == "
<< getEnumName(PredFn.getOrigPatFragRecord()->getTree(0)->getType(0))
<< " && ";

TreePattern *TP = PredFn.getOrigPatFragRecord();
ValueTypeByHwMode VVT = TP->getTree(0)->getType(0);
assert(VVT.isSimple() &&
"Cannot use variable value types with fast isel");
OS << "VT == " << getEnumName(VVT.getSimple().SimpleTy) << " && ";

OS << PredFn.getFnName() << "(imm" << i <<')';
EmittedAnything = true;
Expand Down Expand Up @@ -236,12 +237,12 @@ struct OperandsSignature {
return false;
}

assert(Op->hasTypeSet(0) && "Type infererence not done?");
assert(Op->hasConcreteType(0) && "Type infererence not done?");

// For now, all the operands must have the same type (if they aren't
// immediates). Note that this causes us to reject variable sized shifts
// on X86.
if (Op->getType(0) != VT)
if (Op->getSimpleType(0) != VT)
return false;

DefInit *OpDI = dyn_cast<DefInit>(Op->getLeafValue());
Expand Down Expand Up @@ -502,11 +503,11 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
Record *InstPatOp = InstPatNode->getOperator();
std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
MVT::SimpleValueType RetVT = MVT::isVoid;
if (InstPatNode->getNumTypes()) RetVT = InstPatNode->getType(0);
if (InstPatNode->getNumTypes()) RetVT = InstPatNode->getSimpleType(0);
MVT::SimpleValueType VT = RetVT;
if (InstPatNode->getNumChildren()) {
assert(InstPatNode->getChild(0)->getNumTypes() == 1);
VT = InstPatNode->getChild(0)->getType(0);
VT = InstPatNode->getChild(0)->getSimpleType(0);
}

// For now, filter out any instructions with predicates.
Expand Down
41 changes: 24 additions & 17 deletions llvm/utils/TableGen/GlobalISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1893,7 +1893,7 @@ class GlobalISelEmitter {
void gatherNodeEquivs();
const CodeGenInstruction *findNodeEquiv(Record *N) const;

Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates);
Error importRulePredicates(RuleMatcher &M, ArrayRef<Predicate> Predicates);
Expected<InstructionMatcher &>
createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher,
const TreePatternNode *Src,
Expand Down Expand Up @@ -1940,17 +1940,19 @@ const CodeGenInstruction *GlobalISelEmitter::findNodeEquiv(Record *N) const {
}

GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK)
: RK(RK), CGP(RK), Target(CGP.getTargetInfo()), CGRegs(RK) {}
: RK(RK), CGP(RK), Target(CGP.getTargetInfo()),
CGRegs(RK, Target.getHwModes()) {}

//===- Emitter ------------------------------------------------------------===//

Error
GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
ArrayRef<Init *> Predicates) {
for (const Init *Predicate : Predicates) {
const DefInit *PredicateDef = static_cast<const DefInit *>(Predicate);
declareSubtargetFeature(PredicateDef->getDef());
M.addRequiredFeature(PredicateDef->getDef());
ArrayRef<Predicate> Predicates) {
for (const Predicate &P : Predicates) {
if (!P.Def)
continue;
declareSubtargetFeature(P.Def);
M.addRequiredFeature(P.Def);
}

return Error::success();
Expand Down Expand Up @@ -1986,9 +1988,10 @@ GlobalISelEmitter::createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher,
}

unsigned OpIdx = 0;
for (const EEVT::TypeSet &Ty : Src->getExtTypes()) {
auto OpTyOrNone = MVTToLLT(Ty.getConcrete());

for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
auto OpTyOrNone = VTy.isMachineValueType()
? MVTToLLT(VTy.getMachineValueType().SimpleTy)
: None;
if (!OpTyOrNone)
return failedImport(
"Result of Src pattern operator has an unsupported type");
Expand Down Expand Up @@ -2064,7 +2067,7 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher,
OperandMatcher &OM =
InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx);

ArrayRef<EEVT::TypeSet> ChildTypes = SrcChild->getExtTypes();
ArrayRef<TypeSetByHwMode> ChildTypes = SrcChild->getExtTypes();
if (ChildTypes.size() != 1)
return failedImport("Src pattern child has multiple results");

Expand All @@ -2079,7 +2082,9 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher,
}
}

auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete());
Optional<LLTCodeGen> OpTyOrNone = None;
if (ChildTypes.front().isMachineValueType())
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
if (!OpTyOrNone)
return failedImport("Src operand has an unsupported type (" + to_string(*SrcChild) + ")");
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
Expand Down Expand Up @@ -2177,11 +2182,13 @@ Error GlobalISelEmitter::importExplicitUseRenderer(
if (auto *ChildDefInit = dyn_cast<DefInit>(DstChild->getLeafValue())) {
auto *ChildRec = ChildDefInit->getDef();

ArrayRef<EEVT::TypeSet> ChildTypes = DstChild->getExtTypes();
ArrayRef<TypeSetByHwMode> ChildTypes = DstChild->getExtTypes();
if (ChildTypes.size() != 1)
return failedImport("Dst pattern child has multiple results");

auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete());
Optional<LLTCodeGen> OpTyOrNone = None;
if (ChildTypes.front().isMachineValueType())
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
if (!OpTyOrNone)
return failedImport("Dst operand has an unsupported type");

Expand Down Expand Up @@ -2360,7 +2367,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
RuleMatcher M;
M.addAction<DebugCommentAction>(P);

if (auto Error = importRulePredicates(M, P.getPredicates()->getValues()))
if (auto Error = importRulePredicates(M, P.getPredicates()))
return std::move(Error);

// Next, analyze the pattern operators.
Expand Down Expand Up @@ -2426,8 +2433,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// The root of the match also has constraints on the register bank so that it
// matches the result instruction.
unsigned OpIdx = 0;
for (const EEVT::TypeSet &Ty : Src->getExtTypes()) {
(void)Ty;
for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
(void)VTy;

const auto &DstIOperand = DstI.Operands[OpIdx];
Record *DstIOpRec = DstIOperand.Rec;
Expand Down
199 changes: 199 additions & 0 deletions llvm/utils/TableGen/InfoByHwMode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
//===--- InfoByHwMode.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Classes that implement data parameterized by HW modes for instruction
// selection. Currently it is ValueTypeByHwMode (parameterized ValueType),
// and RegSizeInfoByHwMode (parameterized register/spill size and alignment
// data).
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "InfoByHwMode.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

#include <set>
#include <sstream>
#include <string>

using namespace llvm;

std::string llvm::getModeName(unsigned Mode) {
if (Mode == DefaultMode)
return "*";
return (Twine('m') + Twine(Mode)).str();
}

ValueTypeByHwMode::ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH) {
const HwModeSelect &MS = CGH.getHwModeSelect(R);
for (const HwModeSelect::PairType &P : MS.Items) {
auto I = Map.insert({P.first, MVT(llvm::getValueType(P.second))});
assert(I.second && "Duplicate entry?");
(void)I;
}
}

bool ValueTypeByHwMode::operator== (const ValueTypeByHwMode &T) const {
assert(isValid() && T.isValid() && "Invalid type in assignment");
bool Simple = isSimple();
if (Simple != T.isSimple())
return false;
if (Simple)
return getSimple() == T.getSimple();

return Map == T.Map;
}

bool ValueTypeByHwMode::operator< (const ValueTypeByHwMode &T) const {
assert(isValid() && T.isValid() && "Invalid type in comparison");
// Default order for maps.
return Map < T.Map;
}

MVT &ValueTypeByHwMode::getOrCreateTypeForMode(unsigned Mode, MVT Type) {
auto F = Map.find(Mode);
if (F != Map.end())
return F->second;
// If Mode is not in the map, look up the default mode. If it exists,
// make a copy of it for Mode and return it.
auto D = Map.find(DefaultMode);
if (D != Map.end())
return Map.insert(std::make_pair(Mode, D->second)).first->second;
// If default mode is not present either, use provided Type.
return Map.insert(std::make_pair(Mode, Type)).first->second;
}

std::string ValueTypeByHwMode::getMVTName(MVT T) {
std::string N = llvm::getEnumName(T.SimpleTy);
if (N.substr(0,5) == "MVT::")
N = N.substr(5);
return N;
}

std::string ValueTypeByHwMode::getAsString() const {
if (isSimple())
return getMVTName(getSimple());

std::vector<const PairType*> Pairs;
for (const auto &P : Map)
Pairs.push_back(&P);
std::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>());

std::stringstream str;
str << '{';
for (unsigned i = 0, e = Pairs.size(); i != e; ++i) {
const PairType *P = Pairs[i];
str << '(' << getModeName(P->first)
<< ':' << getMVTName(P->second) << ')';
if (i != e-1)
str << ',';
}
str << '}';
return str.str();
}

LLVM_DUMP_METHOD
void ValueTypeByHwMode::dump() const {
dbgs() << "size=" << Map.size() << '\n';
for (const auto &P : Map)
dbgs() << " " << P.first << " -> "
<< llvm::getEnumName(P.second.SimpleTy) << '\n';
}

ValueTypeByHwMode llvm::getValueTypeByHwMode(Record *Rec,
const CodeGenHwModes &CGH) {
#ifndef NDEBUG
if (!Rec->isSubClassOf("ValueType"))
Rec->dump();
#endif
assert(Rec->isSubClassOf("ValueType") &&
"Record must be derived from ValueType");
if (Rec->isSubClassOf("HwModeSelect"))
return ValueTypeByHwMode(Rec, CGH);
return ValueTypeByHwMode(llvm::getValueType(Rec));
}

RegSizeInfo::RegSizeInfo(Record *R, const CodeGenHwModes &CGH) {
RegSize = R->getValueAsInt("RegSize");
SpillSize = R->getValueAsInt("SpillSize");
SpillAlignment = R->getValueAsInt("SpillAlignment");
}

bool RegSizeInfo::operator< (const RegSizeInfo &I) const {
return std::tie(RegSize, SpillSize, SpillAlignment) <
std::tie(I.RegSize, I.SpillSize, I.SpillAlignment);
}

bool RegSizeInfo::isSubClassOf(const RegSizeInfo &I) const {
return RegSize <= I.RegSize &&
SpillAlignment && I.SpillAlignment % SpillAlignment == 0 &&
SpillSize <= I.SpillSize;
}

std::string RegSizeInfo::getAsString() const {
std::stringstream str;
str << "[R=" << RegSize << ",S=" << SpillSize
<< ",A=" << SpillAlignment << ']';
return str.str();
}

RegSizeInfoByHwMode::RegSizeInfoByHwMode(Record *R,
const CodeGenHwModes &CGH) {
const HwModeSelect &MS = CGH.getHwModeSelect(R);
for (const HwModeSelect::PairType &P : MS.Items) {
auto I = Map.insert({P.first, RegSizeInfo(P.second, CGH)});
assert(I.second && "Duplicate entry?");
(void)I;
}
}

bool RegSizeInfoByHwMode::operator< (const RegSizeInfoByHwMode &I) const {
unsigned M0 = Map.begin()->first;
return get(M0) < I.get(M0);
}

bool RegSizeInfoByHwMode::operator== (const RegSizeInfoByHwMode &I) const {
unsigned M0 = Map.begin()->first;
return get(M0) == I.get(M0);
}

bool RegSizeInfoByHwMode::isSubClassOf(const RegSizeInfoByHwMode &I) const {
unsigned M0 = Map.begin()->first;
return get(M0).isSubClassOf(I.get(M0));
}

bool RegSizeInfoByHwMode::hasStricterSpillThan(const RegSizeInfoByHwMode &I)
const {
unsigned M0 = Map.begin()->first;
const RegSizeInfo &A0 = get(M0);
const RegSizeInfo &B0 = I.get(M0);
return std::tie(A0.SpillSize, A0.SpillAlignment) >
std::tie(B0.SpillSize, B0.SpillAlignment);
}

std::string RegSizeInfoByHwMode::getAsString() const {
typedef typename decltype(Map)::value_type PairType;
std::vector<const PairType*> Pairs;
for (const auto &P : Map)
Pairs.push_back(&P);
std::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>());

std::stringstream str;
str << '{';
for (unsigned i = 0, e = Pairs.size(); i != e; ++i) {
const PairType *P = Pairs[i];
str << '(' << getModeName(P->first)
<< ':' << P->second.getAsString() << ')';
if (i != e-1)
str << ',';
}
str << '}';
return str.str();
}
167 changes: 167 additions & 0 deletions llvm/utils/TableGen/InfoByHwMode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//===--- InfoByHwMode.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Classes that implement data parameterized by HW modes for instruction
// selection. Currently it is ValueTypeByHwMode (parameterized ValueType),
// and RegSizeInfoByHwMode (parameterized register/spill size and alignment
// data).
//===----------------------------------------------------------------------===//

#ifndef LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
#define LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H

#include "CodeGenHwModes.h"
#include "llvm/CodeGen/MachineValueType.h"

#include <map>
#include <set>
#include <string>
#include <vector>

namespace llvm {

struct CodeGenHwModes;
class Record;

template <typename InfoT> struct InfoByHwMode;

std::string getModeName(unsigned Mode);

enum : unsigned {
DefaultMode = CodeGenHwModes::DefaultMode,
};

template <typename InfoT>
std::vector<unsigned> union_modes(const InfoByHwMode<InfoT> &A,
const InfoByHwMode<InfoT> &B) {
std::vector<unsigned> V;
std::set<unsigned> U;
for (const auto &P : A)
U.insert(P.first);
for (const auto &P : B)
U.insert(P.first);
// Make sure that the default mode is last on the list.
bool HasDefault = U.count(DefaultMode);
for (unsigned M : U)
if (M != DefaultMode)
V.push_back(M);
if (HasDefault)
V.push_back(DefaultMode);
return V;
}

template <typename InfoT>
struct InfoByHwMode {
typedef std::map<unsigned,InfoT> MapType;
typedef typename MapType::value_type PairType;
typedef typename MapType::iterator iterator;
typedef typename MapType::const_iterator const_iterator;

InfoByHwMode() = default;
InfoByHwMode(const MapType &&M) : Map(M) {}

iterator begin() { return Map.begin(); }
iterator end() { return Map.end(); }
const_iterator begin() const { return Map.begin(); }
const_iterator end() const { return Map.end(); }
bool empty() const { return Map.empty(); }

bool hasMode(unsigned M) const { return Map.find(M) != Map.end(); }
bool hasDefault() const { return hasMode(DefaultMode); }

InfoT &get(unsigned Mode) {
if (!hasMode(Mode)) {
assert(hasMode(DefaultMode));
Map[Mode] = Map[DefaultMode];
}
return Map[Mode];
}
const InfoT &get(unsigned Mode) const {
auto F = Map.find(Mode);
if (Mode != DefaultMode && F == Map.end())
F = Map.find(DefaultMode);
assert(F != Map.end());
return F->second;
}

bool isSimple() const {
return Map.size() == 1 && Map.begin()->first == DefaultMode;
}
InfoT getSimple() const {
assert(isSimple());
return Map.begin()->second;
}
void makeSimple(unsigned Mode) {
assert(hasMode(Mode) || hasDefault());
InfoT I = get(Mode);
Map.clear();
Map.insert(std::make_pair(DefaultMode, I));
}

MapType Map;
};

struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH);
ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode,T}); }
ValueTypeByHwMode() = default;

bool operator== (const ValueTypeByHwMode &T) const;
bool operator< (const ValueTypeByHwMode &T) const;

bool isValid() const {
return !Map.empty();
}
MVT getType(unsigned Mode) const { return get(Mode); }
MVT &getOrCreateTypeForMode(unsigned Mode, MVT Type);

static std::string getMVTName(MVT T);
std::string getAsString() const;
void dump() const;
};

ValueTypeByHwMode getValueTypeByHwMode(Record *Rec,
const CodeGenHwModes &CGH);

struct RegSizeInfo {
unsigned RegSize;
unsigned SpillSize;
unsigned SpillAlignment;

RegSizeInfo(Record *R, const CodeGenHwModes &CGH);
RegSizeInfo() = default;
bool operator< (const RegSizeInfo &I) const;
bool operator== (const RegSizeInfo &I) const {
return std::tie(RegSize, SpillSize, SpillAlignment) ==
std::tie(I.RegSize, I.SpillSize, I.SpillAlignment);
}
bool operator!= (const RegSizeInfo &I) const {
return !(*this == I);
}

bool isSubClassOf(const RegSizeInfo &I) const;
std::string getAsString() const;
};

struct RegSizeInfoByHwMode : public InfoByHwMode<RegSizeInfo> {
RegSizeInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
RegSizeInfoByHwMode() = default;
bool operator< (const RegSizeInfoByHwMode &VI) const;
bool operator== (const RegSizeInfoByHwMode &VI) const;
bool operator!= (const RegSizeInfoByHwMode &VI) const {
return !(*this == VI);
}

bool isSubClassOf(const RegSizeInfoByHwMode &I) const;
bool hasStricterSpillThan(const RegSizeInfoByHwMode &I) const;

std::string getAsString() const;
};
} // namespace llvm

#endif // LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
9 changes: 6 additions & 3 deletions llvm/utils/TableGen/RegisterBankEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"

#include "CodeGenHwModes.h"
#include "CodeGenRegisters.h"

#define DEBUG_TYPE "register-bank-emitter"
Expand Down Expand Up @@ -84,7 +85,8 @@ class RegisterBank {
// the VT's reliably due to Untyped.
if (RCWithLargestRegsSize == nullptr)
RCWithLargestRegsSize = RC;
else if (RCWithLargestRegsSize->SpillSize < RC->SpillSize)
else if (RCWithLargestRegsSize->RSI.get(DefaultMode).SpillSize <
RC->RSI.get(DefaultMode).SpillSize)
RCWithLargestRegsSize = RC;
assert(RCWithLargestRegsSize && "RC was nullptr?");

Expand Down Expand Up @@ -115,7 +117,7 @@ class RegisterBankEmitter {

public:
RegisterBankEmitter(RecordKeeper &R)
: Records(R), RegisterClassHierarchy(Records) {}
: Records(R), RegisterClassHierarchy(Records, CodeGenHwModes(R)) {}

void run(raw_ostream &OS);
};
Expand Down Expand Up @@ -241,7 +243,8 @@ void RegisterBankEmitter::emitBaseClassImplementation(
for (const auto &Bank : Banks) {
std::string QualifiedBankID =
(TargetName + "::" + Bank.getEnumeratorName()).str();
unsigned Size = Bank.getRCWithLargestRegsSize()->SpillSize;
const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegsSize();
unsigned Size = RC.RSI.get(DefaultMode).SpillSize;
OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
<< QualifiedBankID << ", /* Name */ \"" << Bank.getName()
<< "\", /* Size */ " << Size << ", "
Expand Down
84 changes: 64 additions & 20 deletions llvm/utils/TableGen/RegisterInfoEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,13 +1037,14 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,

for (const auto &RC : RegisterClasses) {
assert(isInt<8>(RC.CopyCost) && "Copy cost too large.");
// Register size and spill size will become independent, but are not at
// the moment. For now use SpillSize as the register size.
uint32_t RegSize = 0;
if (RC.RSI.isSimple())
RegSize = RC.RSI.getSimple().RegSize;
OS << " { " << RC.getName() << ", " << RC.getName() << "Bits, "
<< RegClassStrings.get(RC.getName()) << ", "
<< RC.getOrder().size() << ", sizeof(" << RC.getName() << "Bits), "
<< RC.getQualifiedName() + "RegClassID" << ", "
<< RC.SpillSize/8 << ", "
<< RegSize/8 << ", "
<< RC.CopyCost << ", "
<< ( RC.Allocatable ? "true" : "false" ) << " },\n";
}
Expand Down Expand Up @@ -1111,7 +1112,8 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,

OS << "struct " << ClassName << " : public TargetRegisterInfo {\n"
<< " explicit " << ClassName
<< "(unsigned RA, unsigned D = 0, unsigned E = 0, unsigned PC = 0);\n";
<< "(unsigned RA, unsigned D = 0, unsigned E = 0,\n"
<< " unsigned PC = 0, unsigned HwMode = 0);\n";
if (!RegBank.getSubRegIndices().empty()) {
OS << " unsigned composeSubRegIndicesImpl"
<< "(unsigned, unsigned) const override;\n"
Expand Down Expand Up @@ -1190,10 +1192,19 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
AllocatableRegs.insert(Order.begin(), Order.end());
}

const CodeGenHwModes &CGH = Target.getHwModes();
unsigned NumModes = CGH.getNumModeIds();

// Build a shared array of value types.
SequenceToOffsetTable<SmallVector<MVT::SimpleValueType, 4> > VTSeqs;
for (const auto &RC : RegisterClasses)
VTSeqs.add(RC.VTs);
SequenceToOffsetTable<std::vector<MVT::SimpleValueType>> VTSeqs;
for (unsigned M = 0; M < NumModes; ++M) {
for (const auto &RC : RegisterClasses) {
std::vector<MVT::SimpleValueType> S;
for (const ValueTypeByHwMode &VVT : RC.VTs)
S.push_back(VVT.get(M).SimpleTy);
VTSeqs.add(S);
}
}
VTSeqs.layout();
OS << "\nstatic const MVT::SimpleValueType VTLists[] = {\n";
VTSeqs.emit(OS, printSimpleValueType, "MVT::Other");
Expand Down Expand Up @@ -1221,6 +1232,31 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,

// Now that all of the structs have been emitted, emit the instances.
if (!RegisterClasses.empty()) {
OS << "\nstatic const TargetRegisterInfo::RegClassInfo RegClassInfos[]"
<< " = {\n";
for (unsigned M = 0; M < NumModes; ++M) {
unsigned EV = 0;
OS << " // Mode = " << M << " (";
if (M == 0)
OS << "Default";
else
OS << CGH.getMode(M).Name;
OS << ")\n";
for (const auto &RC : RegisterClasses) {
assert(RC.EnumValue == EV++ && "Unexpected order of register classes");
const RegSizeInfo &RI = RC.RSI.get(M);
OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", "
<< RI.SpillAlignment;
std::vector<MVT::SimpleValueType> VTs;
for (const ValueTypeByHwMode &VVT : RC.VTs)
VTs.push_back(VVT.get(M).SimpleTy);
OS << ", VTLists+" << VTSeqs.get(VTs) << " }, // "
<< RC.getName() << '\n';
}
}
OS << "};\n";


OS << "\nstatic const TargetRegisterClass *const "
<< "NullRegClasses[] = { nullptr };\n\n";

Expand Down Expand Up @@ -1327,15 +1363,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< " { // Register class instances\n";

for (const auto &RC : RegisterClasses) {
assert(isUInt<16>(RC.SpillSize/8) && "SpillSize too large.");
assert(isUInt<16>(RC.SpillAlignment/8) && "SpillAlignment too large.");
OS << " extern const TargetRegisterClass " << RC.getName()
<< "RegClass = {\n " << '&' << Target.getName()
<< "MCRegisterClasses[" << RC.getName() << "RegClassID],\n "
<< RC.SpillSize/8 << ", /* SpillSize */\n "
<< RC.SpillAlignment/8 << ", /* SpillAlignment */\n "
<< "VTLists + " << VTSeqs.get(RC.VTs) << ",\n " << RC.getName()
<< "SubClassMask,\n SuperRegIdxSeqs + "
<< RC.getName() << "SubClassMask,\n SuperRegIdxSeqs + "
<< SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n ";
printMask(OS, RC.LaneMask);
OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n "
Expand Down Expand Up @@ -1439,12 +1470,14 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
EmitRegMappingTables(OS, Regs, true);

OS << ClassName << "::\n" << ClassName
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour, unsigned PC)\n"
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,\n"
" unsigned PC, unsigned HwMode)\n"
<< " : TargetRegisterInfo(" << TargetName << "RegInfoDesc"
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n"
<< " SubRegIndexNameTable, SubRegIndexLaneMaskTable, ";
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() << ",\n"
<< " SubRegIndexNameTable, SubRegIndexLaneMaskTable,\n"
<< " ";
printMask(OS, RegBank.CoveringLanes);
OS << ") {\n"
OS << ", RegClassInfos, HwMode) {\n"
<< " InitMCRegisterInfo(" << TargetName << "RegDesc, " << Regs.size() + 1
<< ", RA, PC,\n " << TargetName
<< "MCRegisterClasses, " << RegisterClasses.size() << ",\n"
Expand Down Expand Up @@ -1547,12 +1580,23 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {

void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
CodeGenRegBank &RegBank = Target.getRegBank();
const CodeGenHwModes &CGH = Target.getHwModes();
unsigned NumModes = CGH.getNumModeIds();
auto getModeName = [CGH] (unsigned M) -> StringRef {
if (M == 0)
return "Default";
return CGH.getMode(M).Name;
};

for (const CodeGenRegisterClass &RC : RegBank.getRegClasses()) {
OS << "RegisterClass " << RC.getName() << ":\n";
OS << "\tSpillSize: " << RC.SpillSize << '\n';
OS << "\tSpillAlignment: " << RC.SpillAlignment << '\n';
OS << "\tNumRegs: " << RC.getMembers().size() << '\n';
OS << "\tSpillSize: {";
for (unsigned M = 0; M != NumModes; ++M)
OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillSize;
OS << " }\n\tSpillAlignment: {";
for (unsigned M = 0; M != NumModes; ++M)
OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillAlignment;
OS << " }\n\tNumRegs: " << RC.getMembers().size() << '\n';
OS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n';
OS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n';
OS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n';
Expand Down