File: BreakConstantGEPs.cpp

package info (click to toggle)
pocl 6.0-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 25,304 kB
  • sloc: lisp: 149,513; ansic: 103,778; cpp: 54,947; python: 1,513; sh: 949; ruby: 255; pascal: 226; tcl: 180; makefile: 173; java: 72; xml: 49
file content (363 lines) | stat: -rw-r--r-- 11,316 bytes parent folder | download | duplicates (2)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
//===- BreakConstantGEPs.cpp - Change constant GEPs into GEP instructions - --//
// 
// pocl note: This pass is taken from The SAFECode project with trivial modifications.
//            Automatic locals might cause constant GEPs which cause problems during 
//            converting the locals to kernel function arguments for thread safety.
//
//                          The SAFECode Compiler 
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This pass changes all GEP constant expressions into GEP instructions.  This
// permits the rest of SAFECode to put run-time checks on them if necessary.
//
//===----------------------------------------------------------------------===//

#include "CompilerWarnings.h"
IGNORE_COMPILER_WARNING("-Wmaybe-uninitialized")
#include <llvm/ADT/Twine.h>
POP_COMPILER_DIAGS
IGNORE_COMPILER_WARNING("-Wunused-parameter")
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/InstIterator.h"

#include "BreakConstantGEPs.h"
#include "LLVMUtils.h"
#include "Workgroup.h"
#include "WorkitemHandlerChooser.h"
POP_COMPILER_DIAGS

#include <iostream>
#include <map>
#include <utility>

#define DEBUG_TYPE "break-constgeps"

#define PASS_NAME "break-constgeps"
#define PASS_CLASS pocl::BreakConstantGEPs
#define PASS_DESC "Remove GEP Constant Expressions"

// Statistics
STATISTIC (GEPChanges,   "Number of Converted GEP Constant Expressions");
STATISTIC (TotalChanges, "Number of Converted Constant Expressions");

namespace pocl {

using namespace llvm;

static bool breakConstantGEPs(Function &F);

//
// Function: hasConstantGEP()
//
// Description:
//  This function determines whether the given value is a constant expression
//  that has a constant GEP expression embedded within it.
//
// Inputs:
//  V - The value to check.
//
// Return value:
//  NULL  - This value is not a constant expression with a constant expression
//          GEP within it.
//  ~NULL - A pointer to the value casted into a ConstantExpr is returned.
//
static ConstantExpr *
hasConstantGEP (Value * V) {
  if (ConstantExpr * CE = dyn_cast<ConstantExpr>(V)) {
    bool isGEPOrCast =
        CE->getOpcode() == Instruction::GetElementPtr ||
        CE->getOpcode() == Instruction::BitCast;

    isGEPOrCast |= CE->getOpcode() == Instruction::AddrSpaceCast;
    if (isGEPOrCast) {
      return CE;
    } else {
      for (unsigned index = 0; index < CE->getNumOperands(); ++index) {
        if (hasConstantGEP (CE->getOperand(index)))
          return CE;
      }
    }
  }

  return 0;
}

//
// Function: convertGEP()
//
// Description:
//  Convert a GEP constant expression into a GEP instruction.
//
// Inputs:
//  CE       - The GEP constant expression.
//  InsertPt - The instruction before which to insert the new GEP instruction.
//
// Return value:
//  A pointer to the new GEP instruction is returned.
//
static Instruction *
convertGEP (ConstantExpr * CE, Instruction * InsertPt) {
  //
  // Create iterators to the indices of the constant expression.
  //
  std::vector<Value *> Indices;
  for (unsigned index = 1; index < CE->getNumOperands(); ++index) {
    Indices.push_back (CE->getOperand (index));
  }

  //
  // Update the statistics.
  //
  ++GEPChanges;

  //
  // Make the new GEP instruction.
  //
  /* The first NULL is the Type. It is not used at all, just asserted 
   * against. And it asserts, no matter what is passed. Except NULL. 
   * Seems this API is still "fluctuation in progress"*/
  return (GetElementPtrInst::Create (NULL,
                                     CE->getOperand(0),
                                     Indices,
                                     CE->getName(),
                                     InsertPt));
}

//
// Function: convertExpression()
//
// Description:
//  Convert a constant expression into an instruction.  This routine does *not*
//  perform any recursion, so the resulting instruction may have constant
//  expression operands.
//
static Instruction *
convertExpression (ConstantExpr * CE, Instruction * InsertPt) {
  //
  // Convert this constant expression into a regular instruction.
  //
  Instruction * NewInst = 0;
  switch (CE->getOpcode()) {
    case Instruction::GetElementPtr: {
      NewInst = convertGEP (CE, InsertPt);
      break;
    }

    case Instruction::Add:
    case Instruction::Sub:
    case Instruction::Mul:
    case Instruction::UDiv:
    case Instruction::SDiv:
    case Instruction::FDiv:
    case Instruction::URem:
    case Instruction::SRem:
    case Instruction::FRem:
    case Instruction::Shl:
    case Instruction::LShr:
    case Instruction::AShr:
    case Instruction::And:
    case Instruction::Or:
    case Instruction::Xor: {
      Instruction::BinaryOps Op = (Instruction::BinaryOps)(CE->getOpcode());
      NewInst = BinaryOperator::Create (Op,
                                        CE->getOperand(0),
                                        CE->getOperand(1),
                                        CE->getName(),
                                        InsertPt);
      break;
    }

    case Instruction::Trunc:
    case Instruction::ZExt:
    case Instruction::SExt:
    case Instruction::FPToUI:
    case Instruction::FPToSI:
    case Instruction::UIToFP:
    case Instruction::SIToFP:
    case Instruction::FPTrunc:
    case Instruction::FPExt:
    case Instruction::PtrToInt:
    case Instruction::IntToPtr:
    case Instruction::AddrSpaceCast:
    case Instruction::BitCast: {
      Instruction::CastOps Op = (Instruction::CastOps)(CE->getOpcode());
      NewInst = CastInst::Create (Op,
                                  CE->getOperand(0),
                                  CE->getType(),
                                  CE->getName(),
                                  InsertPt);
      break;
    }

    case Instruction:: FCmp:
    case Instruction:: ICmp: {
      Instruction::OtherOps Op = (Instruction::OtherOps)(CE->getOpcode());
      NewInst = CmpInst::Create (Op,
                                 (llvm::CmpInst::Predicate)CE->getPredicate(),
                                 CE->getOperand(0),
                                 CE->getOperand(1),
                                 CE->getName(),
                                 InsertPt);
      break;
    }

    case Instruction:: Select:
      NewInst = SelectInst::Create (CE->getOperand(0),
                                    CE->getOperand(1),
                                    CE->getOperand(2),
                                    CE->getName(),
                                    InsertPt);
      break;

    case Instruction:: ExtractElement:
    case Instruction:: InsertElement:
    case Instruction:: ShuffleVector:
    case Instruction:: InsertValue:
    default:
      assert (0 && "Unhandled constant expression!\n");
      break;
  }

  //
  // Update the statistics.
  //
  ++TotalChanges;

  return NewInst;
}

//
// Method: runOnFunction()
//
// Description:
//  Entry point for this LLVM pass.
//
// Return value:
//  true  - The function was modified.
//  false - The function was not modified.
//
static bool breakConstantGEPs(Function &F) {

  if (!pocl::isKernelToProcess(F))
    return false;

  bool modified = false;

  // Worklist of values to check for constant GEP expressions
  std::vector<Instruction *> Worklist;

  //
  // Initialize the worklist by finding all instructions that have one or more
  // operands containing a constant GEP expression.
  //
  for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
    for (BasicBlock::iterator i = BB->begin(); i != BB->end(); ++i) {
      //
      // Scan through the operands of this instruction.  If it is a constant
      // expression GEP, insert an instruction GEP before the instruction.
      //
      Instruction * I = &*i;
      for (unsigned index = 0; index < I->getNumOperands(); ++index) {
        if (hasConstantGEP (I->getOperand(index))) {
          Worklist.push_back (I);
        }
      }
    }
  }

