|  | // 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_EmitInteger32, 0 | 
|  | // ADD-NEXT: OPC_MorphNodeTo1None, 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_EmitInteger32, 2 | 
|  | // ADDINT-NEXT: OPC_MorphNodeTo1None, TARGET_VAL(::AddRRI) | 
|  |  | 
|  | // SUB: SwitchOpcode{{.*}}TARGET_VAL(ISD::SUB) | 
|  | // SUB-NEXT: OPC_RecordChild0 | 
|  | // SUB-NEXT: OPC_RecordChild1 | 
|  | // SUB-NEXT: OPC_EmitInteger32, 0 | 
|  | // SUB-NEXT: OPC_MorphNodeTo1None, 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_MorphNodeTo1Chain, TARGET_VAL(::MulRRI) | 
|  |  | 
|  | // MUL: SwitchOpcode{{.*}}TARGET_VAL(ISD::MUL) | 
|  | // MUL-NEXT: OPC_EmitInteger32, 0 | 
|  | // MUL-NEXT: OPC_RecordChild0 | 
|  | // MUL-NEXT: OPC_RecordChild1 | 
|  | // MUL-NEXT: OPC_MorphNodeTo1Chain, TARGET_VAL(::MulRRI) |