mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-04 05:17:07 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146440 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			134 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===-- AutoUpgrade.cpp - Implement auto-upgrade helper functions ---------===//
 | 
						|
//
 | 
						|
//                     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 auto-upgrade helper functions 
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/AutoUpgrade.h"
 | 
						|
#include "llvm/Constants.h"
 | 
						|
#include "llvm/Function.h"
 | 
						|
#include "llvm/Instruction.h"
 | 
						|
#include "llvm/LLVMContext.h"
 | 
						|
#include "llvm/Module.h"
 | 
						|
#include "llvm/IntrinsicInst.h"
 | 
						|
#include "llvm/ADT/DenseMap.h"
 | 
						|
#include "llvm/ADT/SmallPtrSet.h"
 | 
						|
#include "llvm/ADT/SmallVector.h"
 | 
						|
#include "llvm/Support/CallSite.h"
 | 
						|
#include "llvm/Support/CFG.h"
 | 
						|
#include "llvm/Support/ErrorHandling.h"
 | 
						|
#include "llvm/Support/IRBuilder.h"
 | 
						|
#include <cstring>
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
 | 
						|
static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
 | 
						|
  assert(F && "Illegal to upgrade a non-existent Function.");
 | 
						|
 | 
						|
  // Quickly eliminate it, if it's not a candidate.
 | 
						|
  StringRef Name = F->getName();
 | 
						|
  if (Name.size() <= 8 || !Name.startswith("llvm."))
 | 
						|
    return false;
 | 
						|
  Name = Name.substr(5); // Strip off "llvm."
 | 
						|
 | 
						|
  switch (Name[0]) {
 | 
						|
  default: break;
 | 
						|
  case 'c': {
 | 
						|
    if (Name.startswith("ctlz.") && F->arg_size() == 1) {
 | 
						|
      F->setName(Name + ".old");
 | 
						|
      NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz,
 | 
						|
                                        F->arg_begin()->getType());
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    if (Name.startswith("cttz.") && F->arg_size() == 1) {
 | 
						|
      F->setName(Name + ".old");
 | 
						|
      NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::cttz,
 | 
						|
                                        F->arg_begin()->getType());
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  //  This may not belong here. This function is effectively being overloaded 
 | 
						|
  //  to both detect an intrinsic which needs upgrading, and to provide the 
 | 
						|
  //  upgraded form of the intrinsic. We should perhaps have two separate 
 | 
						|
  //  functions for this.
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn) {
 | 
						|
  NewFn = 0;
 | 
						|
  bool Upgraded = UpgradeIntrinsicFunction1(F, NewFn);
 | 
						|
 | 
						|
  // Upgrade intrinsic attributes.  This does not change the function.
 | 
						|
  if (NewFn)
 | 
						|
    F = NewFn;
 | 
						|
  if (unsigned id = F->getIntrinsicID())
 | 
						|
    F->setAttributes(Intrinsic::getAttributes((Intrinsic::ID)id));
 | 
						|
  return Upgraded;
 | 
						|
}
 | 
						|
 | 
						|
bool llvm::UpgradeGlobalVariable(GlobalVariable *GV) {
 | 
						|
  // Nothing to do yet.
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// UpgradeIntrinsicCall - Upgrade a call to an old intrinsic to be a call the 
 | 
						|
// upgraded intrinsic. All argument and return casting must be provided in 
 | 
						|
// order to seamlessly integrate with existing context.
 | 
						|
void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) {
 | 
						|
  assert(CI->getCalledFunction() && "Intrinsic call is not direct?");
 | 
						|
  if (!NewFn) return;
 | 
						|
 | 
						|
  LLVMContext &C = CI->getContext();
 | 
						|
  IRBuilder<> Builder(C);
 | 
						|
  Builder.SetInsertPoint(CI->getParent(), CI);
 | 
						|
 | 
						|
  switch (NewFn->getIntrinsicID()) {
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Unknown function for CallInst upgrade.");
 | 
						|
 | 
						|
  case Intrinsic::ctlz:
 | 
						|
  case Intrinsic::cttz:
 | 
						|
    assert(CI->getNumArgOperands() == 1 &&
 | 
						|
           "Mismatch between function args and call args");
 | 
						|
    StringRef Name = CI->getName();
 | 
						|
    CI->setName(Name + ".old");
 | 
						|
    CI->replaceAllUsesWith(Builder.CreateCall2(NewFn, CI->getArgOperand(0),
 | 
						|
                                               Builder.getFalse(), Name));
 | 
						|
    CI->eraseFromParent();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// This tests each Function to determine if it needs upgrading. When we find 
 | 
						|
// one we are interested in, we then upgrade all calls to reflect the new 
 | 
						|
// function.
 | 
						|
void llvm::UpgradeCallsToIntrinsic(Function* F) {
 | 
						|
  assert(F && "Illegal attempt to upgrade a non-existent intrinsic.");
 | 
						|
 | 
						|
  // Upgrade the function and check if it is a totaly new function.
 | 
						|
  Function *NewFn;
 | 
						|
  if (UpgradeIntrinsicFunction(F, NewFn)) {
 | 
						|
    if (NewFn != F) {
 | 
						|
      // Replace all uses to the old function with the new one if necessary.
 | 
						|
      for (Value::use_iterator UI = F->use_begin(), UE = F->use_end();
 | 
						|
           UI != UE; ) {
 | 
						|
        if (CallInst *CI = dyn_cast<CallInst>(*UI++))
 | 
						|
          UpgradeIntrinsicCall(CI, NewFn);
 | 
						|
      }
 | 
						|
      // Remove old function, no longer used, from the module.
 | 
						|
      F->eraseFromParent();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 |