Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
Line
Count
Source (jump to first uncovered line)
1
//===----- RISCVMergeBaseOffset.cpp - Optimise address calculations  ------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Merge the offset of address calculation into the offset field
10
// of instructions in a global address lowering sequence. This pass transforms:
11
//   lui  vreg1, %hi(s)
12
//   addi vreg2, vreg1, %lo(s)
13
//   addi vreg3, verg2, Offset
14
//
15
//   Into:
16
//   lui  vreg1, %hi(s+Offset)
17
//   addi vreg2, vreg1, %lo(s+Offset)
18
//
19
// The transformation is carried out under certain conditions:
20
// 1) The offset field in the base of global address lowering sequence is zero.
21
// 2) The lowered global address has only one use.
22
//
23
// The offset field can be in a different form. This pass handles all of them.
24
//===----------------------------------------------------------------------===//
25
26
#include "RISCV.h"
27
#include "RISCVTargetMachine.h"
28
#include "llvm/CodeGen/Passes.h"
29
#include "llvm/Support/Debug.h"
30
#include "llvm/Support/TargetRegistry.h"
31
#include "llvm/Target/TargetOptions.h"
32
#include <set>
33
using namespace llvm;
34
35
#define DEBUG_TYPE "riscv-merge-base-offset"
36
3.68k
#define RISCV_MERGE_BASE_OFFSET_NAME "RISCV Merge Base Offset"
37
namespace {
38
39
struct RISCVMergeBaseOffsetOpt : public MachineFunctionPass {
40
  static char ID;
41
  const MachineFunction *MF;
42
  bool runOnMachineFunction(MachineFunction &Fn) override;
43
  bool detectLuiAddiGlobal(MachineInstr &LUI, MachineInstr *&ADDI);
44
45
  bool detectAndFoldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI);
46
  void foldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI, MachineInstr &Tail,
47
                  int64_t Offset);
48
  bool matchLargeOffset(MachineInstr &TailAdd, unsigned GSReg, int64_t &Offset);
49
329
  RISCVMergeBaseOffsetOpt() : MachineFunctionPass(ID) {}
50
51
329
  MachineFunctionProperties getRequiredProperties() const override {
52
329
    return MachineFunctionProperties().set(
53
329
        MachineFunctionProperties::Property::IsSSA);
54
329
  }
55
56
3.68k
  StringRef getPassName() const override {
57
3.68k
    return RISCV_MERGE_BASE_OFFSET_NAME;
58
3.68k
  }
59
60
private:
61
  MachineRegisterInfo *MRI;
62
  std::set<MachineInstr *> DeadInstrs;
63
};
64
} // end anonymous namespace
65
66
char RISCVMergeBaseOffsetOpt::ID = 0;
67
INITIALIZE_PASS(RISCVMergeBaseOffsetOpt, "riscv-merge-base-offset",
68
                RISCV_MERGE_BASE_OFFSET_NAME, false, false)
