LLVM API Documentation

AliasSetTracker.cpp

Go to the documentation of this file.
00001 //===- AliasSetTracker.cpp - Alias Sets Tracker implementation-------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements the AliasSetTracker and AliasSet classes.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "llvm/Analysis/AliasSetTracker.h"
00015 #include "llvm/Analysis/AliasAnalysis.h"
00016 #include "llvm/Instructions.h"
00017 #include "llvm/Pass.h"
00018 #include "llvm/Type.h"
00019 #include "llvm/Target/TargetData.h"
00020 #include "llvm/Assembly/Writer.h"
00021 #include "llvm/Support/Compiler.h"
00022 #include "llvm/Support/InstIterator.h"
00023 #include "llvm/Support/Streams.h"
00024 using namespace llvm;
00025 
00026 /// mergeSetIn - Merge the specified alias set into this alias set.
00027 ///
00028 void AliasSet::mergeSetIn(AliasSet &AS, AliasSetTracker &AST) {
00029   assert(!AS.Forward && "Alias set is already forwarding!");
00030   assert(!Forward && "This set is a forwarding set!!");
00031 
00032   // Update the alias and access types of this set...
00033   AccessTy |= AS.AccessTy;
00034   AliasTy  |= AS.AliasTy;
00035 
00036   if (AliasTy == MustAlias) {
00037     // Check that these two merged sets really are must aliases.  Since both
00038     // used to be must-alias sets, we can just check any pointer from each set
00039     // for aliasing.
00040     AliasAnalysis &AA = AST.getAliasAnalysis();
00041     HashNodePair *L = getSomePointer();
00042     HashNodePair *R = AS.getSomePointer();
00043 
00044     // If the pointers are not a must-alias pair, this set becomes a may alias.
00045     if (AA.alias(L->first, L->second.getSize(), R->first, R->second.getSize())
00046         != AliasAnalysis::MustAlias)
00047       AliasTy = MayAlias;
00048   }
00049 
00050   if (CallSites.empty()) {            // Merge call sites...
00051     if (!AS.CallSites.empty())
00052       std::swap(CallSites, AS.CallSites);
00053   } else if (!AS.CallSites.empty()) {
00054     CallSites.insert(CallSites.end(), AS.CallSites.begin(), AS.CallSites.end());
00055     AS.CallSites.clear();
00056   }
00057 
00058   AS.Forward = this;  // Forward across AS now...
00059   addRef();           // AS is now pointing to us...
00060 
00061   // Merge the list of constituent pointers...
00062   if (AS.PtrList) {
00063     *PtrListEnd = AS.PtrList;
00064     AS.PtrList->second.setPrevInList(PtrListEnd);
00065     PtrListEnd = AS.PtrListEnd;
00066 
00067     AS.PtrList = 0;
00068     AS.PtrListEnd = &AS.PtrList;
00069     assert(*AS.PtrListEnd == 0 && "End of list is not null?");
00070   }
00071 }
00072 
00073 void AliasSetTracker::removeAliasSet(AliasSet *AS) {
00074   if (AliasSet *Fwd = AS->Forward) {
00075     Fwd->dropRef(*this);
00076     AS->Forward = 0;
00077   }
00078   AliasSets.erase(AS);
00079 }
00080 
00081 void AliasSet::removeFromTracker(AliasSetTracker &AST) {
00082   assert(RefCount == 0 && "Cannot remove non-dead alias set from tracker!");
00083   AST.removeAliasSet(this);
00084 }
00085 
00086 void AliasSet::addPointer(AliasSetTracker &AST, HashNodePair &Entry,
00087                           unsigned Size, bool KnownMustAlias) {
00088   assert(!Entry.second.hasAliasSet() && "Entry already in set!");
00089 
00090   // Check to see if we have to downgrade to _may_ alias.
00091   if (isMustAlias() && !KnownMustAlias)
00092     if (HashNodePair *P = getSomePointer()) {
00093       AliasAnalysis &AA = AST.getAliasAnalysis();
00094       AliasAnalysis::AliasResult Result =
00095         AA.alias(P->first, P->second.getSize(), Entry.first, Size);
00096       if (Result == AliasAnalysis::MayAlias)
00097         AliasTy = MayAlias;
00098       else                  // First entry of must alias must have maximum size!
00099         P->second.updateSize(Size);
00100       assert(Result != AliasAnalysis::NoAlias && "Cannot be part of must set!");
00101     }
00102 
00103   Entry.second.setAliasSet(this);
00104   Entry.second.updateSize(Size);
00105 
00106   // Add it to the end of the list...
00107   assert(*PtrListEnd == 0 && "End of list is not null?");
00108   *PtrListEnd = &Entry;
00109   PtrListEnd = Entry.second.setPrevInList(PtrListEnd);
00110   assert(*PtrListEnd == 0 && "End of list is not null?");
00111   addRef();               // Entry points to alias set...
00112 }
00113 
00114 void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) {
00115   CallSites.push_back(CS);
00116 
00117   AliasAnalysis::ModRefBehavior Behavior = AA.getModRefBehavior(CS);
00118   if (Behavior == AliasAnalysis::DoesNotAccessMemory)
00119     return;
00120   else if (Behavior == AliasAnalysis::OnlyReadsMemory) {
00121     AliasTy = MayAlias;
00122     AccessTy |= Refs;
00123     return;
00124   }
00125 
00126   // FIXME: This should use mod/ref information to make this not suck so bad
00127   AliasTy = MayAlias;
00128   AccessTy = ModRef;
00129 }
00130 
00131 /// aliasesPointer - Return true if the specified pointer "may" (or must)
00132 /// alias one of the members in the set.
00133 ///
00134 bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size,
00135                               AliasAnalysis &AA) const {
00136   if (AliasTy == MustAlias) {
00137     assert(CallSites.empty() && "Illegal must alias set!");
00138 
00139     // If this is a set of MustAliases, only check to see if the pointer aliases
00140     // SOME value in the set...
00141     HashNodePair *SomePtr = getSomePointer();
00142     assert(SomePtr && "Empty must-alias set??");
00143     return AA.alias(SomePtr->first, SomePtr->second.getSize(), Ptr, Size);
00144   }
00145 
00146   // If this is a may-alias set, we have to check all of the pointers in the set
00147   // to be sure it doesn't alias the set...
00148   for (iterator I = begin(), E = end(); I != E; ++I)
00149     if (AA.alias(Ptr, Size, I.getPointer(), I.getSize()))
00150       return true;
00151 
00152   // Check the call sites list and invoke list...
00153   if (!CallSites.empty()) {
00154     if (AA.hasNoModRefInfoForCalls())
00155       return true;
00156 
00157     for (unsigned i = 0, e = CallSites.size(); i != e; ++i)
00158       if (AA.getModRefInfo(CallSites[i], const_cast<Value*>(Ptr), Size)
00159                    != AliasAnalysis::NoModRef)
00160         return true;
00161   }
00162 
00163   return false;
00164 }
00165 
00166 bool AliasSet::aliasesCallSite(CallSite CS, AliasAnalysis &AA) const {
00167   if (AA.doesNotAccessMemory(CS))
00168     return false;
00169 
00170   if (AA.hasNoModRefInfoForCalls())
00171     return true;
00172 
00173   for (unsigned i = 0, e = CallSites.size(); i != e; ++i)
00174     if (AA.getModRefInfo(CallSites[i], CS) != AliasAnalysis::NoModRef ||
00175         AA.getModRefInfo(CS, CallSites[i]) != AliasAnalysis::NoModRef)
00176       return true;
00177 
00178   for (iterator I = begin(), E = end(); I != E; ++I)
00179     if (AA.getModRefInfo(CS, I.getPointer(), I.getSize()) !=
00180            AliasAnalysis::NoModRef)
00181       return true;
00182 
00183   return false;
00184 }
00185 
00186 
00187 /// findAliasSetForPointer - Given a pointer, find the one alias set to put the
00188 /// instruction referring to the pointer into.  If there are multiple alias sets
00189 /// that may alias the pointer, merge them together and return the unified set.
00190 ///
00191 AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr,
00192                                                   unsigned Size) {
00193   AliasSet *FoundSet = 0;
00194   for (iterator I = begin(), E = end(); I != E; ++I)
00195     if (!I->Forward && I->aliasesPointer(Ptr, Size, AA)) {
00196       if (FoundSet == 0) {  // If this is the first alias set ptr can go into.
00197         FoundSet = I;       // Remember it.
00198       } else {              // Otherwise, we must merge the sets.
00199         FoundSet->mergeSetIn(*I, *this);     // Merge in contents.
00200       }
00201     }
00202 
00203   return FoundSet;
00204 }
00205 
00206 /// containsPointer - Return true if the specified location is represented by
00207 /// this alias set, false otherwise.  This does not modify the AST object or
00208 /// alias sets.
00209 bool AliasSetTracker::containsPointer(Value *Ptr, unsigned Size) const {
00210   for (const_iterator I = begin(), E = end(); I != E; ++I)
00211     if (!I->Forward && I->aliasesPointer(Ptr, Size, AA))
00212       return true;
00213   return false;
00214 }
00215 
00216 
00217 
00218 AliasSet *AliasSetTracker::findAliasSetForCallSite(CallSite CS) {
00219   AliasSet *FoundSet = 0;
00220   for (iterator I = begin(), E = end(); I != E; ++I)
00221     if (!I->Forward && I->aliasesCallSite(CS, AA)) {
00222       if (FoundSet == 0) {  // If this is the first alias set ptr can go into.
00223         FoundSet = I;       // Remember it.
00224       } else if (!I->Forward) {     // Otherwise, we must merge the sets.
00225         FoundSet->mergeSetIn(*I, *this);     // Merge in contents.
00226       }
00227     }
00228 
00229   return FoundSet;
00230 }
00231 
00232 
00233 
00234 
00235 /// getAliasSetForPointer - Return the alias set that the specified pointer
00236 /// lives in...
00237 AliasSet &AliasSetTracker::getAliasSetForPointer(Value *Pointer, unsigned Size,
00238                                                  bool *New) {
00239   AliasSet::HashNodePair &Entry = getEntryFor(Pointer);
00240 
00241   // Check to see if the pointer is already known...
00242   if (Entry.second.hasAliasSet()) {
00243     Entry.second.updateSize(Size);
00244     // Return the set!
00245     return *Entry.second.getAliasSet(*this)->getForwardedTarget(*this);
00246   } else if (AliasSet *AS = findAliasSetForPointer(Pointer, Size)) {
00247     // Add it to the alias set it aliases...
00248     AS->addPointer(*this, Entry, Size);
00249     return *AS;
00250   } else {
00251     if (New) *New = true;
00252     // Otherwise create a new alias set to hold the loaded pointer...
00253     AliasSets.push_back(new AliasSet());
00254     AliasSets.back().addPointer(*this, Entry, Size);
00255     return AliasSets.back();
00256   }
00257 }
00258 
00259 bool AliasSetTracker::add(Value *Ptr, unsigned Size) {
00260   bool NewPtr;
00261   addPointer(Ptr, Size, AliasSet::NoModRef, NewPtr);
00262   return NewPtr;
00263 }
00264 
00265 
00266 bool AliasSetTracker::add(LoadInst *LI) {
00267   bool NewPtr;
00268   AliasSet &AS = addPointer(LI->getOperand(0),
00269                             AA.getTargetData().getTypeStoreSize(LI->getType()),
00270                             AliasSet::Refs, NewPtr);
00271   if (LI->isVolatile()) AS.setVolatile();
00272   return NewPtr;
00273 }
00274 
00275 bool AliasSetTracker::add(StoreInst *SI) {
00276   bool NewPtr;
00277   Value *Val = SI->getOperand(0);
00278   AliasSet &AS = addPointer(SI->getOperand(1),
00279                             AA.getTargetData().getTypeStoreSize(Val->getType()),
00280                             AliasSet::Mods, NewPtr);
00281   if (SI->isVolatile()) AS.setVolatile();
00282   return NewPtr;
00283 }
00284 
00285 bool AliasSetTracker::add(FreeInst *FI) {
00286   bool NewPtr;
00287   addPointer(FI->getOperand(0), ~0, AliasSet::Mods, NewPtr);
00288   return NewPtr;
00289 }
00290 
00291 bool AliasSetTracker::add(VAArgInst *VAAI) {
00292   bool NewPtr;
00293   addPointer(VAAI->getOperand(0), ~0, AliasSet::ModRef, NewPtr);
00294   return NewPtr;
00295 }
00296 
00297 
00298 bool AliasSetTracker::add(CallSite CS) {
00299   if (AA.doesNotAccessMemory(CS))
00300     return true; // doesn't alias anything
00301 
00302   AliasSet *AS = findAliasSetForCallSite(CS);
00303   if (!AS) {
00304     AliasSets.push_back(new AliasSet());
00305     AS = &AliasSets.back();
00306     AS->addCallSite(CS, AA);
00307     return true;
00308   } else {
00309     AS->addCallSite(CS, AA);
00310     return false;
00311   }
00312 }
00313 
00314 bool AliasSetTracker::add(Instruction *I) {
00315   // Dispatch to one of the other add methods...
00316   if (LoadInst *LI = dyn_cast<LoadInst>(I))
00317     return add(LI);
00318   else if (StoreInst *SI = dyn_cast<StoreInst>(I))
00319     return add(SI);
00320   else if (CallInst *CI = dyn_cast<CallInst>(I))
00321     return add(CI);
00322   else if (InvokeInst *II = dyn_cast<InvokeInst>(I))
00323     return add(II);
00324   else if (FreeInst *FI = dyn_cast<FreeInst>(I))
00325     return add(FI);
00326   else if (VAArgInst *VAAI = dyn_cast<VAArgInst>(I))
00327     return add(VAAI);
00328   return true;
00329 }
00330 
00331 void AliasSetTracker::add(BasicBlock &BB) {
00332   for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
00333     add(I);
00334 }
00335 
00336 void AliasSetTracker::add(const AliasSetTracker &AST) {
00337   assert(&AA == &AST.AA &&
00338          "Merging AliasSetTracker objects with different Alias Analyses!");
00339 
00340   // Loop over all of the alias sets in AST, adding the pointers contained
00341   // therein into the current alias sets.  This can cause alias sets to be
00342   // merged together in the current AST.
00343   for (const_iterator I = AST.begin(), E = AST.end(); I != E; ++I)
00344     if (!I->Forward) {   // Ignore forwarding alias sets
00345       AliasSet &AS = const_cast<AliasSet&>(*I);
00346 
00347       // If there are any call sites in the alias set, add them to this AST.
00348       for (unsigned i = 0, e = AS.CallSites.size(); i != e; ++i)
00349         add(AS.CallSites[i]);
00350 
00351       // Loop over all of the pointers in this alias set...
00352       AliasSet::iterator I = AS.begin(), E = AS.end();
00353       bool X;
00354       for (; I != E; ++I) {
00355         AliasSet &NewAS = addPointer(I.getPointer(), I.getSize(),
00356                                      (AliasSet::AccessType)AS.AccessTy, X);
00357         if (AS.isVolatile()) NewAS.setVolatile();
00358       }
00359     }
00360 }
00361 
00362 /// remove - Remove the specified (potentially non-empty) alias set from the
00363 /// tracker.
00364 void AliasSetTracker::remove(AliasSet &AS) {
00365   // Drop all call sites.
00366   AS.CallSites.clear();
00367   
00368   // Clear the alias set.
00369   unsigned NumRefs = 0;
00370   while (!AS.empty()) {
00371     AliasSet::HashNodePair *P = AS.PtrList;
00372     
00373     // Unlink from the list of values.
00374     P->second.removeFromList();
00375     
00376     // Remember how many references need to be dropped.
00377     ++NumRefs;
00378 
00379     // Finally, remove the entry.
00380     Value *Remove = P->first;   // Take a copy because it is invalid to pass
00381     PointerMap.erase(Remove);   // a reference to the data being erased.
00382   }
00383   
00384   // Stop using the alias set, removing it.
00385   AS.RefCount -= NumRefs;
00386   if (AS.RefCount == 0)
00387     AS.removeFromTracker(*this);
00388 }
00389 
00390 bool AliasSetTracker::remove(Value *Ptr, unsigned Size) {
00391   AliasSet *AS = findAliasSetForPointer(Ptr, Size);
00392   if (!AS) return false;
00393   remove(*AS);
00394   return true;
00395 }
00396 
00397 bool AliasSetTracker::remove(LoadInst *LI) {
00398   unsigned Size = AA.getTargetData().getTypeStoreSize(LI->getType());
00399   AliasSet *AS = findAliasSetForPointer(LI->getOperand(0), Size);
00400   if (!AS) return false;
00401   remove(*AS);
00402   return true;
00403 }
00404 
00405 bool AliasSetTracker::remove(StoreInst *SI) {
00406   unsigned Size =
00407     AA.getTargetData().getTypeStoreSize(SI->getOperand(0)->getType());
00408   AliasSet *AS = findAliasSetForPointer(SI->getOperand(1), Size);
00409   if (!AS) return false;
00410   remove(*AS);
00411   return true;
00412 }
00413 
00414 bool AliasSetTracker::remove(FreeInst *FI) {
00415   AliasSet *AS = findAliasSetForPointer(FI->getOperand(0), ~0);
00416   if (!AS) return false;
00417   remove(*AS);
00418   return true;
00419 }
00420 
00421 bool AliasSetTracker::remove(VAArgInst *VAAI) {
00422   AliasSet *AS = findAliasSetForPointer(VAAI->getOperand(0), ~0);
00423   if (!AS) return false;
00424   remove(*AS);
00425   return true;
00426 }
00427 
00428 bool AliasSetTracker::remove(CallSite CS) {
00429   if (AA.doesNotAccessMemory(CS))
00430     return false; // doesn't alias anything
00431 
00432   AliasSet *AS = findAliasSetForCallSite(CS);
00433   if (!AS) return false;
00434   remove(*AS);
00435   return true;
00436 }
00437 
00438 bool AliasSetTracker::remove(Instruction *I) {
00439   // Dispatch to one of the other remove methods...
00440   if (LoadInst *LI = dyn_cast<LoadInst>(I))
00441     return remove(LI);
00442   else if (StoreInst *SI = dyn_cast<StoreInst>(I))
00443     return remove(SI);
00444   else if (CallInst *CI = dyn_cast<CallInst>(I))
00445     return remove(CI);
00446   else if (FreeInst *FI = dyn_cast<FreeInst>(I))
00447     return remove(FI);
00448   else if (VAArgInst *VAAI = dyn_cast<VAArgInst>(I))
00449     return remove(VAAI);
00450   return true;
00451 }
00452 
00453 
00454 // deleteValue method - This method is used to remove a pointer value from the
00455 // AliasSetTracker entirely.  It should be used when an instruction is deleted
00456 // from the program to update the AST.  If you don't use this, you would have
00457 // dangling pointers to deleted instructions.
00458 //
00459 void AliasSetTracker::deleteValue(Value *PtrVal) {
00460   // Notify the alias analysis implementation that this value is gone.
00461   AA.deleteValue(PtrVal);
00462 
00463   // If this is a call instruction, remove the callsite from the appropriate
00464   // AliasSet.
00465   CallSite CS = CallSite::get(PtrVal);
00466   if (CS.getInstruction())
00467     if (!AA.doesNotAccessMemory(CS))
00468       if (AliasSet *AS = findAliasSetForCallSite(CS))
00469         AS->removeCallSite(CS);
00470 
00471   // First, look up the PointerRec for this pointer.
00472   hash_map<Value*, AliasSet::PointerRec>::iterator I = PointerMap.find(PtrVal);
00473   if (I == PointerMap.end()) return;  // Noop
00474 
00475   // If we found one, remove the pointer from the alias set it is in.
00476   AliasSet::HashNodePair &PtrValEnt = *I;
00477   AliasSet *AS = PtrValEnt.second.getAliasSet(*this);
00478 
00479   // Unlink from the list of values...
00480   PtrValEnt.second.removeFromList();
00481   // Stop using the alias set
00482   AS->dropRef(*this);
00483   PointerMap.erase(I);
00484 }
00485 
00486 // copyValue - This method should be used whenever a preexisting value in the
00487 // program is copied or cloned, introducing a new value.  Note that it is ok for
00488 // clients that use this method to introduce the same value multiple times: if
00489 // the tracker already knows about a value, it will ignore the request.
00490 //
00491 void AliasSetTracker::copyValue(Value *From, Value *To) {
00492   // Notify the alias analysis implementation that this value is copied.
00493   AA.copyValue(From, To);
00494 
00495   // First, look up the PointerRec for this pointer.
00496   hash_map<Value*, AliasSet::PointerRec>::iterator I = PointerMap.find(From);
00497   if (I == PointerMap.end() || !I->second.hasAliasSet())
00498     return;  // Noop
00499 
00500   AliasSet::HashNodePair &Entry = getEntryFor(To);
00501   if (Entry.second.hasAliasSet()) return;    // Already in the tracker!
00502 
00503   // Add it to the alias set it aliases...
00504   AliasSet *AS = I->second.getAliasSet(*this);
00505   AS->addPointer(*this, Entry, I->second.getSize(), true);
00506 }
00507 
00508 
00509 
00510 //===----------------------------------------------------------------------===//
00511 //               AliasSet/AliasSetTracker Printing Support
00512 //===----------------------------------------------------------------------===//
00513 
00514 void AliasSet::print(std::ostream &OS) const {
00515   OS << "  AliasSet[" << (void*)this << "," << RefCount << "] ";
00516   OS << (AliasTy == MustAlias ? "must" : "may") << " alias, ";
00517   switch (AccessTy) {
00518   case NoModRef: OS << "No access "; break;
00519   case Refs    : OS << "Ref       "; break;
00520   case Mods    : OS << "Mod       "; break;
00521   case ModRef  : OS << "Mod/Ref   "; break;
00522   default: assert(0 && "Bad value for AccessTy!");
00523   }
00524   if (isVolatile()) OS << "[volatile] ";
00525   if (Forward)
00526     OS << " forwarding to " << (void*)Forward;
00527 
00528 
00529   if (!empty()) {
00530     OS << "Pointers: ";
00531     for (iterator I = begin(), E = end(); I != E; ++I) {
00532       if (I != begin()) OS << ", ";
00533       WriteAsOperand(OS << "(", I.getPointer());
00534       OS << ", " << I.getSize() << ")";
00535     }
00536   }
00537   if (!CallSites.empty()) {
00538     OS << "\n    " << CallSites.size() << " Call Sites: ";
00539     for (unsigned i = 0, e = CallSites.size(); i != e; ++i) {
00540       if (i) OS << ", ";
00541       WriteAsOperand(OS, CallSites[i].getCalledValue());
00542     }
00543   }
00544   OS << "\n";
00545 }
00546 
00547 void AliasSetTracker::print(std::ostream &OS) const {
00548   OS << "Alias Set Tracker: " << AliasSets.size() << " alias sets for "
00549      << PointerMap.size() << " pointer values.\n";
00550   for (const_iterator I = begin(), E = end(); I != E; ++I)
00551     I->print(OS);
00552   OS << "\n";
00553 }
00554 
00555 void AliasSet::dump() const { print (cerr); }
00556 void AliasSetTracker::dump() const { print(cerr); }
00557 
00558 //===----------------------------------------------------------------------===//
00559 //                            AliasSetPrinter Pass
00560 //===----------------------------------------------------------------------===//
00561 
00562 namespace {
00563   class VISIBILITY_HIDDEN AliasSetPrinter : public FunctionPass {
00564     AliasSetTracker *Tracker;
00565   public:
00566     static char ID; // Pass identification, replacement for typeid
00567     AliasSetPrinter() : FunctionPass(&ID) {}
00568 
00569     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00570       AU.setPreservesAll();
00571       AU.addRequired<AliasAnalysis>();
00572     }
00573 
00574     virtual bool runOnFunction(Function &F) {
00575       Tracker = new AliasSetTracker(getAnalysis<AliasAnalysis>());
00576 
00577       for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
00578         Tracker->add(&*I);
00579       Tracker->print(cerr);
00580       delete Tracker;
00581       return false;
00582     }
00583   };
00584 }
00585 
00586 char AliasSetPrinter::ID = 0;
00587 static RegisterPass<AliasSetPrinter>
00588 X("print-alias-sets", "Alias Set Printer", false, true);



This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.