From 7878b852e63edb758f89f28313be31f8bf1bc92f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 18 Jul 2013 10:06:15 +0000 Subject: [PATCH] [SystemZ] Use RXSBG Extend the previous R.SBG patches to handle XORs. llvm-svn: 186570 --- .../Target/SystemZ/SystemZISelDAGToDAG.cpp | 27 +++-- llvm/test/CodeGen/SystemZ/rxsbg-01.ll | 112 ++++++++++++++++++ 2 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 llvm/test/CodeGen/SystemZ/rxsbg-01.ll diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index aea08083c5ff..67e9d217ee3a 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -241,9 +241,9 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { // Return the selected node on success, otherwise return null. SDNode *tryRISBGZero(SDNode *N); - // Try to use RISBG or ROSBG to implement OR node N. Return the selected - // node on success, otherwise return null. - SDNode *tryRISBGOrROSBG(SDNode *N); + // Try to use RISBG or Opcode to implement OR or XOR node N. + // Return the selected node on success, otherwise return null. + SDNode *tryRxSBG(SDNode *N, unsigned Opcode); // If Op0 is null, then Node is a constant that can be loaded using: // @@ -799,8 +799,8 @@ SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { return convertTo(SDLoc(N), VT, SDValue(N, 0)).getNode(); } -SDNode *SystemZDAGToDAGISel::tryRISBGOrROSBG(SDNode *N) { - // Try treating each operand of N as the second operand of RISBG or ROSBG +SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { + // Try treating each operand of N as the second operand of the RxSBG // and see which goes deepest. RxSBGOperands RxSBG[] = { N->getOperand(0), N->getOperand(1) }; unsigned Count[] = { 0, 0 }; @@ -817,15 +817,14 @@ SDNode *SystemZDAGToDAGISel::tryRISBGOrROSBG(SDNode *N) { SDValue Op0 = N->getOperand(I ^ 1); // Prefer IC for character insertions from memory. - if ((RxSBG[I].Mask & 0xff) == 0) + if (Opcode == SystemZ::ROSBG && (RxSBG[I].Mask & 0xff) == 0) if (LoadSDNode *Load = dyn_cast(Op0.getNode())) if (Load->getMemoryVT() == MVT::i8) return 0; // See whether we can avoid an AND in the first operand by converting // ROSBG to RISBG. - unsigned Opcode = SystemZ::ROSBG; - if (detectOrAndInsertion(Op0, RxSBG[I].Mask)) + if (Opcode == SystemZ::ROSBG && detectOrAndInsertion(Op0, RxSBG[I].Mask)) Opcode = SystemZ::RISBG; EVT VT = N->getValueType(0); @@ -913,9 +912,14 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { switch (Opcode) { case ISD::OR: if (Node->getOperand(1).getOpcode() != ISD::Constant) - ResNode = tryRISBGOrROSBG(Node); - // Fall through. + ResNode = tryRxSBG(Node, SystemZ::ROSBG); + goto or_xor; + case ISD::XOR: + if (Node->getOperand(1).getOpcode() != ISD::Constant) + ResNode = tryRxSBG(Node, SystemZ::RXSBG); + // Fall through. + or_xor: // If this is a 64-bit operation in which both 32-bit halves are nonzero, // split the operation into two. if (!ResNode && Node->getValueType(0) == MVT::i64) @@ -931,7 +935,8 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { case ISD::ROTL: case ISD::SHL: case ISD::SRL: - ResNode = tryRISBGZero(Node); + if (!ResNode) + ResNode = tryRISBGZero(Node); break; case ISD::Constant: diff --git a/llvm/test/CodeGen/SystemZ/rxsbg-01.ll b/llvm/test/CodeGen/SystemZ/rxsbg-01.ll new file mode 100644 index 000000000000..5491bff2ecdc --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/rxsbg-01.ll @@ -0,0 +1,112 @@ +; Test sequences that can use RXSBG. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Test the simple case. +define i32 @f1(i32 %a, i32 %b) { +; CHECK-LABEL: f1: +; CHECK: rxsbg %r2, %r3, 59, 59, 0 +; CHECK: br %r14 + %andb = and i32 %b, 16 + %xor = xor i32 %a, %andb + ret i32 %xor +} + +; ...and again with i64. +define i64 @f2(i64 %a, i64 %b) { +; CHECK-LABEL: f2: +; CHECK: rxsbg %r2, %r3, 59, 59, 0 +; CHECK: br %r14 + %andb = and i64 %b, 16 + %xor = xor i64 %a, %andb + ret i64 %xor +} + +; Test a case where wraparound is needed. +define i32 @f3(i32 %a, i32 %b) { +; CHECK-LABEL: f3: +; CHECK: rxsbg %r2, %r3, 63, 60, 0 +; CHECK: br %r14 + %andb = and i32 %b, -7 + %xor = xor i32 %a, %andb + ret i32 %xor +} + +; ...and again with i64. +define i64 @f4(i64 %a, i64 %b) { +; CHECK-LABEL: f4: +; CHECK: rxsbg %r2, %r3, 63, 60, 0 +; CHECK: br %r14 + %andb = and i64 %b, -7 + %xor = xor i64 %a, %andb + ret i64 %xor +} + +; Test a case with just a shift. +define i32 @f6(i32 %a, i32 %b) { +; CHECK-LABEL: f6: +; CHECK: rxsbg %r2, %r3, 32, 51, 12 +; CHECK: br %r14 + %shlb = shl i32 %b, 12 + %xor = xor i32 %a, %shlb + ret i32 %xor +} + +; ...and again with i64. +define i64 @f7(i64 %a, i64 %b) { +; CHECK-LABEL: f7: +; CHECK: rxsbg %r2, %r3, 0, 51, 12 +; CHECK: br %r14 + %shlb = shl i64 %b, 12 + %xor = xor i64 %a, %shlb + ret i64 %xor +} + +; Test a case with just a rotate (using XOR for the rotate combination too, +; to test that this kind of rotate does get recognised by the target- +; independent code). This can't use RXSBG. +define i32 @f8(i32 %a, i32 %b) { +; CHECK-LABEL: f8: +; CHECK: rll {{%r[0-5]}} +; CHECK: xr {{%r[0-5]}} +; CHECK: br %r14 + %shlb = shl i32 %b, 30 + %shrb = lshr i32 %b, 2 + %rotlb = xor i32 %shlb, %shrb + %xor = xor i32 %a, %rotlb + ret i32 %xor +} + +; ...and again with i64, which can use RXSBG for the rotate. +define i64 @f9(i64 %a, i64 %b) { +; CHECK-LABEL: f9: +; CHECK: rxsbg %r2, %r3, 0, 63, 47 +; CHECK: br %r14 + %shlb = shl i64 %b, 47 + %shrb = lshr i64 %b, 17 + %rotlb = xor i64 %shlb, %shrb + %xor = xor i64 %a, %rotlb + ret i64 %xor +} + +; Test a case with a shift and AND. +define i32 @f10(i32 %a, i32 %b) { +; CHECK-LABEL: f10: +; CHECK: rxsbg %r2, %r3, 56, 59, 4 +; CHECK: br %r14 + %shlb = shl i32 %b, 4 + %andb = and i32 %shlb, 240 + %xor = xor i32 %a, %andb + ret i32 %xor +} + +; ...and again with i64. +define i64 @f11(i64 %a, i64 %b) { +; CHECK-LABEL: f11: +; CHECK: rxsbg %r2, %r3, 56, 59, 4 +; CHECK: br %r14 + %shlb = shl i64 %b, 4 + %andb = and i64 %shlb, 240 + %xor = xor i64 %a, %andb + ret i64 %xor +}