reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include %s -o %t
// RUN: FileCheck --check-prefix=ADD %s < %t
// RUN: FileCheck --check-prefix=ADDINT %s < %t
// RUN: FileCheck --check-prefix=SUB %s < %t
// RUN: FileCheck --check-prefix=MULINT %s < %t

include "llvm/Target/Target.td"

def TestInstrInfo : InstrInfo;
def TestTarget : Target {
    let InstructionSet = TestInstrInfo;
}

class TestEncoding : Instruction {
  field bits<32> Inst;
}

class TestReg<int index> : Register<"R"#index, []> {
    let HWEncoding{15-4} = 0;
    let HWEncoding{3-0} = !cast<bits<4>>(index);
}
foreach i = 0-15 in
  def "R"#i : TestReg<i>;

def Reg : RegisterClass<"TestTarget", [i32], 32, (sequence "R%d", 0, 15)>;

def IntOperand: Operand<i32>;
def OptionalIntOperand: OperandWithDefaultOps<i32, (ops (i32 0))>;

class RRI<string Mnemonic, bits<4> Opcode> : TestEncoding {
  dag OutOperandList = (outs Reg:$dest);
  dag InOperandList = (ins Reg:$src1, Reg:$src2, OptionalIntOperand:$imm);
  string AsmString = Mnemonic # " $dest1, $src1, $src2, #$imm";
  string AsmVariantName = "";
  field bits<4> dest;
  field bits<4> src1;
  field bits<4> src2;
  field bits<16> imm;
  let Inst{31-28} = Opcode;
  let Inst{27-24} = dest;
  let Inst{23-20} = src1;
  let Inst{19-16} = src2;
  let Inst{15-0} = imm;
}

def AddRRI : RRI<"add", 0b0001>;

// I define one of these intrinsics with IntrNoMem and the other
// without it, so that they'll match different top-level DAG opcodes
// (INTRINSIC_WO_CHAIN and INTRINSIC_W_CHAIN), which makes the
// FileCheck-herding easier, because every case I want to detect
// should show up as a separate top-level switch element.
def int_addplus1 : Intrinsic<
    [llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
def int_mul3 : Intrinsic<
    [llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty]>;

def AddPat  : Pat<(add i32:$x, i32:$y),
                  (AddRRI Reg:$x, Reg:$y)>;
def Add1Pat : Pat<(int_addplus1 i32:$x, i32:$y),
                  (AddRRI Reg:$x, Reg:$y, (i32 1))>;

def SubRRI : RRI<"sub", 0b0010> {
  let Pattern = [(set Reg:$dest, (sub Reg:$src1, Reg:$src2))];
}

def MulRRI : RRI<"mul", 0b0011> {
  let Pattern = [(set Reg:$dest, (int_mul3 Reg:$src1, Reg:$src2, i32:$imm))];
}

def MulIRR : RRI<"mul2", 0b0100> {
  let InOperandList = (ins OptionalIntOperand:$imm, Reg:$src1, Reg:$src2);
}
def MulIRRPat : Pat<(mul i32:$x, i32:$y), (MulIRR Reg:$x, Reg:$y)>;

// ADD: SwitchOpcode{{.*}}TARGET_VAL(ISD::ADD)
// ADD-NEXT: OPC_RecordChild0
// ADD-NEXT: OPC_RecordChild1
// ADD-NEXT: OPC_EmitInteger, MVT::i32, 0
// ADD-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::AddRRI)

// ADDINT: SwitchOpcode{{.*}}TARGET_VAL(ISD::INTRINSIC_WO_CHAIN)
// ADDINT-NEXT: OPC_CheckChild0Integer
// ADDINT-NEXT: OPC_RecordChild1
// ADDINT-NEXT: OPC_RecordChild2
// ADDINT-NEXT: OPC_EmitInteger, MVT::i32, 1
// ADDINT-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::AddRRI)

// SUB: SwitchOpcode{{.*}}TARGET_VAL(ISD::SUB)
// SUB-NEXT: OPC_RecordChild0
// SUB-NEXT: OPC_RecordChild1
// SUB-NEXT: OPC_EmitInteger, MVT::i32, 0
// SUB-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::SubRRI)

// MULINT: SwitchOpcode{{.*}}TARGET_VAL(ISD::INTRINSIC_W_CHAIN)
// MULINT-NEXT: OPC_RecordNode
// MULINT-NEXT: OPC_CheckChild1Integer
// MULINT-NEXT: OPC_RecordChild2
// MULINT-NEXT: OPC_RecordChild3
// MULINT-NEXT: OPC_RecordChild4
// MULINT-NEXT: OPC_EmitMergeInputChains
// MULINT-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::MulRRI)

// MUL: SwitchOpcode{{.*}}TARGET_VAL(ISD::MUL)
// MUL-NEXT: OPC_EmitInteger, MVT::i32, 0
// MUL-NEXT: OPC_RecordChild0
// MUL-NEXT: OPC_RecordChild1
// MUL-NEXT: OPC_MorphNodeTo1, TARGET_VAL(::MulRRI)