#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
-#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/SmallVector.h"
using namespace llvm;
namespace {
- class LowerGC : public FunctionPass {
+ class VISIBILITY_HIDDEN LowerGC : public FunctionPass {
/// GCRootInt, GCReadInt, GCWriteInt - The function prototypes for the
/// llvm.gcread/llvm.gcwrite/llvm.gcroot intrinsics.
Function *GCRootInt, *GCReadInt, *GCWriteInt;
/// GCRead/GCWrite - These are the functions provided by the garbage
/// collector for read/write barriers.
- Function *GCRead, *GCWrite;
+ Constant *GCRead, *GCWrite;
/// RootChain - This is the global linked-list that contains the chain of GC
/// roots.
/// had zero roots.
const Type *MainRootRecordType;
public:
- LowerGC() : GCRootInt(0), GCReadInt(0), GCWriteInt(0),
+ static char ID; // Pass identification, replacement for typeid
+ LowerGC() : FunctionPass((intptr_t)&ID),
+ GCRootInt(0), GCReadInt(0), GCWriteInt(0),
GCRead(0), GCWrite(0), RootChain(0), MainRootRecordType(0) {}
virtual bool doInitialization(Module &M);
virtual bool runOnFunction(Function &F);
const StructType *getRootRecordType(unsigned NumRoots);
};
- RegisterOpt<LowerGC>
+ char LowerGC::ID = 0;
+ RegisterPass<LowerGC>
X("lowergc", "Lower GC intrinsics, for GCless code generators");
}
MainRootRecordType ? (Type*)MainRootRecordType : (Type*)OpaqueType::get();
ST.clear();
ST.push_back(PointerType::get(RootListH)); // Prev pointer
- ST.push_back(Type::UIntTy); // NumElements in array
+ ST.push_back(Type::Int32Ty); // NumElements in array
ST.push_back(PairArrTy); // The pairs
StructType *RootList = StructType::get(ST);
if (MainRootRecordType)
/// doInitialization - If this module uses the GC intrinsics, find them now. If
/// not, this pass does not do anything.
bool LowerGC::doInitialization(Module &M) {
- GCRootInt = M.getNamedFunction("llvm.gcroot");
- GCReadInt = M.getNamedFunction("llvm.gcread");
- GCWriteInt = M.getNamedFunction("llvm.gcwrite");
+ GCRootInt = M.getFunction("llvm.gcroot");
+ GCReadInt = M.getFunction("llvm.gcread");
+ GCWriteInt = M.getFunction("llvm.gcwrite");
if (!GCRootInt && !GCReadInt && !GCWriteInt) return false;
- PointerType *VoidPtr = PointerType::get(Type::SByteTy);
+ PointerType *VoidPtr = PointerType::get(Type::Int8Ty);
PointerType *VoidPtrPtr = PointerType::get(VoidPtr);
// If the program is using read/write barriers, find the implementations of
// them from the GC runtime library.
if (GCReadInt) // Make: sbyte* %llvm_gc_read(sbyte**)
- GCRead = M.getOrInsertFunction("llvm_gc_read", VoidPtr, VoidPtr, VoidPtrPtr, 0);
+ GCRead = M.getOrInsertFunction("llvm_gc_read", VoidPtr, VoidPtr, VoidPtrPtr,
+ (Type *)0);
if (GCWriteInt) // Make: void %llvm_gc_write(sbyte*, sbyte**)
GCWrite = M.getOrInsertFunction("llvm_gc_write", Type::VoidTy,
- VoidPtr, VoidPtr, VoidPtrPtr, 0);
+ VoidPtr, VoidPtr, VoidPtrPtr, (Type *)0);
// If the program has GC roots, get or create the global root list.
if (GCRootInt) {
GlobalValue::LinkOnceLinkage,
Constant::getNullValue(PRLTy),
"llvm_gc_root_chain", &M);
- } else if (RootChain->hasExternalLinkage() && RootChain->isExternal()) {
+ } else if (RootChain->hasExternalLinkage() && RootChain->isDeclaration()) {
RootChain->setInitializer(Constant::getNullValue(PRLTy));
RootChain->setLinkage(GlobalValue::LinkOnceLinkage);
}
}
/// Coerce - If the specified operand number of the specified instruction does
-/// not have the specified type, insert a cast.
+/// not have the specified type, insert a cast. Note that this only uses BitCast
+/// because the types involved are all pointers.
static void Coerce(Instruction *I, unsigned OpNum, Type *Ty) {
if (I->getOperand(OpNum)->getType() != Ty) {
if (Constant *C = dyn_cast<Constant>(I->getOperand(OpNum)))
- I->setOperand(OpNum, ConstantExpr::getCast(C, Ty));
+ I->setOperand(OpNum, ConstantExpr::getBitCast(C, Ty));
else {
- CastInst *CI = new CastInst(I->getOperand(OpNum), Ty, "", I);
+ CastInst *CI = new BitCastInst(I->getOperand(OpNum), Ty, "", I);
I->setOperand(OpNum, CI);
}
}
// Quick exit for programs that are not using GC mechanisms.
if (!GCRootInt && !GCReadInt && !GCWriteInt) return false;
- PointerType *VoidPtr = PointerType::get(Type::SByteTy);
+ PointerType *VoidPtr = PointerType::get(Type::Int8Ty);
PointerType *VoidPtrPtr = PointerType::get(VoidPtr);
// If there are read/write barriers in the program, perform a quick pass over
CI->setOperand(0, GCRead);
} else {
// Create a whole new call to replace the old one.
- CallInst *NC = new CallInst(GCRead, CI->getOperand(1),
- CI->getOperand(2),
+
+ // It sure would be nice to pass op_begin()+1,
+ // op_begin()+2 but it runs into trouble with
+ // CallInst::init's &*iterator, which requires a
+ // conversion from Use* to Value*. The conversion
+ // from Use to Value * is not useful because the
+ // memory for Value * won't be contiguous.
+ Value* Args[] = {
+ CI->getOperand(1),
+ CI->getOperand(2)
+ };
+ CallInst *NC = new CallInst(GCRead, Args, Args + 2,
CI->getName(), CI);
- Value *NV = new CastInst(NC, CI->getType(), "", CI);
+ // These functions only deal with ptr type results so BitCast
+ // is the correct kind of cast (no-op cast).
+ Value *NV = new BitCastInst(NC, CI->getType(), "", CI);
CI->replaceAllUsesWith(NV);
BB->getInstList().erase(CI);
CI = NC;
}
}
- // Now that we made the replacement, inline expand the call if
- // possible, otherwise things will be too horribly expensive.
- InlineFunction(CI);
MadeChange = true;
}
}
BasicBlock::iterator IP = AI;
while (isa<AllocaInst>(IP)) ++IP;
- Constant *Zero = ConstantUInt::get(Type::UIntTy, 0);
- Constant *One = ConstantUInt::get(Type::UIntTy, 1);
+ Constant *Zero = ConstantInt::get(Type::Int32Ty, 0);
+ Constant *One = ConstantInt::get(Type::Int32Ty, 1);
+ Value *Idx[2] = { Zero, Zero };
+
// Get a pointer to the prev pointer.
- std::vector<Value*> Par;
- Par.push_back(Zero);
- Par.push_back(Zero);
- Value *PrevPtrPtr = new GetElementPtrInst(AI, Par, "prevptrptr", IP);
+ Value *PrevPtrPtr = new GetElementPtrInst(AI, Idx, Idx + 2,
+ "prevptrptr", IP);
// Load the previous pointer.
Value *PrevPtr = new LoadInst(RootChain, "prevptr", IP);
new StoreInst(PrevPtr, PrevPtrPtr, IP);
// Set the number of elements in this record.
- Par[1] = ConstantUInt::get(Type::UIntTy, 1);
- Value *NumEltsPtr = new GetElementPtrInst(AI, Par, "numeltsptr", IP);
- new StoreInst(ConstantUInt::get(Type::UIntTy, GCRoots.size()), NumEltsPtr,IP);
+ Idx[1] = One;
+ Value *NumEltsPtr = new GetElementPtrInst(AI, Idx, Idx + 2,
+ "numeltsptr", IP);
+ new StoreInst(ConstantInt::get(Type::Int32Ty, GCRoots.size()), NumEltsPtr,IP);
- Par[1] = ConstantUInt::get(Type::UIntTy, 2);
- Par.resize(4);
+ Value* Par[4];
+ Par[0] = Zero;
+ Par[1] = ConstantInt::get(Type::Int32Ty, 2);
const PointerType *PtrLocTy =
cast<PointerType>(GCRootInt->getFunctionType()->getParamType(0));
Constant *Null = ConstantPointerNull::get(PtrLocTy);
- // Initialize all of the gcroot records now, and eliminate them as we go.
+ // Initialize all of the gcroot records now.
for (unsigned i = 0, e = GCRoots.size(); i != e; ++i) {
// Initialize the meta-data pointer.
- Par[2] = ConstantUInt::get(Type::UIntTy, i);
+ Par[2] = ConstantInt::get(Type::Int32Ty, i);
Par[3] = One;
- Value *MetaDataPtr = new GetElementPtrInst(AI, Par, "MetaDataPtr", IP);
+ Value *MetaDataPtr = new GetElementPtrInst(AI, Par, Par + 4,
+ "MetaDataPtr", IP);
assert(isa<Constant>(GCRoots[i]->getOperand(2)) && "Must be a constant");
new StoreInst(GCRoots[i]->getOperand(2), MetaDataPtr, IP);
// Initialize the root pointer to null on entry to the function.
Par[3] = Zero;
- Value *RootPtrPtr = new GetElementPtrInst(AI, Par, "RootEntPtr", IP);
+ Value *RootPtrPtr = new GetElementPtrInst(AI, Par, Par + 4,
+ "RootEntPtr", IP);
new StoreInst(Null, RootPtrPtr, IP);
// Each occurrance of the llvm.gcroot intrinsic now turns into an
new StoreInst(Constant::getNullValue(PtrLocTy->getElementType()),
GCRoots[i]->getOperand(1), GCRoots[i]);
new StoreInst(GCRoots[i]->getOperand(1), RootPtrPtr, GCRoots[i]);
- GCRoots[i]->getParent()->getInstList().erase(GCRoots[i]);
}
// Now that the record is all initialized, store the pointer into the global
// pointer.
- Value *C = new CastInst(AI, PointerType::get(MainRootRecordType), "", IP);
+ Value *C = new BitCastInst(AI, PointerType::get(MainRootRecordType), "", IP);
new StoreInst(C, RootChain, IP);
+ // Eliminate all the gcroot records now.
+ for (unsigned i = 0, e = GCRoots.size(); i != e; ++i)
+ GCRoots[i]->getParent()->getInstList().erase(GCRoots[i]);
+
// On exit from the function we have to remove the entry from the GC root
// chain. Doing this is straight-forward for return and unwind instructions:
// just insert the appropriate copy.
NewBB->getInstList().remove(CI);
// Create a new invoke instruction.
+ std::vector<Value*> Args(CI->op_begin()+1, CI->op_end());
+
Value *II = new InvokeInst(CI->getCalledValue(), NewBB, Cleanup,
- std::vector<Value*>(CI->op_begin()+1,
- CI->op_end()),
- CI->getName(), CBB);
+ Args.begin(), Args.end(), CI->getName(), CBB);
CI->replaceAllUsesWith(II);
delete CI;
}