Index: llvm/trunk/lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ llvm/trunk/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -216,6 +216,85 @@ LoweredMI = MCInstBuilder(SystemZ::BR).addReg(SystemZ::R1D); break; + case SystemZ::CallBCR: + LoweredMI = MCInstBuilder(SystemZ::BCR) + .addImm(MI->getOperand(0).getImm()) + .addImm(MI->getOperand(1).getImm()) + .addReg(SystemZ::R1D); + break; + + case SystemZ::CRBCall: + LoweredMI = MCInstBuilder(SystemZ::CRB) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CGRBCall: + LoweredMI = MCInstBuilder(SystemZ::CGRB) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CIBCall: + LoweredMI = MCInstBuilder(SystemZ::CIB) + .addReg(MI->getOperand(0).getReg()) + .addImm(MI->getOperand(1).getImm()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CGIBCall: + LoweredMI = MCInstBuilder(SystemZ::CGIB) + .addReg(MI->getOperand(0).getReg()) + .addImm(MI->getOperand(1).getImm()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CLRBCall: + LoweredMI = MCInstBuilder(SystemZ::CLRB) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CLGRBCall: + LoweredMI = MCInstBuilder(SystemZ::CLGRB) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CLIBCall: + LoweredMI = MCInstBuilder(SystemZ::CLIB) + .addReg(MI->getOperand(0).getReg()) + .addImm(MI->getOperand(1).getImm()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + + case SystemZ::CLGIBCall: + LoweredMI = MCInstBuilder(SystemZ::CLGIB) + .addReg(MI->getOperand(0).getReg()) + .addImm(MI->getOperand(1).getImm()) + .addImm(MI->getOperand(2).getImm()) + .addReg(SystemZ::R1D) + .addImm(0); + break; + case SystemZ::TLS_GDCALL: LoweredMI = MCInstBuilder(SystemZ::BRASL) .addReg(SystemZ::R14D) Index: llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp +++ llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp @@ -392,6 +392,9 @@ case SystemZ::CondReturn: Type = SystemZII::CompareAndReturn; break; + case SystemZ::CallBCR: + Type = SystemZII::CompareAndSibcall; + break; default: return false; } @@ -412,19 +415,24 @@ (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI))) return false; - // Read the branch mask and target (if applicable). + // Read the branch mask, target (if applicable), regmask (if applicable). MachineOperand CCMask(MBBI->getOperand(1)); assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 && "Invalid condition-code mask for integer comparison"); // This is only valid for CompareAndBranch. MachineOperand Target(MBBI->getOperand( Type == SystemZII::CompareAndBranch ? 2 : 0)); + const uint32_t *RegMask; + if (Type == SystemZII::CompareAndSibcall) + RegMask = MBBI->getOperand(2).getRegMask(); // Clear out all current operands. int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI); assert(CCUse >= 0 && "BRC/BCR must use CC"); Branch->RemoveOperand(CCUse); - if (Type == SystemZII::CompareAndBranch) + // Remove target (branch) or regmask (sibcall). + if (Type == SystemZII::CompareAndBranch || + Type == SystemZII::CompareAndSibcall) Branch->RemoveOperand(2); Branch->RemoveOperand(1); Branch->RemoveOperand(0); @@ -444,6 +452,9 @@ .addReg(SystemZ::CC, RegState::ImplicitDefine); } + if (Type == SystemZII::CompareAndSibcall) + MIB.addRegMask(RegMask); + // Clear any intervening kills of SrcReg and SrcReg2. MBBI = Compare; for (++MBBI; MBBI != MBBE; ++MBBI) { Index: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h +++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h @@ -119,7 +119,10 @@ CompareAndBranch, // Indirect branch, used for return - CRBReturn etc. - CompareAndReturn + CompareAndReturn, + + // Indirect branch, used for sibcall - CRBCall etc. + CompareAndSibcall }; } // end namespace SystemZII Index: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -511,7 +511,8 @@ if (STI.hasLoadStoreOnCond() && getConditionalMove(Opcode)) return true; if (Opcode == SystemZ::Return || - Opcode == SystemZ::CallJG) + Opcode == SystemZ::CallJG || + Opcode == SystemZ::CallBR) return true; return false; } @@ -585,6 +586,16 @@ .addReg(SystemZ::CC, RegState::Implicit); return true; } + if (Opcode == SystemZ::CallBR) { + const uint32_t *RegMask = MI.getOperand(0).getRegMask(); + MI.RemoveOperand(0); + MI.setDesc(get(SystemZ::CallBCR)); + MachineInstrBuilder(*MI.getParent()->getParent(), MI) + .addImm(CCValid).addImm(CCMask) + .addRegMask(RegMask) + .addReg(SystemZ::CC, RegState::Implicit); + return true; + } return false; } @@ -1348,6 +1359,27 @@ default: return 0; } + case SystemZII::CompareAndSibcall: + switch (Opcode) { + case SystemZ::CR: + return SystemZ::CRBCall; + case SystemZ::CGR: + return SystemZ::CGRBCall; + case SystemZ::CHI: + return SystemZ::CIBCall; + case SystemZ::CGHI: + return SystemZ::CGIBCall; + case SystemZ::CLR: + return SystemZ::CLRBCall; + case SystemZ::CLGR: + return SystemZ::CLGRBCall; + case SystemZ::CLFI: + return SystemZ::CLIBCall; + case SystemZ::CLGFI: + return SystemZ::CLGIBCall; + default: + return 0; + } } return 0; } Index: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td +++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td @@ -327,10 +327,26 @@ def CallBR : Alias<2, (outs), (ins), [(z_sibcall R1D)]>; } -let CCMaskFirst = 1, isCall = 1, isReturn = 1 in +let CCMaskFirst = 1, isCall = 1, isTerminator = 1, isReturn = 1 in { def CallBRCL : Alias<6, (outs), (ins cond4:$valid, cond4:$R1, pcrel32:$I2), []>; + let Uses = [R1D] in + def CallBCR : Alias<2, (outs), (ins cond4:$valid, cond4:$R1), []>; +} + +// Fused compare and conditional sibling calls. +let isCall = 1, isTerminator = 1, isReturn = 1, Uses = [R1D] in { + def CRBCall : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>; + def CGRBCall : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>; + def CIBCall : Alias<6, (outs), (ins GR32:$R1, imm32sx8:$I2, cond4:$M3), []>; + def CGIBCall : Alias<6, (outs), (ins GR64:$R1, imm64sx8:$I2, cond4:$M3), []>; + def CLRBCall : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>; + def CLGRBCall : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>; + def CLIBCall : Alias<6, (outs), (ins GR32:$R1, imm32zx8:$I2, cond4:$M3), []>; + def CLGIBCall : Alias<6, (outs), (ins GR64:$R1, imm64zx8:$I2, cond4:$M3), []>; +} + // TLS calls. These will be lowered into a call to __tls_get_offset, // with an extra relocation specifying the TLS symbol. let isCall = 1, Defs = [R14D, CC] in { Index: llvm/trunk/test/CodeGen/SystemZ/call-05.ll =================================================================== --- llvm/trunk/test/CodeGen/SystemZ/call-05.ll +++ llvm/trunk/test/CodeGen/SystemZ/call-05.ll @@ -0,0 +1,467 @@ +; Test conditional sibling calls. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + + +@var = global i32 1; +@fun_a = global void()* null; +@fun_b = global void()* null; +@fun_c = global void(i32)* null; + +; Check a conditional sibling call. +define void @f1(i32 %val1, i32 %val2) { +; CHECK-LABEL: f1: +; CHECK: crbl %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp slt i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call when there are two possibilities. +define void @f2(i32 %val1, i32 %val2) { +; CHECK-LABEL: f2: +; CHECK: crbl %r2, %r3, 0(%r1) +; CHECK: br %r1 + %fun_a = load volatile void() *, void()** @fun_a; + %fun_b = load volatile void() *, void()** @fun_b; + %cond = icmp slt i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + tail call void %fun_b() + ret void +} + +; Check a conditional sibling call with an argument - not supported. +define void @f3(i32 %val1, i32 %val2) { +; CHECK-LABEL: f3: +; CHECK: crjhe %r2, %r3 +; CHECK: br %r1 +; CHECK: br %r14 + %fun_c = load volatile void(i32) *, void(i32)** @fun_c; + %cond = icmp slt i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_c(i32 1) + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - unsigned compare. +define void @f4(i32 %val1, i32 %val2) { +; CHECK-LABEL: f4: +; CHECK: clrbl %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ult i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - 64-bit compare. +define void @f5(i64 %val1, i64 %val2) { +; CHECK-LABEL: f5: +; CHECK: cgrbl %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp slt i64 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - unsigned 64-bit compare. +define void @f6(i64 %val1, i64 %val2) { +; CHECK-LABEL: f6: +; CHECK: clgrbl %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ult i64 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - less-equal compare. +define void @f7(i32 %val1, i32 %val2) { +; CHECK-LABEL: f7: +; CHECK: crble %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sle i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - high compare. +define void @f8(i32 %val1, i32 %val2) { +; CHECK-LABEL: f8: +; CHECK: crbh %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sgt i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - high-equal compare. +define void @f9(i32 %val1, i32 %val2) { +; CHECK-LABEL: f9: +; CHECK: crbhe %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sge i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - equal compare. +define void @f10(i32 %val1, i32 %val2) { +; CHECK-LABEL: f10: +; CHECK: crbe %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp eq i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - unequal compare. +define void @f11(i32 %val1, i32 %val2) { +; CHECK-LABEL: f11: +; CHECK: crblh %r2, %r3, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ne i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate slt. +define void @f12(i32 %val1) { +; CHECK-LABEL: f12: +; CHECK: cible %r2, 4, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp slt i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate sle. +define void @f13(i32 %val1) { +; CHECK-LABEL: f13: +; CHECK: cible %r2, 5, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sle i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate sgt. +define void @f14(i32 %val1) { +; CHECK-LABEL: f14: +; CHECK: cibhe %r2, 6, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sgt i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate sge. +define void @f15(i32 %val1) { +; CHECK-LABEL: f15: +; CHECK: cibhe %r2, 5, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp sge i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate eq. +define void @f16(i32 %val1) { +; CHECK-LABEL: f16: +; CHECK: cibe %r2, 5, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp eq i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate ne. +define void @f17(i32 %val1) { +; CHECK-LABEL: f17: +; CHECK: ciblh %r2, 5, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ne i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate ult. +define void @f18(i32 %val1) { +; CHECK-LABEL: f18: +; CHECK: clible %r2, 4, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ult i32 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate 64-bit slt. +define void @f19(i64 %val1) { +; CHECK-LABEL: f19: +; CHECK: cgible %r2, 4, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp slt i64 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - immediate 64-bit ult. +define void @f20(i64 %val1) { +; CHECK-LABEL: f20: +; CHECK: clgible %r2, 4, 0(%r1) +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = icmp ult i64 %val1, 5; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call to an argument - will fail due to +; intervening lgr. +define void @f21(i32 %val1, i32 %val2, void()* %fun) { +; CHECK-LABEL: f21: +; CHECK: crjhe %r2, %r3 +; CHECK: lgr %r1, %r4 +; CHECK: br %r1 +; CHECK: br %r14 + %cond = icmp slt i32 %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - float olt compare. +define void @f22(float %val1, float %val2) { +; CHECK-LABEL: f22: +; CHECK: cebr %f0, %f2 +; CHECK: blr %r1 +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = fcmp olt float %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - float ult compare. +define void @f23(float %val1, float %val2) { +; CHECK-LABEL: f23: +; CHECK: cebr %f0, %f2 +; CHECK: bnher %r1 +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = fcmp ult float %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - float ord compare. +define void @f24(float %val1, float %val2) { +; CHECK-LABEL: f24: +; CHECK: cebr %f0, %f2 +; CHECK: bnor %r1 +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = fcmp ord float %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +} + +; Check a conditional sibling call - float uno compare. +define void @f25(float %val1, float %val2) { +; CHECK-LABEL: f25: +; CHECK: cebr %f0, %f2 +; CHECK: bor %r1 +; CHECK: br %r14 + %fun_a = load volatile void() *, void()** @fun_a; + %cond = fcmp uno float %val1, %val2; + br i1 %cond, label %a, label %b; + +a: + tail call void %fun_a() + ret void + +b: + store i32 1, i32 *@var; + ret void +}