Coverage Report

Created: 2023-10-30 17:15

/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/andersen/ConstraintCollect.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "parcoach/andersen/Andersen.h"
2
3
#include "llvm/ADT/STLExtras.h"
4
#include "llvm/Analysis/ValueTracking.h"
5
#include "llvm/IR/Constants.h"
6
#include "llvm/IR/InstIterator.h"
7
#include "llvm/IR/Instructions.h"
8
#include "llvm/IR/Module.h"
9
#include "llvm/IR/PatternMatch.h"
10
#include "llvm/Support/Debug.h"
11
#include "llvm/Support/raw_ostream.h"
12
13
#define DEBUG_TYPE "hello"
14
15
using namespace llvm;
16
17
// CollectConstraints - This stage scans the program, adding a constraint to the
18
// Constraints list for each instruction in the program that induces a
19
// constraint, and setting up the initial points-to graph.
20
21
1.76k
void Andersen::collectConstraints(Module const &M) {
22
  // First, the universal ptr points to universal obj, and the universal obj
23
  // points to itself
24
1.76k
  constraints.emplace_back(AndersConstraint::ADDR_OF,
25
1.76k
                           nodeFactory.getUniversalPtrNode(),
26
1.76k
                           nodeFactory.getUniversalObjNode());
27
1.76k
  constraints.emplace_back(AndersConstraint::STORE,
28
1.76k
                           nodeFactory.getUniversalObjNode(),
29
1.76k
                           nodeFactory.getUniversalObjNode());
30
31
  // Next, the null pointer points to the null object.
32
1.76k
  constraints.emplace_back(AndersConstraint::ADDR_OF,
33
1.76k
                           nodeFactory.getNullPtrNode(),
34
1.76k
                           nodeFactory.getNullObjectNode());
35
36
  // Next, add any constraints on global variables. Associate the address of the
37
  // global object as pointing to the memory for the global: &G = <G memory>
38
1.76k
  collectConstraintsForGlobals(M);
39
40
  // Here is a notable points before we proceed:
41
  // For functions with non-local linkage type, theoretically we should not
42
  // trust anything that get passed to it or get returned by it. However,
43
  // precision will be seriously hurt if we do that because if we do not run a
44
  // -internalize pass before the -anders pass, almost every function is marked
45
  // external. We'll just assume that even external linkage will not ruin the
46
  // analysis result first
47
48
19.8k
  for (auto const &f : M) {
49
19.8k
    if (f.isDeclaration() || f.isIntrinsic())
50
18.0k
      continue;
51
52
    // Scan the function body
53
    // A visitor pattern might help modularity, but it needs more boilerplate
54
    // codes to set up, and it breaks down the main logic into pieces
55
56
    // First, create a value node for each instruction with pointer type. It is
57
    // necessary to do the job here rather than on-the-fly because an
58
    // instruction may refer to the value node definied before it (e.g. phi
59
    // nodes)
60
191k
    for (const_inst_iterator itr = inst_begin(f), ite = inst_end(f); itr != ite;
61
189k
         ++itr) {
62
189k
      auto inst = &*itr.getInstructionIterator();
63
189k
      if (inst->getType()->isPointerTy())
64
58.5k
        nodeFactory.createValueNode(inst);
65
189k
    }
66
67
    // Now, collect constraint for each relevant instruction
68
191k
    for (const_inst_iterator itr = inst_begin(f), ite = inst_end(f); itr != ite;
69
189k
         ++itr) {
70
189k
      auto inst = &*itr.getInstructionIterator();
71
189k
      collectConstraintsForInstruction(inst);
72
189k
    }
73
1.85k
  }
74
1.76k
}
75
76
1.76k
void Andersen::collectConstraintsForGlobals(Module const &M) {
77
  // Create a pointer and an object for each global variable
78
11.5k
  for (auto const &globalVal : M.globals()) {
79
11.5k
    NodeIndex gVal = nodeFactory.createValueNode(&globalVal);
80
11.5k
    NodeIndex gObj = nodeFactory.createObjectNode(&globalVal);
81
11.5k
    constraints.emplace_back(AndersConstraint::ADDR_OF, gVal, gObj);
82
11.5k
  }
83
84
  // Functions and function pointers are also considered global
85
19.8k
  for (auto const &f : M) {
86
    // If f is an addr-taken function, create a pointer and an object for it
87
19.8k
    if (f.hasAddressTaken()) {
88
9
      NodeIndex fVal = nodeFactory.createValueNode(&f);
89
9
      NodeIndex fObj = nodeFactory.createObjectNode(&f);
90
9
      constraints.emplace_back(AndersConstraint::ADDR_OF, fVal, fObj);
91
9
    }
92
93
19.8k
    if (f.isDeclaration() || f.isIntrinsic())
94
18.0k
      continue;
95
96
    // Create return node
97
1.85k
    if (f.getFunctionType()->getReturnType()->isPointerTy()) {
98
0
      nodeFactory.createReturnNode(&f);
99
0
    }
100
101
    // Create vararg node
102
1.85k
    if (f.getFunctionType()->isVarArg())
103
0
      nodeFactory.createVarargNode(&f);
104
105
    // Add nodes for all formal arguments.
106
1.85k
    for (Function::const_arg_iterator itr = f.arg_begin(), ite = f.arg_end();
107
5.56k
         itr != ite; ++itr) {
108
3.71k
      if (isa<PointerType>(itr->getType()))
109
1.92k
        nodeFactory.createValueNode(&*itr);
110
3.71k
    }
111
1.85k
  }
112
113
  // Init globals here since an initializer may refer to a global var/func below
114
  // it
115
11.5k
  for (auto const &globalVal : M.globals()) {
116
11.5k
    NodeIndex gObj = nodeFactory.getObjectNodeFor(&globalVal);
117
11.5k
    assert(gObj != AndersNodeFactory::InvalidIndex &&
118
11.5k
           "Cannot find global object!");
119
120
11.5k
    if (globalVal.hasDefinitiveInitializer()) {
121
5.23k
      addGlobalInitializerConstraints(gObj, globalVal.getInitializer());
122
6.35k
    } else {
123
      // If it doesn't have an initializer (i.e. it's defined in another
124
      // translation unit), it points to the universal set.
125
6.35k
      constraints.emplace_back(AndersConstraint::COPY, gObj,
126
6.35k
                               nodeFactory.getUniversalObjNode());
127
6.35k
    }
128
11.5k
  }
129
1.76k
}
130
131
void Andersen::addGlobalInitializerConstraints(NodeIndex objNode,
132
5.48k
                                               Constant const *c) {
133
  // errs() << "Called with node# = " << objNode << ", initializer = " << *c <<
134
  // "\n";
135
5.48k
  if (c->getType()->isSingleValueType()) {
136
250
    if (isa<PointerType>(c->getType())) {
137
50
      NodeIndex rhsNode = nodeFactory.getObjectNodeForConstant(c);
138
50
      assert(rhsNode != AndersNodeFactory::InvalidIndex &&
139
50
             "rhs node not found");
140
50
      constraints.emplace_back(AndersConstraint::ADDR_OF, objNode, rhsNode);
141
50
    }
142
5.23k
  } else if (c->isNullValue()) {
143
0
    constraints.emplace_back(AndersConstraint::COPY, objNode,
144
0
                             nodeFactory.getNullObjectNode());
145
5.23k
  } else if (!isa<UndefValue>(c)) {
146
    // Since we are doing field-insensitive analysis, all objects in the
147
    // array/struct are pointed-to by the 1st-field pointer
148
5.23k
    assert(isa<ConstantArray>(c) || isa<ConstantDataSequential>(c) ||
149
5.23k
           isa<ConstantStruct>(c));
150
151
5.48k
    for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i)
152
250
      addGlobalInitializerConstraints(objNode,
153
250
                                      cast<Constant>(c->getOperand(i)));
154
5.23k
  }