69
70
// Detect the pattern:
71
//   lui   vreg1, %hi(s)
72
//   addi  vreg2, vreg1, %lo(s)
73
//
74
//   Pattern only accepted if:
75
//     1) ADDI has only one use.
76
//     2) LUI has only one use; which is the ADDI.
77
//     3) Both ADDI and LUI have GlobalAddress type which indicates that these
78
//        are generated from global address lowering.
79
//     4) Offset value in the Global Address is 0.
80
bool RISCVMergeBaseOffsetOpt::detectLuiAddiGlobal(MachineInstr &HiLUI,
81
41.0k
                                                  MachineInstr *&LoADDI) {
82
41.0k
  if (HiLUI.getOpcode() != RISCV::LUI ||
83
41.0k
      
HiLUI.getOperand(1).getTargetFlags() != RISCVII::MO_HI751
||
84
41.0k
      
HiLUI.getOperand(1).getType() != MachineOperand::MO_GlobalAddress240
||
85
41.0k
      
HiLUI.getOperand(1).getOffset() != 0151
||
86
41.0k
      
!MRI->hasOneUse(HiLUI.getOperand(0).getReg())151
)
87
40.9k
    return false;
88
75
  unsigned HiLuiDestReg = HiLUI.getOperand(0).getReg();
89
75
  LoADDI = MRI->use_begin(HiLuiDestReg)->getParent();
90
75
  if (LoADDI->getOpcode() != RISCV::ADDI ||
91
75
      
LoADDI->getOperand(2).getTargetFlags() != RISCVII::MO_LO23
||
92
75
      
LoADDI->getOperand(2).getType() != MachineOperand::MO_GlobalAddress23
||
93
75
      
LoADDI->getOperand(2).getOffset() != 023
||
94
75
      
!MRI->hasOneUse(LoADDI->getOperand(0).getReg())23
)
95
55
    return false;
96
20
  return true;
97
20
}
98
99
// Update the offset in HiLUI and LoADDI instructions.
100
// Delete the tail instruction and update all the uses to use the
101
// output from LoADDI.
102
void RISCVMergeBaseOffsetOpt::foldOffset(MachineInstr &HiLUI,
103
                                         MachineInstr &LoADDI,
104
4
                                         MachineInstr &Tail, int64_t Offset) {
105
4
  // Put the offset back in HiLUI and the LoADDI
106
4
  HiLUI.getOperand(1).setOffset(Offset);
107
4
  LoADDI.getOperand(2).setOffset(Offset);
108
4
  // Delete the tail instruction.
109
4
  DeadInstrs.insert(&Tail);
110
4
  MRI->replaceRegWith(Tail.getOperand(0).getReg(),
111
4
                      LoADDI.getOperand(0).getReg());
112
4
  LLVM_DEBUG(dbgs() << "  Merged offset " << Offset << " into base.\n"
113
4
                    << "     " << HiLUI << "     " << LoADDI;);
114
4
}
115
116
// Detect patterns for large offsets that are passed into an ADD instruction.
117
//
118
//                     Base address lowering is of the form:
119
//                        HiLUI:  lui   vreg1, %hi(s)
120
//                       LoADDI:  addi  vreg2, vreg1, %lo(s)
121
//                       /                                  \
122
//                      /                                    \
123
//                     /                                      \
124
//                    /  The large offset can be of two forms: \
125
//  1) Offset that has non zero bits in lower      2) Offset that has non zero
126
//     12 bits and upper 20 bits                      bits in upper 20 bits only
127
//   OffseLUI: lui   vreg3, 4
128
// OffsetTail: addi  voff, vreg3, 188                OffsetTail: lui  voff, 128
129
//                    \                                        /
130
//                     \                                      /
131
//                      \                                    /
132
//                       \                                  /
133
//                         TailAdd: add  vreg4, vreg2, voff
134
bool RISCVMergeBaseOffsetOpt::matchLargeOffset(MachineInstr &TailAdd,
135
                                               unsigned GAReg,
136
3
                                               int64_t &Offset) {
137
3
  assert((TailAdd.getOpcode() == RISCV::ADD) && "Expected ADD instruction!");
138
3
  unsigned Rs = TailAdd.getOperand(1).getReg();
139
3
  unsigned Rt = TailAdd.getOperand(2).getReg();
140
3
  unsigned Reg = Rs == GAReg ? Rt : 
Rs0
;
141
3
142
3
  // Can't fold if the register has more than one use.
143
3
  if (!MRI->hasOneUse(Reg))
144
0
    return false;
145
3
  // This can point to an ADDI or a LUI:
146
3
  MachineInstr &OffsetTail = *MRI->getVRegDef(Reg);
147
3
  if (OffsetTail.getOpcode() == RISCV::ADDI) {
148
2
    // The offset value has non zero bits in both %hi and %lo parts.
149
2
    // Detect an ADDI that feeds from a LUI instruction.
150
2
    MachineOperand &AddiImmOp = OffsetTail.getOperand(2);
151
2
    if (AddiImmOp.getTargetFlags() != RISCVII::MO_None)
152
0
      return false;
153
2
    int64_t OffLo = AddiImmOp.getImm();
154
2
    MachineInstr &OffsetLui =
155
2
        *MRI->getVRegDef(OffsetTail.getOperand(1).getReg());
156
2
    MachineOperand &LuiImmOp = OffsetLui.getOperand(1);
157
2
    if (OffsetLui.getOpcode() != RISCV::LUI ||
158
2
        LuiImmOp.getTargetFlags() != RISCVII::MO_None ||
159
2
        !MRI->hasOneUse(OffsetLui.getOperand(0).getReg()))
160
0
      return false;
161
2
    int64_t OffHi = OffsetLui.getOperand(1).getImm();
162
2
    Offset = (OffHi << 12) + OffLo;
163
2
    LLVM_DEBUG(dbgs() << "  Offset Instrs: " << OffsetTail
164
2
                      << "                 " << OffsetLui);
165
2
    DeadInstrs.insert(&OffsetTail);
166
2
    DeadInstrs.insert(&OffsetLui);
167
2
    return true;
168
2
  } else 
if (1
OffsetTail.getOpcode() == RISCV::LUI1
) {
169
1
    // The offset value has all zero bits in the lower 12 bits. Only LUI
170
1
    // exists.
171
1
    LLVM_DEBUG(dbgs() << "  Offset Instr: " << OffsetTail);
172
1
    Offset = OffsetTail.getOperand(1).getImm() << 12;
173
1
    DeadInstrs.insert(&OffsetTail);
174
1
    return true;
175
1
  }
176
0
  return false;
177
0
}
178
179
bool RISCVMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &HiLUI,
180
20
                                                  MachineInstr &LoADDI) {
181
20
  unsigned DestReg = LoADDI.getOperand(0).getReg();
182
20
  assert(MRI->hasOneUse(DestReg) && "expected one use for LoADDI");
183
20
  // LoADDI has only one use.
184
20
  MachineInstr &Tail = *MRI->use_begin(DestReg)->getParent();
185
20
  switch (Tail.getOpcode()) {
186
20
  default:
187
14
    LLVM_DEBUG(dbgs() << "Don't know how to get offset from this instr:"
188
14
                      << Tail);
189
14
    return false;
190
20
  case RISCV::ADDI: {
191
1
    // Offset is simply an immediate operand.
192
1
    int64_t Offset = Tail.getOperand(2).getImm();
193
1
    LLVM_DEBUG(dbgs() << "  Offset Instr: " << Tail);
194
1
    foldOffset(HiLUI, LoADDI, Tail, Offset);
195
1
    return true;
196
20
  } 
break0
;
197
20
  case RISCV::ADD: {
198
3
    // The offset is too large to fit in the immediate field of ADDI.
199
3
    // This can be in two forms:
200
3
    // 1) LUI hi_Offset followed by:
201
3
    //    ADDI lo_offset
202
3
    //    This happens in case the offset has non zero bits in
203
3
    //    both hi 20 and lo 12 bits.
204
3
    // 2) LUI (offset20)
205
3
    //    This happens in case the lower 12 bits of the offset are zeros.
206
3
    int64_t Offset;
207
3
    if (!matchLargeOffset(Tail, DestReg, Offset))
208
0
      return false;
209
3
    foldOffset(HiLUI, LoADDI, Tail, Offset);
210
3
    return true;
211
3
  } 
break0
;
212
3
  case RISCV::LB:
213
2
  case RISCV::LH:
214
2
  case RISCV::LW:
215
2
  case RISCV::LBU:
216
2
  case RISCV::LHU:
217
2
  case RISCV::LWU:
218
2
  case RISCV::LD:
219
2
  case RISCV::FLW:
220
2
  case RISCV::FLD:
221
2
  case RISCV::SB:
222
2
  case RISCV::SH:
223
2
  case RISCV::SW:
224
2
  case RISCV::SD:
225
2
  case RISCV::FSW:
226
2
  case RISCV::FSD: {
227
2
    // Transforms the sequence:            Into:
228
2
    // HiLUI:  lui vreg1, %hi(foo)          --->  lui vreg1, %hi(foo+8)
229
2
    // LoADDI: addi vreg2, vreg1, %lo(foo)  --->  lw vreg3, lo(foo+8)(vreg1)
230
2
    // Tail:   lw vreg3, 8(vreg2)
231
2
    if (Tail.getOperand(1).isFI())
232
0
      return false;
233
2
    // Register defined by LoADDI should be used in the base part of the
234
2
    // load\store instruction. Otherwise, no folding possible.
235
2
    unsigned BaseAddrReg = Tail.getOperand(1).getReg();
236
2
    if (DestReg != BaseAddrReg)
237
0
      return false;
238
2
    MachineOperand &TailImmOp = Tail.getOperand(2);
239
2
    int64_t Offset = TailImmOp.getImm();
240
2
    // Update the offsets in global address lowering.
241
2
    HiLUI.getOperand(1).setOffset(Offset);
242
2
    // Update the immediate in the Tail instruction to add the offset.
243
2
    Tail.RemoveOperand(2);
244
2
    MachineOperand &ImmOp = LoADDI.getOperand(2);
245
2
    ImmOp.setOffset(Offset);
246
2
    Tail.addOperand(ImmOp);
247
2
    // Update the base reg in the Tail instruction to feed from LUI.
248
2
    // Output of HiLUI is only used in LoADDI, no need to use
249
2
    // MRI->replaceRegWith().
250
2
    Tail.getOperand(1).setReg(HiLUI.getOperand(0).getReg());
251
2
    DeadInstrs.insert(&LoADDI);
252
2
    return true;
253
2
  } 
break0
;
254
0
  }
255
0
  return false;
256
0
}
257
258
3.35k
bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
259
3.35k
  if (skipFunction(Fn.getFunction()))
