From 4ec3e5ffd10b23c3614cd9a766c2a3ec1fe62ba4 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Thu, 16 Jul 2009 13:52:31 +0000 Subject: [PATCH] Conditional branches and comparisons git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75947 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SystemZ/SystemZ.h | 14 +++ lib/Target/SystemZ/SystemZISelLowering.cpp | 70 +++++++++++ lib/Target/SystemZ/SystemZISelLowering.h | 12 +- lib/Target/SystemZ/SystemZInstrInfo.td | 135 ++++++++++++++++++++- 4 files changed, 228 insertions(+), 3 deletions(-) diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h index c58daa374c8..048dcea8d08 100644 --- a/lib/Target/SystemZ/SystemZ.h +++ b/lib/Target/SystemZ/SystemZ.h @@ -22,12 +22,26 @@ namespace llvm { class FunctionPass; class raw_ostream; + namespace SystemZCC { + // SystemZ specific condition code. These correspond to SYSTEMZ_*_COND in + // SystemZInstrInfo.td. They must be kept in synch. + enum CondCodes { + E = 0, + NE = 1, + H = 2, + L = 3, + HE = 4, + LE = 5 + }; + } + FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel); FunctionPass *createSystemZCodePrinterPass(raw_ostream &o, SystemZTargetMachine &tm, CodeGenOpt::Level OptLevel, bool verbose); + } // end namespace llvm; // Defines symbolic names for SystemZ registers. diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 9cff6ea2f0d..448f52160d4 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -57,6 +57,10 @@ SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) : setSchedulingPreference(SchedulingForLatency); setOperationAction(ISD::RET, MVT::Other, Custom); + + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_CC, MVT::i64, Custom); } SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { @@ -64,6 +68,7 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); case ISD::RET: return LowerRET(Op, DAG); case ISD::CALL: return LowerCALL(Op, DAG); + case ISD::BR_CC: return LowerBR_CC(Op, DAG); default: assert(0 && "unimplemented operand"); return SDValue(); @@ -406,10 +411,75 @@ SDValue SystemZTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain); } +SDValue SystemZTargetLowering::EmitCmp(SDValue LHS, SDValue RHS, + ISD::CondCode CC, SDValue &SystemZCC, + SelectionDAG &DAG) { + assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet"); + + // FIXME: Emit a test if RHS is zero + + bool isUnsigned = false; + SystemZCC::CondCodes TCC; + switch (CC) { + default: assert(0 && "Invalid integer condition!"); + case ISD::SETEQ: + TCC = SystemZCC::E; + break; + case ISD::SETNE: + TCC = SystemZCC::NE; + break; + case ISD::SETULE: + isUnsigned = true; // FALLTHROUGH + case ISD::SETLE: + TCC = SystemZCC::LE; + break; + case ISD::SETUGE: + isUnsigned = true; // FALLTHROUGH + case ISD::SETGE: + TCC = SystemZCC::HE; + break; + case ISD::SETUGT: + isUnsigned = true; + case ISD::SETGT: + TCC = SystemZCC::H; // FALLTHROUGH + break; + case ISD::SETULT: + isUnsigned = true; + case ISD::SETLT: // FALLTHROUGH + TCC = SystemZCC::L; + break; + } + + SystemZCC = DAG.getConstant(TCC, MVT::i32); + + DebugLoc dl = LHS.getDebugLoc(); + return DAG.getNode((isUnsigned ? SystemZISD::UCMP : SystemZISD::CMP), + dl, MVT::Flag, LHS, RHS); +} + + +SDValue SystemZTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + DebugLoc dl = Op.getDebugLoc(); + + SDValue SystemZCC; + SDValue Flag = EmitCmp(LHS, RHS, CC, SystemZCC, DAG); + return DAG.getNode(SystemZISD::BRCOND, dl, Op.getValueType(), + Chain, Dest, SystemZCC, Flag); +} + + const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { case SystemZISD::RET_FLAG: return "SystemZISD::RET_FLAG"; case SystemZISD::CALL: return "SystemZISD::CALL"; + case SystemZISD::BRCOND: return "SystemZISD::BRCOND"; + case SystemZISD::CMP: return "SystemZISD::CMP"; + case SystemZISD::UCMP: return "SystemZISD::UCMP"; default: return NULL; } } diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h index 4e74b972430..0f432bb3f7d 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.h +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -30,7 +30,11 @@ namespace llvm { /// CALL/TAILCALL - These operations represent an abstract call /// instruction, which includes a bunch of information. - CALL + CALL, + + CMP, + UCMP, + BRCOND }; } @@ -51,14 +55,18 @@ namespace llvm { SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); SDValue LowerRET(SDValue Op, SelectionDAG &DAG); SDValue LowerCALL(SDValue Op, SelectionDAG &DAG); + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG); SDValue LowerCCCArguments(SDValue Op, SelectionDAG &DAG); SDValue LowerCCCCallTo(SDValue Op, SelectionDAG &DAG, unsigned CC); - SDNode* LowerCallResult(SDValue Chain, SDValue InFlag, CallSDNode *TheCall, unsigned CallingConv, SelectionDAG &DAG); + SDValue EmitCmp(SDValue LHS, SDValue RHS, + ISD::CondCode CC, SDValue &SystemZCC, + SelectionDAG &DAG); + private: const SystemZSubtarget &Subtarget; const SystemZTargetMachine &TM; diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 007df017ff2..fb1a0706624 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -27,6 +27,10 @@ class SDTCisI64 : SDTCisVT; def SDT_SystemZCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; def SDT_SystemZCallSeqStart : SDCallSeqStart<[SDTCisI64<0>]>; def SDT_SystemZCallSeqEnd : SDCallSeqEnd<[SDTCisI64<0>, SDTCisI64<1>]>; +def SDT_CmpTest : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; +def SDT_BrCond : SDTypeProfile<0, 2, + [SDTCisVT<0, OtherVT>, + SDTCisI8<1>]>; //===----------------------------------------------------------------------===// // SystemZ Specific Node Definitions. @@ -41,10 +45,24 @@ def SystemZcallseq_start : def SystemZcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SystemZCallSeqEnd, [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; +def SystemZcmp : SDNode<"SystemZISD::CMP", SDT_CmpTest, [SDNPOutFlag]>; +def SystemZucmp : SDNode<"SystemZISD::UCMP", SDT_CmpTest, [SDNPOutFlag]>; +def SystemZbrcond : SDNode<"SystemZISD::BRCOND", SDT_BrCond, + [SDNPHasChain, SDNPInFlag]>; //===----------------------------------------------------------------------===// // Instruction Pattern Stuff. //===----------------------------------------------------------------------===// + +// SystemZ specific condition code. These correspond to CondCode in +// SystemZ.h. They must be kept in synch. +def SYSTEMZ_COND_E : PatLeaf<(i8 0)>; +def SYSTEMZ_COND_NE : PatLeaf<(i8 1)>; +def SYSTEMZ_COND_H : PatLeaf<(i8 2)>; +def SYSTEMZ_COND_L : PatLeaf<(i8 3)>; +def SYSTEMZ_COND_HE : PatLeaf<(i8 4)>; +def SYSTEMZ_COND_LE : PatLeaf<(i8 5)>; + def LL16 : SDNodeXFormgetZExtValue() & 0x000000000000FFFFULL); @@ -140,6 +158,18 @@ def i32immSExt16 : PatLeaf<(i32 imm), [{ return (int32_t)N->getZExtValue() == (int16_t)N->getZExtValue(); }]>; +def i64immSExt32 : PatLeaf<(i64 imm), [{ + // i64immSExt32 predicate - True if the 64-bit immediate fits in a 32-bit + // sign extended field. + return (int64_t)N->getZExtValue() == (int32_t)N->getZExtValue(); +}]>; + +def i64immZExt32 : PatLeaf<(i64 imm), [{ + // i64immZExt32 predicate - True if the 64-bit immediate fits in a 32-bit + // zero extended field. + return (uint64_t)N->getZExtValue() == (uint32_t)N->getZExtValue(); +}]>; + // extloads def extloadi64i8 : PatFrag<(ops node:$ptr), (i64 (extloadi8 node:$ptr))>; def extloadi64i16 : PatFrag<(ops node:$ptr), (i64 (extloadi16 node:$ptr))>; @@ -158,6 +188,10 @@ def zextloadi64i32 : PatFrag<(ops node:$ptr), (i64 (zextloadi32 node:$ptr))>; def i32i8imm : Operand; // 32-bits but only 16 bits are significant. def i32i16imm : Operand; +// 64-bits but only 32 bits are significant. +def i64i32imm : Operand; +// Branch targets have OtherVT type. +def brtarget : Operand; //===----------------------------------------------------------------------===// // SystemZ Operand Definitions. @@ -208,10 +242,34 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), // // FIXME: Provide proper encoding! -let isReturn = 1, isTerminator = 1 in { +let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in { def RET : Pseudo<(outs), (ins), "br\t%r14", [(SystemZretflag)]>; } +let isBranch = 1, isTerminator = 1 in { + let Uses = [PSW] in { + def JE : Pseudo<(outs), (ins brtarget:$dst), + "je\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_E)]>; + def JNE : Pseudo<(outs), (ins brtarget:$dst), + "jne\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_NE)]>; + def JH : Pseudo<(outs), (ins brtarget:$dst), + "jh\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_H)]>; + def JL : Pseudo<(outs), (ins brtarget:$dst), + "jl\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_L)]>; + def JHE : Pseudo<(outs), (ins brtarget:$dst), + "jhe\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_HE)]>; + def JLE : Pseudo<(outs), (ins brtarget:$dst), + "jle\t$dst", + [(SystemZbrcond bb:$dst, SYSTEMZ_COND_LE)]>; + + } // Uses = [PSW] +} // isBranch = 1 + //===----------------------------------------------------------------------===// // Call Instructions... // @@ -560,6 +618,81 @@ def SRA64ri : Pseudo<(outs GR64:$dst), (ins GR64:$src, i32imm:$amt), (implicit PSW)]>; } // Defs = [PSW] +//===----------------------------------------------------------------------===// +// Test instructions (like AND but do not produce any result + +// Integer comparisons +let Defs = [PSW] in { +def CMP32rr : Pseudo<(outs), (ins GR32:$src1, GR32:$src2), + "cr\t$src1, $src2", + [(SystemZcmp GR32:$src1, GR32:$src2), (implicit PSW)]>; +def CMP64rr : Pseudo<(outs), (ins GR64:$src1, GR64:$src2), + "cgr\t$src1, $src2", + [(SystemZcmp GR64:$src1, GR64:$src2), (implicit PSW)]>; + +def CMP32ri : Pseudo<(outs), (ins GR32:$src1, i32imm:$src2), + "cfi\t$src1, $src2", + [(SystemZcmp GR32:$src1, imm:$src2), (implicit PSW)]>; +def CMP64ri32 : Pseudo<(outs), (ins GR64:$src1, i64i32imm:$src2), + "cgfi\t$src1, $src2", + [(SystemZcmp GR64:$src1, i64immSExt32:$src2), + (implicit PSW)]>; + +def CMP32rm : Pseudo<(outs), (ins GR32:$src1, rriaddr:$src2), + "cy\t$src1, $src2", + [(SystemZcmp GR32:$src1, (load rriaddr:$src2)), + (implicit PSW)]>; +def CMP64rm : Pseudo<(outs), (ins GR64:$src1, rriaddr:$src2), + "cg\t$src1, $src2", + [(SystemZcmp GR64:$src1, (load rriaddr:$src2)), + (implicit PSW)]>; + +def UCMP32rr : Pseudo<(outs), (ins GR32:$src1, GR32:$src2), + "clr\t$src1, $src2", + [(SystemZucmp GR32:$src1, GR32:$src2), (implicit PSW)]>; +def UCMP64rr : Pseudo<(outs), (ins GR64:$src1, GR64:$src2), + "clgr\t$src1, $src2", + [(SystemZucmp GR64:$src1, GR64:$src2), (implicit PSW)]>; + +def UCMP32ri : Pseudo<(outs), (ins GR32:$src1, i32imm:$src2), + "clfi\t$src1, $src2", + [(SystemZucmp GR32:$src1, imm:$src2), (implicit PSW)]>; +def UCMP64ri32 : Pseudo<(outs), (ins GR64:$src1, i64i32imm:$src2), + "clgfi\t$src1, $src2", + [(SystemZucmp GR64:$src1, i64immZExt32:$src2), + (implicit PSW)]>; + +def UCMP32rm : Pseudo<(outs), (ins GR32:$src1, rriaddr:$src2), + "cly\t$src1, $src2", + [(SystemZucmp GR32:$src1, (load rriaddr:$src2)), + (implicit PSW)]>; +def UCMP64rm : Pseudo<(outs), (ins GR64:$src1, rriaddr:$src2), + "clg\t$src1, $src2", + [(SystemZucmp GR64:$src1, (load rriaddr:$src2)), + (implicit PSW)]>; + +def CMPSX64rr32 : Pseudo<(outs), (ins GR64:$src1, GR32:$src2), + "cgfr\t$src1, $src2", + [(SystemZucmp GR64:$src1, (sext GR32:$src2)), + (implicit PSW)]>; +def UCMPZX64rr32 : Pseudo<(outs), (ins GR64:$src1, GR32:$src2), + "clgfr\t$src1, $src2", + [(SystemZucmp GR64:$src1, (zext GR32:$src2)), + (implicit PSW)]>; + +def CMPSX64rm32 : Pseudo<(outs), (ins GR64:$src1, rriaddr:$src2), + "cgf\t$src1, $src2", + [(SystemZucmp GR64:$src1, (sextloadi64i32 rriaddr:$src2)), + (implicit PSW)]>; +def UCMPZX64rm32 : Pseudo<(outs), (ins GR64:$src1, rriaddr:$src2), + "clgf\t$src1, $src2", + [(SystemZucmp GR64:$src1, (zextloadi64i32 rriaddr:$src2)), + (implicit PSW)]>; + +// FIXME: Add other crazy ucmp forms + +} // Defs = [PSW] + //===----------------------------------------------------------------------===// // Non-Instruction Patterns. //===----------------------------------------------------------------------===// -- 2.34.1