[SystemZ] Use MVST to implement strcpy and stpcpy
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 16 Aug 2013 11:29:37 +0000 (11:29 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Fri, 16 Aug 2013 11:29:37 +0000 (11:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188546 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/llvm/Target/TargetLibraryInfo.h
include/llvm/Target/TargetSelectionDAGInfo.h
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
lib/Target/SystemZ/SystemZISelLowering.cpp
lib/Target/SystemZ/SystemZISelLowering.h
lib/Target/SystemZ/SystemZInstrInfo.td
lib/Target/SystemZ/SystemZOperators.td
lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
lib/Target/SystemZ/SystemZSelectionDAGInfo.h
test/CodeGen/SystemZ/strcpy-01.ll [new file with mode: 0644]
test/MC/Disassembler/SystemZ/insns.txt
test/MC/SystemZ/insn-good.s

index a033d07387a9aa1e4e5cc83c7acb19736c375673..7a06415f4b68a3f83b2079e67bebbb32b3674657 100644 (file)
@@ -699,7 +699,8 @@ public:
     case LibFunc::trunc:     case LibFunc::truncf:     case LibFunc::truncl:
     case LibFunc::log2:      case LibFunc::log2f:      case LibFunc::log2l:
     case LibFunc::exp2:      case LibFunc::exp2f:      case LibFunc::exp2l:
-    case LibFunc::memcmp:    case LibFunc::strcmp:
+    case LibFunc::memcmp:    case LibFunc::strcmp:     case LibFunc::strcpy:
+    case LibFunc::stpcpy:
       return true;
     }
     return false;
index 2d0989c8ffeef32493ff5185a91af3cbeb921064..5e65c304a1dfd5824bc0447589d3f2ea9e79d751 100644 (file)
@@ -109,6 +109,21 @@ public:
     return std::make_pair(SDValue(), SDValue());
   }
 
+  /// EmitTargetCodeForStrcpy - Emit target-specific code that performs a
+  /// strcpy or stpcpy, in cases where that is faster than a libcall.
+  /// The first returned SDValue is the result of the copy (the start
+  /// of the destination string for strcpy, a pointer to the null terminator
+  /// for stpcpy) and the second is the chain.  Both SDValues can be null
+  /// if a normal libcall should be used.
+  virtual std::pair<SDValue, SDValue>
+  EmitTargetCodeForStrcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
+                          SDValue Dest, SDValue Src,
+                          MachinePointerInfo DestPtrInfo,
+                          MachinePointerInfo SrcPtrInfo,
+                          bool isStpcpy) const {
+    return std::make_pair(SDValue(), SDValue());
+  }
+
   /// EmitTargetCodeForStrcmp - Emit target-specific code that performs a
   /// strcmp, in cases where that is faster than a libcall.  The first
   /// returned SDValue is the result of the strcmp and the second is
index b1812f2cda96f4fcbd13e183b4628fd96773e7de..9bb78978e11149add37ba70fda574d6a5eb90e42 100644 (file)
@@ -5558,6 +5558,35 @@ bool SelectionDAGBuilder::visitMemCmpCall(const CallInst &I) {
   return false;
 }
 
+/// visitStrCpyCall -- See if we can lower a strcpy or stpcpy call into an
+/// optimized form.  If so, return true and lower it, otherwise return false
+/// and it will be lowered like a normal call.
+bool SelectionDAGBuilder::visitStrCpyCall(const CallInst &I, bool isStpcpy) {
+  // Verify that the prototype makes sense.  char *strcpy(char *, char *)
+  if (I.getNumArgOperands() != 2)
+    return false;
+
+  const Value *Arg0 = I.getArgOperand(0), *Arg1 = I.getArgOperand(1);
+  if (!Arg0->getType()->isPointerTy() ||
+      !Arg1->getType()->isPointerTy() ||
+      !I.getType()->isPointerTy())
+    return false;
+
+  const TargetSelectionDAGInfo &TSI = DAG.getSelectionDAGInfo();
+  std::pair<SDValue, SDValue> Res =
+    TSI.EmitTargetCodeForStrcpy(DAG, getCurSDLoc(), getRoot(),
+                                getValue(Arg0), getValue(Arg1),
+                                MachinePointerInfo(Arg0),
+                                MachinePointerInfo(Arg1), isStpcpy);
+  if (Res.first.getNode()) {
+    setValue(&I, Res.first);
+    DAG.setRoot(Res.second);
+    return true;
+  }
+
+  return false;
+}
+
 /// visitStrCmpCall - See if we can lower a call to strcmp in an optimized form.
 /// If so, return true and lower it, otherwise return false and it will be
 /// lowered like a normal call.
@@ -5733,6 +5762,14 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
         if (visitMemCmpCall(I))
           return;
         break;
+      case LibFunc::strcpy:
+        if (visitStrCpyCall(I, false))
+          return;
+        break;
+      case LibFunc::stpcpy:
+        if (visitStrCpyCall(I, true))
+          return;
+        break;
       case LibFunc::strcmp:
         if (visitStrCmpCall(I))
           return;