155
5.48k
}
156
157
189k
void Andersen::collectConstraintsForInstruction(Instruction const *inst) {
158
189k
  switch (inst->getOpcode()) {
159
28.1k
  case Instruction::Alloca: {
160
28.1k
    NodeIndex valNode = nodeFactory.getValueNodeFor(inst);
161
28.1k
    assert(valNode != AndersNodeFactory::InvalidIndex &&
162
28.1k
           "Failed to find alloca value node");
163
28.1k
    NodeIndex objNode = nodeFactory.createObjectNode(inst);
164
28.1k
    constraints.emplace_back(AndersConstraint::ADDR_OF, valNode, objNode);
165
28.1k
    break;
166
0
  }
167
54.2k
  case Instruction::Call:
168
54.2k
  case Instruction::Invoke: {
169
54.2k
    addConstraintForCall(*cast<CallBase>(inst));
170
171
54.2k
    break;
172
54.2k
  }
173
1.85k
  case Instruction::Ret: {
174
1.85k
    if (inst->getNumOperands() > 0 &&
175
1.85k
        inst->getOperand(0)->getType()->isPointerTy()) {
176
0
      NodeIndex retIndex =
177
0
          nodeFactory.getReturnNodeFor(inst->getParent()->getParent());
178
0
      assert(retIndex != AndersNodeFactory::InvalidIndex &&
179
0
             "Failed to find return node");
180
0
      NodeIndex valIndex = nodeFactory.getValueNodeFor(inst->getOperand(0));
181
0
      assert(valIndex != AndersNodeFactory::InvalidIndex &&
182
0
             "Failed to find return value node");
183
0
      constraints.emplace_back(AndersConstraint::COPY, retIndex, valIndex);
184
0
    }
185
1.85k
    break;
186
54.2k
  }
187
44.2k
  case Instruction::Load: {
188
44.2k
    if (inst->getType()->isPointerTy()) {
189
24.9k
      NodeIndex opIndex = nodeFactory.getValueNodeFor(inst->getOperand(0));
190
24.9k
      assert(opIndex != AndersNodeFactory::InvalidIndex &&
191
24.9k
             "Failed to find load operand node");
192
24.9k
      NodeIndex valIndex = nodeFactory.getValueNodeFor(inst);
193
24.9k
      assert(valIndex != AndersNodeFactory::InvalidIndex &&
194
24.9k
             "Failed to find load value node");
195
24.9k
      constraints.emplace_back(AndersConstraint::LOAD, valIndex, opIndex);
196
24.9k
    }
197
44.2k
    break;
198
54.2k
  }
199
26.6k
  case Instruction::Store: {
200
26.6k
    if (inst->getOperand(0)->getType()->isPointerTy()) {
201
10.8k
      NodeIndex srcIndex = nodeFactory.getValueNodeFor(inst->getOperand(0));
202
10.8k
      assert(srcIndex != AndersNodeFactory::InvalidIndex &&
203
10.8k
             "Failed to find store src node");
204
10.8k
      NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst->getOperand(1));
205
10.8k
      assert(dstIndex != AndersNodeFactory::InvalidIndex &&
206
10.8k
             "Failed to find store dst node");
207
10.8k
      constraints.emplace_back(AndersConstraint::STORE, dstIndex, srcIndex);
208
10.8k
    }
209
26.6k
    break;
210
54.2k
  }
211
2.81k
  case Instruction::GetElementPtr: {
212
2.81k
    assert(inst->getType()->isPointerTy());
213
214
    // P1 = getelementptr P2, ... --> <Copy/P1/P2>
215
2.81k
    NodeIndex srcIndex = nodeFactory.getValueNodeFor(inst->getOperand(0));
216
2.81k
    assert(srcIndex != AndersNodeFactory::InvalidIndex &&
217
2.81k
           "Failed to find gep src node");
218
2.81k
    NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst);
219
2.81k
    assert(dstIndex != AndersNodeFactory::InvalidIndex &&
220
2.81k
           "Failed to find gep dst node");
221
222
2.81k
    constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex);
