Conditional branches and comparisons
authorAnton Korobeynikov <asl@math.spbu.ru>
Thu, 16 Jul 2009 13:52:31 +0000 (13:52 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Thu, 16 Jul 2009 13:52:31 +0000 (13:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75947 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/SystemZ/SystemZ.h
lib/Target/SystemZ/SystemZISelLowering.cpp
lib/Target/SystemZ/SystemZISelLowering.h
lib/Target/SystemZ/SystemZInstrInfo.td

index c58daa374c85bb44f32f3951236b5e0b7f6fd38c..048dcea8d08890783cc8a993f7778bd6febb9e2b 100644 (file)
@@ -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.
index 9cff6ea2f0d534d394da2e8200191d35fbefcf5f..448f52160d4ba62a2a838ebb7d5d182f5577977a 100644 (file)
@@ -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<CondCodeSDNode>(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;
   }
 }
index 4e74b972430f79d70150853fe4276e823aa8923b..0f432bb3f7df8fb43bf311c6d98a8fcf90ebcaad 100644 (file)
@@ -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;
index 007df017ff27f1635c9de2170eb7e31863053f73..fb1a0706624e591f79336aa06ad58754432707f4 100644 (file)
@@ -27,6 +27,10 @@ class SDTCisI64<int OpNum> : SDTCisVT<OpNum, i64>;
 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 : SDNodeXForm<imm, [{
   // Transformation function: return low 16 bits.
   return getI16Imm(N->getZExtValue() & 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<i32>;
 // 32-bits but only 16 bits are significant.
 def i32i16imm : Operand<i32>;
+// 64-bits but only 32 bits are significant.
+def i64i32imm : Operand<i64>;
+// Branch targets have OtherVT type.
+def brtarget : Operand<OtherVT>;
 
 //===----------------------------------------------------------------------===//
 // 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.
 //===----------------------------------------------------------------------===//