index ff15347aae5bc64c55f942de22dabd252f1f12c6..7c6e671b73f435f1b620b340ff8eb607ea6937a5 100644 (file)
@@ -523,6 +523,7 @@ private:
   void visitPHI(const PHINode &I);
   void visitCall(const CallInst &I);
   bool visitMemCmpCall(const CallInst &I);
+  bool visitStrCpyCall(const CallInst &I, bool isStpcpy);
   bool visitStrCmpCall(const CallInst &I);
   bool visitUnaryFloatCall(const CallInst &I, unsigned Opcode);
   void visitAtomicLoad(const LoadInst &I);
index 1fe54f1280f8c7b536684ae09c270201aa2a5693..b22cc40155d77133ac833dbc2b02e04dcbdee2f8 100644 (file)
@@ -1703,6 +1703,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
     OPCODE(MVC);
     OPCODE(CLC);
     OPCODE(STRCMP);
+    OPCODE(STPCPY);
     OPCODE(IPM);
     OPCODE(ATOMIC_SWAPW);
     OPCODE(ATOMIC_LOADW_ADD);
@@ -2551,6 +2552,8 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
     return emitMemMemWrapper(MI, MBB, SystemZ::CLC);
   case SystemZ::CLSTLoop:
     return emitStringWrapper(MI, MBB, SystemZ::CLST);
+  case SystemZ::MVSTLoop:
+    return emitStringWrapper(MI, MBB, SystemZ::MVST);
   default:
     llvm_unreachable("Unexpected instr type to insert");
   }
