Index: lib/Target/Mips/MicroMips32r6InstrInfo.td =================================================================== --- lib/Target/Mips/MicroMips32r6InstrInfo.td +++ lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -1772,3 +1772,5 @@ def : LoadRegImmPat, FGR_64, ISA_MICROMIPS32R6; def : StoreRegImmPat, FGR_64, ISA_MICROMIPS32R6; } + +def TAILCALL_MMR6 : TailCall, ISA_MICROMIPS32R6; Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -471,18 +471,6 @@ let isIndirectBranch = 1; } -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1, - hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in { - class TailCall_MM : - PseudoSE<(outs), (ins calltarget:$target), [], II_J>, - PseudoInstExpansion<(JumpInst jmptarget_mm:$target)>; - - class TailCallReg_MM : - PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, - PseudoInstExpansion<(JRInst ResRO:$rs)>; -} - // Break16 and Sdbbp16 class BrkSdbbp16MM : MicroMipsInst16<(outs), (ins uimm4:$code_), @@ -989,11 +977,7 @@ def PREFX_MM : PrefetchIndexed<"prefx">, POOL32F_PREFX_FM_MM<0x15, 0x1A0>; } -let AdditionalPredicates = [InMicroMips] in { - def TAILCALL_MM : TailCall_MM, ISA_MIPS1_NOT_32R6_64R6; - def TAILCALLREG_MM : TailCallReg_MM, - ISA_MIPS1_NOT_32R6_64R6; -} +def TAILCALL_MM : TailCall, ISA_MIPS1_NOT_32R6_64R6; let DecoderNamespace = "MicroMips" in { def RDHWR_MM : MMRel, R6MMR6Rel, ReadHardware, @@ -1068,6 +1052,11 @@ (LW_MM addr:$addr)>; def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), (SUBu_MM GPR32:$lhs, GPR32:$rhs)>; + + def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)), + (TAILCALL_MM tglobaladdr:$dst)>, ISA_MIPS1_NOT_32R6_64R6; + def : MipsPat<(MipsTailCall (iPTR texternalsym:$dst)), + (TAILCALL_MM texternalsym:$dst)>, ISA_MIPS1_NOT_32R6_64R6; } let AddedComplexity = 40 in { Index: lib/Target/Mips/Mips32r6InstrInfo.td =================================================================== --- lib/Target/Mips/Mips32r6InstrInfo.td +++ lib/Target/Mips/Mips32r6InstrInfo.td @@ -848,8 +848,6 @@ def SDC2_R6 : SDC2_R6_ENC, SDC2_R6_DESC, ISA_MIPS32R6; def SWC2_R6 : SWC2_R6_ENC, SWC2_R6_DESC, ISA_MIPS32R6; } -def TAILCALL_R6 : TailCall, ISA_MIPS32R6; -def TAILCALLREG_R6 : TailCallReg, GPR_32, ISA_MIPS32R6; //===----------------------------------------------------------------------===// // Index: lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64InstrInfo.td +++ lib/Target/Mips/Mips64InstrInfo.td @@ -242,9 +242,9 @@ def BLEZ64 : CBranchZero<"blez", brtarget, setle, GPR64Opnd>, BGEZ_FM<6, 0>; def BLTZ64 : CBranchZero<"bltz", brtarget, setlt, GPR64Opnd>, BGEZ_FM<1, 0>; def JALR64Pseudo : JumpLinkRegPseudo; - def TAILCALLREG64 : TailCallReg, GPR_64, ISA_MIPS1_NOT_32R6_64R6; } +def TAILCALLREG64 : TailCallReg; def PseudoReturn64 : PseudoReturnBase; def PseudoIndirectBranch64 : PseudoIndirectBranchBase; Index: lib/Target/Mips/Mips64r6InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64r6InstrInfo.td +++ lib/Target/Mips/Mips64r6InstrInfo.td @@ -165,10 +165,6 @@ def BGEZC64 : BGEZC_ENC, BGEZC64_DESC, ISA_MIPS64R6, GPR_64; } -def TAILCALL64_R6 : TailCall, ISA_MIPS64R6; -def TAILCALLREG64_R6 : TailCallReg, GPR_64, - ISA_MIPS64R6; - //===----------------------------------------------------------------------===// // // Instruction Aliases Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -98,6 +98,7 @@ void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, const MachineInstr *MI) { bool HasLinkReg = false; + bool InMicroMipsMode = Subtarget->inMicroMipsMode(); MCInst TmpInst0; if (Subtarget->hasMips64r6()) { @@ -106,8 +107,12 @@ HasLinkReg = true; } else if (Subtarget->hasMips32r6()) { // MIPS32r6 should use (JALR ZERO, $rs) - TmpInst0.setOpcode(Mips::JALR); - HasLinkReg = true; + if (InMicroMipsMode) + TmpInst0.setOpcode(Mips::JRC16_MMR6); + else { + TmpInst0.setOpcode(Mips::JALR); + HasLinkReg = true; + } } else if (Subtarget->inMicroMipsMode()) // microMIPS should use (JR_MM $rs) TmpInst0.setOpcode(Mips::JR_MM); @@ -185,7 +190,9 @@ if (I->getOpcode() == Mips::PseudoReturn || I->getOpcode() == Mips::PseudoReturn64 || I->getOpcode() == Mips::PseudoIndirectBranch || - I->getOpcode() == Mips::PseudoIndirectBranch64) { + I->getOpcode() == Mips::PseudoIndirectBranch64 || + I->getOpcode() == Mips::TAILCALLREG || + I->getOpcode() == Mips::TAILCALLREG64) { emitPseudoIndirectBranch(*OutStreamer, &*I); continue; } Index: lib/Target/Mips/MipsDelaySlotFiller.cpp =================================================================== --- lib/Target/Mips/MipsDelaySlotFiller.cpp +++ lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -560,7 +560,7 @@ return Mips::JALRS16_MM; case Mips::TAILCALL_MM: llvm_unreachable("Attempting to shorten the TAILCALL_MM pseudo!"); - case Mips::TAILCALLREG_MM: + case Mips::TAILCALLREG: return Mips::JR16_MM; default: llvm_unreachable("Unexpected call instruction for microMIPS."); Index: lib/Target/Mips/MipsInstrInfo.cpp =================================================================== --- lib/Target/Mips/MipsInstrInfo.cpp +++ lib/Target/Mips/MipsInstrInfo.cpp @@ -282,7 +282,7 @@ case Mips::JR: case Mips::PseudoReturn: case Mips::PseudoIndirectBranch: - case Mips::TAILCALLREG_MM: + case Mips::TAILCALLREG: canUseShortMicroMipsCTI = true; break; } @@ -363,8 +363,7 @@ case Mips::JR: case Mips::PseudoReturn: case Mips::PseudoIndirectBranch: - case Mips::TAILCALLREG_MM: - case Mips::TAILCALLREG_R6: + case Mips::TAILCALLREG: if (canUseShortMicroMipsCTI) return Mips::JRC16_MM; return Mips::JIC; @@ -373,7 +372,7 @@ case Mips::JR64: case Mips::PseudoReturn64: case Mips::PseudoIndirectBranch64: - case Mips::TAILCALLREG64_R6: + case Mips::TAILCALLREG64: return Mips::JIC64; case Mips::JALR64Pseudo: return Mips::JIALC64; Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -1370,14 +1370,12 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1, hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in { - class TailCall : + class TailCall : PseudoSE<(outs), (ins calltarget:$target), [], II_J>, - PseudoInstExpansion<(JumpInst jmptarget:$target)>; + PseudoInstExpansion<(JumpInst Opnd:$target)>; - class TailCallReg : - PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, - PseudoInstExpansion<(JRInst ResRO:$rs)>; + class TailCallReg : + MipsPseudo<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>; } class BAL_BR_Pseudo : @@ -1919,11 +1917,12 @@ BGEZAL_FM<0x12>, ISA_MIPS2_NOT_32R6_64R6; def BAL_BR : BAL_BR_Pseudo; -let AdditionalPredicates = [NotInMicroMips] in { -def TAILCALL : TailCall, ISA_MIPS1_NOT_32R6_64R6; -def TAILCALLREG : TailCallReg, ISA_MIPS1_NOT_32R6_64R6, GPR_32; +let Predicates = [NotInMicroMips] in { + def TAILCALL : TailCall; } +def TAILCALLREG : TailCallReg; + // Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64 // then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA. class PseudoIndirectBranchBase : Index: test/CodeGen/Mips/tailcall.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/tailcall.ll @@ -1,303 +0,0 @@ -; RUN: llc -march=mipsel -relocation-model=pic \ -; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=PIC32 -; RUN: llc -march=mipsel -relocation-model=static \ -; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=STATIC32 -; RUN: llc -march=mips64el -mcpu=mips64r2 \ -; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=N64 -; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic \ -; RUN: -verify-machineinstrs < %s | \ -; RUN: FileCheck %s -check-prefix=PIC16 - -; RUN: llc -march=mipsel -relocation-model=pic -mattr=+micromips < %s | \ -; RUN: FileCheck %s -check-prefix=PIC32 -; RUN: llc -march=mipsel -relocation-model=static -mattr=+micromips \ -; RUN: < %s | FileCheck %s -check-prefix=STATIC32 - -; RUN: llc -march=mipsel -relocation-model=pic -mcpu=mips32r6 < %s | \ -; RUN: FileCheck %s -check-prefix=PIC32 -; RUN: llc -march=mipsel -relocation-model=static -mcpu=mips32r6 \ -; RUN: < %s | FileCheck %s -check-prefix=STATIC32 -; RUN: llc -march=mips64el -mcpu=mips64r6 \ -; RUN: < %s | FileCheck %s -check-prefix=N64 - -; RUN: llc -march=mipsel -relocation-model=pic -mcpu=mips32r6 -mattr=+micromips \ -; RUN: < %s | FileCheck %s -check-prefix=PIC32 -; RUN: llc -march=mipsel -relocation-model=static -mcpu=mips32r6 \ -; RUN: -mattr=+micromips < %s | FileCheck %s -check-prefix=STATIC32 -; RUN: llc -march=mips64el -mcpu=mips64r6 -mattr=+micromips < %s \ -; RUN: | FileCheck %s -check-prefix=N64 - -@g0 = common global i32 0, align 4 -@g1 = common global i32 0, align 4 -@g2 = common global i32 0, align 4 -@g3 = common global i32 0, align 4 -@g4 = common global i32 0, align 4 -@g5 = common global i32 0, align 4 -@g6 = common global i32 0, align 4 -@g7 = common global i32 0, align 4 -@g8 = common global i32 0, align 4 -@g9 = common global i32 0, align 4 - -define i32 @caller1(i32 %a0) nounwind { -entry: -; PIC32-NOT: jalr -; STATIC32-NOT: jal -; N64-NOT: jalr -; PIC16: jalrc - - %call = tail call i32 @callee1(i32 1, i32 1, i32 1, i32 %a0) nounwind - ret i32 %call -} - -declare i32 @callee1(i32, i32, i32, i32) - -define i32 @caller2(i32 %a0, i32 %a1, i32 %a2, i32 %a3) nounwind { -entry: -; PIC32: jalr -; STATIC32: jal -; N64-NOT: jalr -; PIC16: jalrc - - %call = tail call i32 @callee2(i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3) nounwind - ret i32 %call -} - -declare i32 @callee2(i32, i32, i32, i32, i32) - -define i32 @caller3(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4) nounwind { -entry: -; PIC32: jalr -; STATIC32: jal -; N64-NOT: jalr -; PIC16: jalrc - - %call = tail call i32 @callee3(i32 1, i32 1, i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4) nounwind - ret i32 %call -} - -declare i32 @callee3(i32, i32, i32, i32, i32, i32, i32, i32) - -define i32 @caller4(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7) nounwind { -entry: -; PIC32: jalr -; STATIC32: jal -; N64: jalr -; PIC16: jalrc - - %call = tail call i32 @callee4(i32 1, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7) nounwind - ret i32 %call -} - -declare i32 @callee4(i32, i32, i32, i32, i32, i32, i32, i32, i32) - -define i32 @caller5() nounwind readonly { -entry: -; PIC32: .ent caller5 -; PIC32-NOT: jalr $25 -; PIC32: .end caller5 -; STATIC32: .ent caller5 -; STATIC32-NOT: jal -; STATIC32: .end caller5 -; N64: .ent caller5 -; N64-NOT: jalr $25 -; N64: .end caller5 -; PIC16: .ent caller5 -; PIC16: jalrc -; PIC16: .end caller5 - - %0 = load i32, i32* @g0, align 4 - %1 = load i32, i32* @g1, align 4 - %2 = load i32, i32* @g2, align 4 - %3 = load i32, i32* @g3, align 4 - %4 = load i32, i32* @g4, align 4 - %5 = load i32, i32* @g5, align 4 - %6 = load i32, i32* @g6, align 4 - %7 = load i32, i32* @g7, align 4 - %8 = load i32, i32* @g8, align 4 - %9 = load i32, i32* @g9, align 4 - %call = tail call fastcc i32 @callee5(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) - ret i32 %call -} - -define internal fastcc i32 @callee5(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7, i32 %a8, i32 %a9) nounwind readnone noinline { -entry: - %add = add nsw i32 %a1, %a0 - %add1 = add nsw i32 %add, %a2 - %add2 = add nsw i32 %add1, %a3 - %add3 = add nsw i32 %add2, %a4 - %add4 = add nsw i32 %add3, %a5 - %add5 = add nsw i32 %add4, %a6 - %add6 = add nsw i32 %add5, %a7 - %add7 = add nsw i32 %add6, %a8 - %add8 = add nsw i32 %add7, %a9 - ret i32 %add8 -} - -declare i32 @callee8(i32, ...) - -define i32 @caller8_0() nounwind { -entry: -; PIC32: .ent caller8_0 -; PIC32: jr -; PIC32: .end caller8_0 -; STATIC32: .ent caller8_0 -; STATIC32: j -; STATIC32: .end caller8_0 -; N64: .ent caller8_0 -; N64-NOT: jalr $25 -; N64: .end caller8_0 -; PIC16: .ent caller8_0 -; PIC16: jalrc -; PIC16: .end caller8_0 - - %call = tail call fastcc i32 @caller8_1() - ret i32 %call -} - -define internal fastcc i32 @caller8_1() nounwind noinline { -entry: -; PIC32: .ent caller8_1 -; PIC32: jalr -; PIC32: .end caller8_1 -; STATIC32: .ent caller8_1 -; STATIC32: jal -; STATIC32: .end caller8_1 -; N64: .ent caller8_1 -; N64-NOT: jalr $25 -; N64: .end caller8_1 -; PIC16: .ent caller8_1 -; PIC16: jalrc -; PIC16: .end caller8_1 - - %call = tail call i32 (i32, ...) @callee8(i32 2, i32 1) nounwind - ret i32 %call -} - -%struct.S = type { [2 x i32] } - -@gs1 = external global %struct.S - -declare i32 @callee9(%struct.S* byval) - -define i32 @caller9_0() nounwind { -entry: -; PIC32: .ent caller9_0 -; PIC32: jr -; PIC32: .end caller9_0 -; STATIC32: .ent caller9_0 -; STATIC32: j -; STATIC32: .end caller9_0 -; N64: .ent caller9_0 -; N64-NOT: jalr $25 -; N64: .end caller9_0 -; PIC16: .ent caller9_0 -; PIC16: jalrc -; PIC16: .end caller9_0 - %call = tail call fastcc i32 @caller9_1() - ret i32 %call -} - -define internal fastcc i32 @caller9_1() nounwind noinline { -entry: -; PIC32: .ent caller9_1 -; PIC32: jalr -; PIC32: .end caller9_1 -; STATIC32: .ent caller9_1 -; STATIC32: jal -; STATIC32: .end caller9_1 -; N64: .ent caller9_1 -; N64: jalr -; N64: .end caller9_1 -; PIC16: .ent caller9_1 -; PIC16: jalrc -; PIC16: .end caller9_1 - - %call = tail call i32 @callee9(%struct.S* byval @gs1) nounwind - ret i32 %call -} - -declare i32 @callee10(i32, i32, i32, i32, i32, i32, i32, i32, i32) - -define i32 @caller10(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7, i32 %a8) nounwind { -entry: -; PIC32: .ent caller10 -; PIC32-NOT: jalr $25 -; STATIC32: .ent caller10 -; STATIC32-NOT: jal -; N64: .ent caller10 -; N64-NOT: jalr $25 -; PIC16: .ent caller10 -; PIC16: jalrc - - %call = tail call i32 @callee10(i32 %a8, i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, i32 %a6, i32 %a7) nounwind - ret i32 %call -} - -declare i32 @callee11(%struct.S* byval) - -define i32 @caller11() nounwind noinline { -entry: -; PIC32: .ent caller11 -; PIC32: jalr -; STATIC32: .ent caller11 -; STATIC32: jal -; N64: .ent caller11 -; N64: jalr -; PIC16: .ent caller11 -; PIC16: jalrc - - %call = tail call i32 @callee11(%struct.S* byval @gs1) nounwind - ret i32 %call -} - -declare i32 @callee12() - -declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind - -define i32 @caller12(%struct.S* nocapture byval %a0) nounwind { -entry: -; PIC32: .ent caller12 -; PIC32: jalr -; STATIC32: .ent caller12 -; STATIC32: jal -; N64: .ent caller12 -; N64: jalr -; PIC16: .ent caller12 -; PIC16: jalrc - - %0 = bitcast %struct.S* %a0 to i8* - tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct.S* @gs1 to i8*), i8* %0, i32 8, i32 4, i1 false) - %call = tail call i32 @callee12() nounwind - ret i32 %call -} - -declare i32 @callee13(i32, ...) - -define i32 @caller13() nounwind { -entry: -; PIC32: .ent caller13 -; PIC32-NOT: jalr -; STATIC32: .ent caller13 -; STATIC32-NOT: jal -; N64: .ent caller13 -; N64-NOT: jalr $25 -; PIC16: .ent caller13 -; PIC16: jalrc - - %call = tail call i32 (i32, ...) @callee13(i32 1, i32 2) nounwind - ret i32 %call -} - -; Check that there is a chain edge between the load and store nodes. -; -; PIC32-LABEL: caller14: -; PIC32: lw ${{[0-9]+}}, 16($sp) -; PIC32: sw $4, 16($sp) - -define void @caller14(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { -entry: - tail call void @callee14(i32 %e, i32 %b, i32 %c, i32 %d, i32 %a) - ret void -} - -declare void @callee14(i32, i32, i32, i32, i32) Index: test/CodeGen/Mips/tailcall/tailcall-wrong-isa.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/tailcall/tailcall-wrong-isa.ll @@ -0,0 +1,43 @@ +; RUN: llc -filetype=obj -march=mipsel -relocation-model=pic -verify-machineinstrs < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=PIC32 + +; RUN: llc -filetype=obj -march=mipsel -relocation-model=static -verify-machineinstrs < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=STATIC32 + +; RUN: llc -filetype=obj -march=mips64el -mcpu=mips64 -verify-machineinstrs < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=N64 + +; RUN: llc -filetype=obj -march=mipsel -relocation-model=pic -mattr=+micromips < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=PIC32MM + +; RUN: llc -filetype=obj -march=mipsel -relocation-model=static -mattr=+micromips < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=STATIC32MM + +; RUN: llc -filetype=obj -march=mipsel -relocation-model=pic -mcpu=mips32r6 < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=PIC32R6 +; RUN: llc -filetype=obj -march=mipsel -relocation-model=static -mcpu=mips32r6 < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=STATIC32R6 + +; RUN: llc -filetype=obj -march=mips64el -mcpu=mips64r6 < %s -o - \ +; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=N64R6 + +declare i8 @f2(i8) + +define i8 @f1(i8 signext %i) nounwind { + %a = tail call i8 @f2(i8 %i) + ret i8 %a +} + +; PIC32: {{[0-9]}}: 08 00 20 03 jr $25 +; STATIC32: {{[0-9]}}: 00 00 00 08 j 0 + +; N64: {{[0-9a-z]+}}: 08 00 20 03 jr $25 + +; PIC32MM: {{[0-9a-z]+}}: b9 45 jrc $25 +; STATIC32MM: {{[0-9]}}: 00 d4 00 00 j 0 + +; PIC32R6: {{[0-9]}}: 00 00 19 d8 jrc $25 +; STATIC32R6: {{[0-9]}}: 00 00 00 08 j 0 + +; N64R6: {{[0-9a-z]+}}: 09 00 20 03 jr $25 +