223
224
2.81k
    break;
225
54.2k
  }
226
49
  case Instruction::PHI: {
227
49
    if (inst->getType()->isPointerTy()) {
228
0
      PHINode const *phiInst = cast<PHINode>(inst);
229
0
      NodeIndex dstIndex = nodeFactory.getValueNodeFor(phiInst);
230
0
      assert(dstIndex != AndersNodeFactory::InvalidIndex &&
231
0
             "Failed to find phi dst node");
232
0
      for (unsigned i = 0, e = phiInst->getNumIncomingValues(); i != e; ++i) {
233
0
        NodeIndex srcIndex =
234
0
            nodeFactory.getValueNodeFor(phiInst->getIncomingValue(i));
235
0
        assert(srcIndex != AndersNodeFactory::InvalidIndex &&
236
0
               "Failed to find phi src node");
237
0
        constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex);
238
0
      }
239
0
    }
240
49
    break;
241
54.2k
  }
242
0
  case Instruction::AddrSpaceCast:
243
0
  case Instruction::BitCast: {
244
0
    if (inst->getType()->isPointerTy()) {
245
0
      NodeIndex srcIndex = nodeFactory.getValueNodeFor(inst->getOperand(0));
246
0
      assert(srcIndex != AndersNodeFactory::InvalidIndex &&
247
0
             "Failed to find bitcast src node");
248
0
      NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst);
249
0
      assert(dstIndex != AndersNodeFactory::InvalidIndex &&
250
0
             "Failed to find bitcast dst node");
251
0
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex);
252
0
    }