index 4ee87d3cb8e43676f92917b856ab1590af2bf3a1..b27f1672e83fe7d347625a34c89dae2acbcbab4b 100644 (file)
@@ -84,6 +84,9 @@ namespace SystemZISD {
     // as for MVC.
     CLC,
 
+    // Use an MVST-based sequence to implement stpcpy().
+    STPCPY,
+
     // Use a CLST-based sequence to implement strcmp().  The two input operands
     // are the addresses of the strings to compare.
     STRCMP,
index 31832f70d298d0405b4dcb1027b9f84070047671..43537aa3cc1454786cd8613de53ac618025650a5 100644 (file)
@@ -336,6 +336,10 @@ def MVGHI : StoreSIL<"mvghi", 0xE548, store,         imm64sx16>;
 let mayLoad = 1, mayStore = 1 in
   defm MVC : MemorySS<"mvc", 0xD2, z_mvc>;
 
+// String moves.
+let mayLoad = 1, mayStore = 1, Defs = [CC], Uses = [R0W] in
+  defm MVST : StringRRE<"mvst", 0xB255, z_stpcpy>;
+
 defm LoadStore8_32  : MVCLoadStore<anyextloadi8, truncstorei8, i32,
                                    MVCWrapper, 1>;
 defm LoadStore16_32 : MVCLoadStore<anyextloadi16, truncstorei16, i32,
index 816fb5d6b1cf5aea28c6de0166b17d9627f7c453..e0eeab109d48e320988f8fd5079773e7aac9909f 100644 (file)
@@ -121,6 +121,8 @@ def z_clc               : SDNode<"SystemZISD::CLC", SDT_ZMemMemLength,
                                  [SDNPHasChain, SDNPOutGlue, SDNPMayLoad]>;
 def z_strcmp            : SDNode<"SystemZISD::STRCMP", SDT_ZString,
                                  [SDNPHasChain, SDNPOutGlue, SDNPMayLoad]>;
+def z_stpcpy            : SDNode<"SystemZISD::STPCPY", SDT_ZString,
+                                 [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
 def z_ipm               : SDNode<"SystemZISD::IPM", SDT_ZI32Intrinsic,
                                  [SDNPInGlue]>;
 
index 789594b36c6025be9c05017ab4b43b140c427262..0a2080db0b99356881d2dd7f30daa4e93fa1df71 100644 (file)
@@ -158,6 +158,17 @@ EmitTargetCodeForMemcmp(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
   return std::make_pair(SDValue(), SDValue());
 }
 
+std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::
+EmitTargetCodeForStrcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
+                        SDValue Dest, SDValue Src,
+                        MachinePointerInfo DestPtrInfo,
+                        MachinePointerInfo SrcPtrInfo, bool isStpcpy) const {
+  SDVTList VTs = DAG.getVTList(Dest.getValueType(), MVT::Other);
+  SDValue EndDest = DAG.getNode(SystemZISD::STPCPY, DL, VTs, Chain, Dest, Src,
+                                DAG.getConstant(0, MVT::i32));
+  return std::make_pair(isStpcpy ? EndDest : Dest, EndDest.getValue(1));
+}
+
 std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::
 EmitTargetCodeForStrcmp(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                         SDValue Src1, SDValue Src2,
index c874a4d1925a7cb98e7552b2f55e43ac1913b14e..123cb63c09c6f575b74039e1ab4fe6f1f64656aa 100644 (file)
@@ -46,6 +46,13 @@ public:
                           MachinePointerInfo Op1PtrInfo,
                           MachinePointerInfo Op2PtrInfo) const LLVM_OVERRIDE;
 
+  virtual std::pair<SDValue, SDValue>
+  EmitTargetCodeForStrcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
+                          SDValue Dest, SDValue Src,
+                          MachinePointerInfo DestPtrInfo,
+                          MachinePointerInfo SrcPtrInfo,
+                          bool isStpcpy) const LLVM_OVERRIDE;
+
   virtual std::pair<SDValue, SDValue>
   EmitTargetCodeForStrcmp(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                           SDValue Src1, SDValue Src2,
diff --git a/test/CodeGen/SystemZ/strcpy-01.ll b/test/CodeGen/SystemZ/strcpy-01.ll
new file mode 100644 (file)
index 0000000..29bab62
--- /dev/null
@@ -0,0 +1,50 @@
+; Test strcpy using MVST.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+declare i8 *@strcpy(i8 *%dest, i8 *%src)
+declare i8 *@stpcpy(i8 *%dest, i8 *%src)
+
+; Check strcpy.
+define i8 *@f1(i8 *%dest, i8 *%src) {
+; CHECK-LABEL: f1:
+; CHECK-DAG: lhi %r0, 0
+; CHECK-DAG: lgr [[REG:%r[145]]], %r2
+; CHECK: [[LABEL:\.[^:]*]]:
+; CHECK-NEXT: mvst [[REG]], %r3
+; CHECK-NEXT: jo [[LABEL]]
+; CHECK-NOT: %r2
+; CHECK: br %r14
+  %res = call i8 *@strcpy(i8 *%dest, i8 *%src)
+  ret i8 *%res
+}
+
+; Check stpcpy.
+define i8 *@f2(i8 *%dest, i8 *%src) {
+; CHECK-LABEL: f2:
+; CHECK: lhi %r0, 0
+; CHECK: [[LABEL:\.[^:]*]]:
+; CHECK-NEXT: mvst %r2, %r3
+; CHECK-NEXT: jo [[LABEL]]
+; CHECK-NOT: %r2
+; CHECK: br %r14
+  %res = call i8 *@stpcpy(i8 *%dest, i8 *%src)
+  ret i8 *%res
+}
+
+; Check correct operation with other loads and stores.  The load must
+; come before the loop and the store afterwards.
+define i32 @f3(i32 %dummy, i8 *%dest, i8 *%src, i32 *%resptr, i32 *%storeptr) {
+; CHECK-LABEL: f3:
+; CHECK-DAG: lhi %r0, 0
+; CHECK-DAG: l %r2, 0(%r5)
+; CHECK: [[LABEL:\.[^:]*]]:
+; CHECK-NEXT: mvst %r3, %r4
+; CHECK-NEXT: jo [[LABEL]]
+; CHECK: mvhi 0(%r6), 0
+; CHECK: br %r14
+  %res = load i32 *%resptr
+  %unused = call i8 *@strcpy(i8 *%dest, i8 *%src)
+  store i32 0, i32 *%storeptr
+  ret i32 %res
+}
index 5f2bc896e3f47031aaec3327984badfeea33ff64..c25bb9f946132bd20a63aec7808f9700ab6577ad 100644 (file)
 # CHECK: mviy 524287(%r15), 42
 0xeb 0x2a 0xff 0xff 0x7f 0x52
 
+# CHECK: mvst %r0, %r0
+0xb2 0x55 0x00 0x00
+
+# CHECK: mvst %r0, %r15
+0xb2 0x55 0x00 0x0f
+
+# CHECK: mvst %r15, %r0
+0xb2 0x55 0x00 0xf0
+
+# CHECK: mvst %r7, %r8
+0xb2 0x55 0x00 0x78
+
 # CHECK: mxbr %f0, %f0
 0xb3 0x4c 0x00 0x00
 
index a4529927e1a81d0dcf9fb8348bdcaf48b6577662..da2b77e4eb7d2861c279cc270a3f18016ec1f300 100644 (file)
        mviy    524287(%r1), 42
        mviy    524287(%r15), 42
 
+#CHECK: mvst   %r0, %r0                # encoding: [0xb2,0x55,0x00,0x00]
+#CHECK: mvst   %r0, %r15               # encoding: [0xb2,0x55,0x00,0x0f]
+#CHECK: mvst   %r15, %r0               # encoding: [0xb2,0x55,0x00,0xf0]
+#CHECK: mvst   %r7, %r8                # encoding: [0xb2,0x55,0x00,0x78]
+
+       mvst    %r0,%r0
+       mvst    %r0,%r15
+       mvst    %r15,%r0
+       mvst    %r7,%r8
+
 #CHECK: mxbr   %f0, %f0                # encoding: [0xb3,0x4c,0x00,0x00]
 #CHECK: mxbr   %f0, %f13               # encoding: [0xb3,0x4c,0x00,0x0d]
 #CHECK: mxbr   %f8, %f5                # encoding: [0xb3,0x4c,0x00,0x85]