// 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 : Register<"R"#index, []> { let HWEncoding{15...4} = 0; let HWEncoding{3...0} = !cast>(index); } foreach i = 0...15 in def "R"#i : TestReg; def Reg : RegisterClass<"TestTarget", [i32], 32, (sequence "R%d", 0, 15)>; def IntOperand: Operand; def OptionalIntOperand: OperandWithDefaultOps; class RRI 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)