253
0
    break;
254
0
  }
255
0
  case Instruction::IntToPtr: {
256
0
    assert(inst->getType()->isPointerTy());
257
258
    // Get the node index for dst
259
0
    NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst);
260
0
    assert(dstIndex != AndersNodeFactory::InvalidIndex &&
261
0
           "Failed to find inttoptr dst node");
262
263
    // We use pattern matching to look for a matching ptrtoint
264
0
    Value *op = inst->getOperand(0);
265
266
    // Pointer copy: Y = inttoptr (ptrtoint X)
267
0
    Value *srcValue = nullptr;
268
0
    if (PatternMatch::match(
269
0
            op, PatternMatch::m_PtrToInt(PatternMatch::m_Value(srcValue)))) {
270
0
      NodeIndex srcIndex = nodeFactory.getValueNodeFor(srcValue);
271
0
      assert(srcIndex != AndersNodeFactory::InvalidIndex &&
272
0
             "Failed to find inttoptr src node");
273
0
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex);
274
0
      break;
275
0
    }
276
277
    // Pointer arithmetic: Y = inttoptr (ptrtoint (X) + offset)
278
0
    if (PatternMatch::match(
279
0
            op, PatternMatch::m_Add(
280
0
                    PatternMatch::m_PtrToInt(PatternMatch::m_Value(srcValue)),
281
0
                    PatternMatch::m_Value()))) {
282
0
      NodeIndex srcIndex = nodeFactory.getValueNodeFor(srcValue);
283
0
      assert(srcIndex != AndersNodeFactory::InvalidIndex &&
284
0
             "Failed to find inttoptr src node");
285
0
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex);
286
0
      break;
287
0
    }
288
289
    // Otherwise, we really don't know what dst points to
290
0
    constraints.emplace_back(AndersConstraint::COPY, dstIndex,
291
0
                             nodeFactory.getUniversalPtrNode());
292
293
0
    break;
294
0
  }
295
5
  case Instruction::Select: {
296
5
    if (inst->getType()->isPointerTy()) {
297
3
      NodeIndex srcIndex1 = nodeFactory.getValueNodeFor(inst->getOperand(1));
298
3
      assert(srcIndex1 != AndersNodeFactory::InvalidIndex &&
299
3
             "Failed to find select src node 1");
300
3
      NodeIndex srcIndex2 = nodeFactory.getValueNodeFor(inst->getOperand(2));
301
3
      assert(srcIndex2 != AndersNodeFactory::InvalidIndex &&
302
3
             "Failed to find select src node 2");
303
3
      NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst);
304
3
      assert(dstIndex != AndersNodeFactory::InvalidIndex &&
305
3
             "Failed to find select dst node");
306
3
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex1);
307
3
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, srcIndex2);
308
3
    }
309
5
    break;
310
0
  }
311
0
  case Instruction::VAArg: {
312
0
    if (inst->getType()->isPointerTy()) {
313
0
      NodeIndex dstIndex = nodeFactory.getValueNodeFor(inst);
314
0
      assert(dstIndex != AndersNodeFactory::InvalidIndex &&
315
0
             "Failed to find va_arg dst node");
316
0
      NodeIndex vaIndex =
317
0
          nodeFactory.getVarargNodeFor(inst->getParent()->getParent());
318
0
      assert(vaIndex != AndersNodeFactory::InvalidIndex &&
319
0
             "Failed to find vararg node");
320
0
      constraints.emplace_back(AndersConstraint::COPY, dstIndex, vaIndex);
321
0
    }
322
0
    break;
323
0
  }