260
3
    return false;
261
3.35k
262
3.35k
  DeadInstrs.clear();
263
3.35k
  MRI = &Fn.getRegInfo();
264
4.73k
  for (MachineBasicBlock &MBB : Fn) {
265
4.73k
    LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
266
41.0k
    for (MachineInstr &HiLUI : MBB) {
267
41.0k
      MachineInstr *LoADDI = nullptr;
268
41.0k
      if (!detectLuiAddiGlobal(HiLUI, LoADDI))
269
40.9k
        continue;
270
20
      LLVM_DEBUG(dbgs() << "  Found lowered global address with one use: "
271
20
                        << *LoADDI->getOperand(2).getGlobal() << "\n");
272
20
      // If the use count is only one, merge the offset
273
20
      detectAndFoldOffset(HiLUI, *LoADDI);
274
20
    }
275
4.73k
  }
276
3.35k
  // Delete dead instructions.
277
3.35k
  for (auto *MI : DeadInstrs)
278
11
    MI->eraseFromParent();
279
3.35k
  return true;
280
3.35k
}
281
282
/// Returns an instance of the Merge Base Offset Optimization pass.
283
329
FunctionPass *llvm::createRISCVMergeBaseOffsetOptPass() {
284
329
  return new RISCVMergeBaseOffsetOpt();
285
329
}