  //
  // Determine whether we will modify anything.
  //
  if (Worklist.size()) modified = true;

  //
  // While the worklist is not empty, take an item from it, convert the
  // operands into instructions if necessary, and determine if the newly
  // added instructions need to be processed as well.
  //
  while (Worklist.size()) {
    Instruction * I = Worklist.back();
    Worklist.pop_back();

    //
    // Scan through the operands of this instruction and convert each into an
    // instruction.  Note that this works a little differently for phi
    // instructions because the new instruction must be added to the
    // appropriate predecessor block.
    //
    if (PHINode * PHI = dyn_cast<PHINode>(I)) {
      for (unsigned index = 0; index < PHI->getNumIncomingValues(); ++index) {
        //
        // For PHI Nodes, if an operand is a constant expression with a GEP, we
        // want to insert the new instructions in the predecessor basic block.
        //
        // Note: It seems that it's possible for a phi to have the same
        // incoming basic block listed multiple times; this seems okay as long
        // the same value is listed for the incoming block.
        //
        Instruction * InsertPt = PHI->getIncomingBlock(index)->getTerminator();
        if (ConstantExpr * CE = hasConstantGEP (PHI->getIncomingValue(index))) {
          Instruction * NewInst = convertExpression (CE, InsertPt);
          for (unsigned i2 = index; i2 < PHI->getNumIncomingValues(); ++i2) {
            if ((PHI->getIncomingBlock (i2)) == PHI->getIncomingBlock (index))
              PHI->setIncomingValue (i2, NewInst);
          }
          Worklist.push_back (NewInst);
        }
      }
    } else {
      for (unsigned index = 0; index < I->getNumOperands(); ++index) {
        //
        // For other instructions, we want to insert instructions replacing
        // constant expressions immediently before the instruction using the
        // constant expression.
        //
        if (ConstantExpr * CE = hasConstantGEP (I->getOperand(index))) {
          Instruction * NewInst = convertExpression (CE, I);
          I->replaceUsesOfWith (CE, NewInst);
          Worklist.push_back (NewInst);
        }
      }
    }
  }

  return modified;
}

#if LLVM_MAJOR < MIN_LLVM_NEW_PASSMANAGER
char BreakConstantGEPs::ID = 0;

bool BreakConstantGEPs::runOnFunction(Function &F) {
  return breakConstantGEPs(F);
}

void BreakConstantGEPs::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
  AU.addPreserved<WorkitemHandlerChooser>();
  AU.setPreservesCFG();
}

REGISTER_OLD_FPASS(PASS_NAME, PASS_CLASS, PASS_DESC);

#else
llvm::PreservedAnalyses
BreakConstantGEPs::run(llvm::Function &F, llvm::FunctionAnalysisManager &AM) {
  PreservedAnalyses PAChanged = PreservedAnalyses::none();
  PAChanged.preserve<WorkitemHandlerChooser>();
  PAChanged.preserveSet<CFGAnalyses>();
  return breakConstantGEPs(F) ? PAChanged : PreservedAnalyses::all();
}

REGISTER_NEW_FPASS(PASS_NAME, PASS_CLASS, PASS_DESC)

#endif

} // namespace pocl