324
0
  case Instruction::ExtractValue:
325
0
  case Instruction::InsertValue: {
326
0
    if (!inst->getType()->isPointerTy())
327
0
      break;
328
0
  }
329
  // We have no intention to support exception-handling in the near future
330
0
  case Instruction::LandingPad:
331
0
  case Instruction::Resume:
332
  // Atomic instructions can be modeled by their non-atomic counterparts. To be
333
  // supported
334
0
  case Instruction::AtomicRMW:
335
0
  case Instruction::AtomicCmpXchg: {
336
0
    errs() << *inst << "\n";
337
0
    llvm_unreachable("not implemented yet");
338
0
  }
339
31.5k
  default: {
340
31.5k
    if (inst->getType()->isPointerTy()) {
341
0
      errs() << *inst << "\n";
342
0
      llvm_unreachable("pointer-related inst not handled!");
343
0
    }
344
31.5k
    break;
345
31.5k
  }
346
189k
  }
347
189k
}
348
349
// There are two types of constraints to add for a function call:
350
// - ValueNode(callsite) = ReturnNode(call target)
351
// - ValueNode(formal arg) = ValueNode(actual arg)
352
54.2k
void Andersen::addConstraintForCall(CallBase const &CB) {
353
54.2k
  if (Function const *f = CB.getCalledFunction()) // Direct call
354
54.2k
  {
355
54.2k
    if (f->isDeclaration() || f->isIntrinsic()) // External library call
356
54.1k
    {
357
      // Handle libraries separately
358
54.1k
      if (addConstraintForExternalLibrary(CB, f))
359
10.2k
        return;
360
43.8k
      else // Unresolved library call: ruin everything!
361
43.8k
      {
362
        // DEBUG(errs() << "Unresolved ext function: " << f->getName() << "\n");
363
43.8k
        if (CB.getType()->isPointerTy()) {
364
50
          NodeIndex retIndex = nodeFactory.getValueNodeFor(&CB);
365
50
          assert(retIndex != AndersNodeFactory::InvalidIndex &&
366
50
                 "Failed to find ret node!");
367
50
          constraints.emplace_back(AndersConstraint::COPY, retIndex,
368
50
                                   nodeFactory.getUniversalPtrNode());
369
50
        }
370
181k
        for (auto itr = CB.arg_begin(), ite = CB.arg_end(); itr != ite; ++itr) {
371
137k
          Value *argVal = *itr;
372
137k
          if (argVal->getType()->isPointerTy()) {
373
47.5k
            NodeIndex argIndex = nodeFactory.getValueNodeFor(argVal);
374
47.5k
            assert(argIndex != AndersNodeFactory::InvalidIndex &&
375
47.5k
                   "Failed to find arg node!");
376
47.5k
            constraints.emplace_back(AndersConstraint::COPY, argIndex,
377
47.5k
                                     nodeFactory.getUniversalPtrNode());
378
47.5k
          }
379
137k
        }
380
43.8k
      }
381
54.1k
    } else // Non-external function call
382
60
    {
383
60
      if (CB.getType()->isPointerTy()) {
384
0
        NodeIndex retIndex = nodeFactory.getValueNodeFor(&CB);
385
0
        assert(retIndex != AndersNodeFactory::InvalidIndex &&
386
0
               "Failed to find ret node!");
387
        // errs() << f->getName() << "\n";
388
0
        NodeIndex fRetIndex = nodeFactory.getReturnNodeFor(f);
389
0
        assert(fRetIndex != AndersNodeFactory::InvalidIndex &&
390
0
               "Failed to find function ret node!");
391
0
        constraints.emplace_back(AndersConstraint::COPY, retIndex, fRetIndex);
392
0
      }
393
      // The argument constraints
394
60
      addArgumentConstraintForCall(CB, f);
395
60
    }
396
54.2k
  } else // Indirect call
397
3
  {
398
    // We do the simplest thing here: just assume the returned value can be
399
    // anything :)
400
3
    if (CB.getType()->isPointerTy()) {
401
1
      NodeIndex retIndex = nodeFactory.getValueNodeFor(&CB);
402
1
      assert(retIndex != AndersNodeFactory::InvalidIndex &&
403
1
             "Failed to find ret node!");
404
1
      constraints.emplace_back(AndersConstraint::COPY, retIndex,
405
1
                               nodeFactory.getUniversalPtrNode());
406
1
    }
407
408
    // For argument constraints, first search through all addr-taken functions:
409
    // any function that takes can take as many variables is a potential
410
    // candidate
411
3
    Module const *M = CB.getParent()->getParent()->getParent();
412
28
    for (auto const &f : *M) {
413
28
      NodeIndex funPtrIndex = nodeFactory.getValueNodeFor(&f);
414
28
      if (funPtrIndex == AndersNodeFactory::InvalidIndex)
415
        // Not an addr-taken function
416
22
        continue;
417
418
6
      if (!f.getFunctionType()->isVarArg() && f.arg_size() != CB.arg_size())
419
        // #arg mismatch
420
0
        continue;
421
422
6
      if (f.isDeclaration() || f.isIntrinsic()) // External library call
423
2
      {
424
2
        if (addConstraintForExternalLibrary(CB, &f))
425
1
          continue;
426
1
        else {
427
          // Pollute everything
428
4
          for (auto itr = CB.arg_begin(), ite = CB.arg_end(); itr != ite;
429
3
               ++itr) {
430
3
            Value *argVal = *itr;
431
432
3
            if (argVal->getType()->isPointerTy()) {
433
3
              NodeIndex argIndex = nodeFactory.getValueNodeFor(argVal);
434
3
              assert(argIndex != AndersNodeFactory::InvalidIndex &&
435
3
                     "Failed to find arg node!");
436
3
              constraints.emplace_back(AndersConstraint::COPY, argIndex,
437
3
                                       nodeFactory.getUniversalPtrNode());
438
3
            }
439
3
          }
440
1
        }
441
2
      } else
442
4
        addArgumentConstraintForCall(CB, &f);
443
6
    }
444
3
  }
445
54.2k
}
446
447
void Andersen::addArgumentConstraintForCall(CallBase const &CB,
448
64
                                            Function const *f) {
449
64
  auto fItr = f->arg_begin();
450
64
  auto aItr = CB.arg_begin();
451
164
  while (fItr != f->arg_end() && aItr != CB.arg_end()) {
452
100
    Argument const *formal = &*fItr;
453
100
    Value const *actual = *aItr;
454
455
100
    if (formal->getType()->isPointerTy()) {
456
88
      NodeIndex fIndex = nodeFactory.getValueNodeFor(formal);
457
88
      assert(fIndex != AndersNodeFactory::InvalidIndex &&
458
88
             "Failed to find formal arg node!");
459
88
      if (actual->getType()->isPointerTy()) {
460
88
        NodeIndex aIndex = nodeFactory.getValueNodeFor(actual);
461
88
        assert(aIndex != AndersNodeFactory::InvalidIndex &&
462
88
               "Failed to find actual arg node!");
463
88
        constraints.emplace_back(AndersConstraint::COPY, fIndex, aIndex);
464
88
      } else
465
0
        constraints.emplace_back(AndersConstraint::COPY, fIndex,
466
0
                                 nodeFactory.getUniversalPtrNode());
467
88
    }
468
469
100
    ++fItr, ++aItr;
470
100
  }
471
472
  // Copy all pointers passed through the varargs section to the varargs node
473
64
  if (f->getFunctionType()->isVarArg()) {
474
0
    while (aItr != CB.arg_end()) {
475
0
      Value const *actual = *aItr;
476
0
      if (actual->getType()->isPointerTy()) {
477
0
        NodeIndex aIndex = nodeFactory.getValueNodeFor(actual);
478
0
        assert(aIndex != AndersNodeFactory::InvalidIndex &&
479
0
               "Failed to find actual arg node!");
480
0
        NodeIndex vaIndex = nodeFactory.getVarargNodeFor(f);
481
0
        assert(vaIndex != AndersNodeFactory::InvalidIndex &&
482
0
               "Failed to find vararg node!");
483
0
        constraints.emplace_back(AndersConstraint::COPY, vaIndex, aIndex);
484
0
      }
485
486
0
      ++aItr;
487
0
    }
488
0
  }
489
64
}