aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
blob: 341dc9465502a0e2c14bc556a9b6c634235724f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//===-- SystemZSelectionDAGInfo.cpp - SystemZ SelectionDAG Info -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the SystemZSelectionDAGInfo class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "systemz-selectiondag-info"
#include "SystemZTargetMachine.h"
#include "llvm/CodeGen/SelectionDAG.h"

using namespace llvm;

SystemZSelectionDAGInfo::
SystemZSelectionDAGInfo(const SystemZTargetMachine &TM)
  : TargetSelectionDAGInfo(TM) {
}

SystemZSelectionDAGInfo::~SystemZSelectionDAGInfo() {
}

SDValue SystemZSelectionDAGInfo::
EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                        SDValue Dst, SDValue Src, SDValue Size, unsigned Align,
                        bool IsVolatile, bool AlwaysInline,
                        MachinePointerInfo DstPtrInfo,
                        MachinePointerInfo SrcPtrInfo) const {
  if (IsVolatile)
    return SDValue();

  if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
    uint64_t Bytes = CSize->getZExtValue();
    if (Bytes >= 1 && Bytes <= 0x100) {
      // A single MVC.
      return DAG.getNode(SystemZISD::MVC, DL, MVT::Other,
                         Chain, Dst, Src, Size);
    }
  }
  return SDValue();
}

// Handle a memset of 1, 2, 4 or 8 bytes with the operands given by
// Chain, Dst, ByteVal and Size.  These cases are expected to use
// MVI, MVHHI, MVHI and MVGHI respectively.
static SDValue memsetStore(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                           SDValue Dst, uint64_t ByteVal, uint64_t Size,
                           unsigned Align,
                           MachinePointerInfo DstPtrInfo) {
  uint64_t StoreVal = ByteVal;
  for (unsigned I = 1; I < Size; ++I)
    StoreVal |= ByteVal << (I * 8);
  return DAG.getStore(Chain, DL,
                      DAG.getConstant(StoreVal, MVT::getIntegerVT(Size * 8)),
                      Dst, DstPtrInfo, false, false, Align);
}

SDValue SystemZSelectionDAGInfo::
EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                        SDValue Dst, SDValue Byte, SDValue Size,
                        unsigned Align, bool IsVolatile,
                        MachinePointerInfo DstPtrInfo) const {
  EVT DstVT = Dst.getValueType();

  if (IsVolatile)
    return SDValue();

  if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
    uint64_t Bytes = CSize->getZExtValue();
    if (Bytes == 0)
      return SDValue();
    if (ConstantSDNode *CByte = dyn_cast<ConstantSDNode>(Byte)) {
      // Handle cases that can be done using at most two of
      // MVI, MVHI, MVHHI and MVGHI.  The latter two can only be
      // used if ByteVal is all zeros or all ones; in other casees,
      // we can move at most 2 halfwords.
      uint64_t ByteVal = CByte->getZExtValue();
      if (ByteVal == 0 || ByteVal == 255 ?
          Bytes <= 16 && CountPopulation_64(Bytes) <= 2 :
          Bytes <= 4) {
        unsigned Size1 = Bytes == 16 ? 8 : 1 << findLastSet(Bytes);
        unsigned Size2 = Bytes - Size1;
        SDValue Chain1 = memsetStore(DAG, DL, Chain, Dst, ByteVal, Size1,
                                     Align, DstPtrInfo);
        if (Size2 == 0)
          return Chain1;
        Dst = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
                          DAG.getConstant(Size1, DstVT));
        DstPtrInfo = DstPtrInfo.getWithOffset(Size1);
        SDValue Chain2 = memsetStore(DAG, DL, Chain, Dst, ByteVal, Size2,
                                     std::min(Align, Size1), DstPtrInfo);
        return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chain1, Chain2);
      }
    } else {
      // Handle one and two bytes using STC.
      if (Bytes <= 2) {
        SDValue Chain1 = DAG.getStore(Chain, DL, Byte, Dst, DstPtrInfo,
                                      false, false, Align);
        if (Bytes == 1)
          return Chain1;
        SDValue Dst2 = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
                                   DAG.getConstant(1, DstVT));
        SDValue Chain2 = DAG.getStore(Chain, DL, Byte, Dst2,
                                      DstPtrInfo.getWithOffset(1),
                                      false, false, 1);
        return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chain1, Chain2);
      }
    }
    assert(Bytes >= 2 && "Should have dealt with 0- and 1-byte cases already");
    if (Bytes <= 0x101) {
      // Copy the byte to the first location and then use MVC to copy
      // it to the rest.
      Chain = DAG.getStore(Chain, DL, Byte, Dst, DstPtrInfo,
                           false, false, Align);
      SDValue Dst2 = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
                                 DAG.getConstant(1, DstVT));
      return DAG.getNode(SystemZISD::MVC, DL, MVT::Other, Chain, Dst2, Dst,
                         DAG.getConstant(Bytes - 1, MVT::i32));
    }
  }
  return SDValue();
}

std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::
EmitTargetCodeForMemcmp(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
                        SDValue Src1, SDValue Src2, SDValue Size,
                        MachinePointerInfo Op1PtrInfo,
                        MachinePointerInfo Op2PtrInfo) const {
  if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
    uint64_t Bytes = CSize->getZExtValue();
    if (Bytes >= 1 && Bytes <= 0x100) {
      // A single CLC.
      SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Glue);
      Chain = DAG.getNode(SystemZISD::CLC, DL, VTs, Chain,
                          Src1, Src2, Size);
      SDValue Glue = Chain.getValue(1);
      // IPM inserts the CC value into bits 29 and 28, with 0 meaning "equal",
      // 1 meaning "greater" and 2 meaning "less".  Convert them into an
      // integer that is respectively equal, greater or less than 0.
      SDValue IPM = DAG.getNode(SystemZISD::IPM, DL, MVT::i32, Glue);
      SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, IPM,
                                DAG.getConstant(2, MVT::i32));
      SDValue SRA = DAG.getNode(ISD::SRA, DL, MVT::i32, SHL,
                                DAG.getConstant(30, MVT::i32));
      return std::make_pair(SRA, Chain);
    }
  }
  return std::make_pair(SDValue(), SDValue());
}