From 7ba9c60ddfdc114e75fd01018581953d00401993 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 4 Apr 2008 15:45:52 +0000 Subject: [PATCH] =?utf8?q?initial=20checkin=20of=20=C3=89toil=C3=A9=20runt?= =?utf8?q?ime=20support,=20patch=20by=20David=20Chisnall?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49215 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCEtoile.cpp | 241 +++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 lib/CodeGen/CGObjCEtoile.cpp diff --git a/lib/CodeGen/CGObjCEtoile.cpp b/lib/CodeGen/CGObjCEtoile.cpp new file mode 100644 index 0000000000..b92418a918 --- /dev/null +++ b/lib/CodeGen/CGObjCEtoile.cpp @@ -0,0 +1,241 @@ +//===------- CGObjCEtoile.cpp - Emit LLVM Code from ASTs for a Module --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides Objective-C code generation targetting the Etoile runtime. +// +//===----------------------------------------------------------------------===// + +#include +#include "CGObjCRuntime.h" +#include "llvm/Module.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/LLVMBuilder.h" +#include "llvm/ADT/SmallVector.h" + + +clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {} + +namespace { +class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime { +private: + llvm::Module &TheModule; + const llvm::Type *SelectorTy; + const llvm::PointerType *PtrToInt8Ty; + const llvm::Type *IMPTy; + const llvm::Type *IntTy; + const llvm::Type *PtrTy; + const llvm::Type *LongTy; + const llvm::Type *PtrToIntTy; + const llvm::Type *IdTy; + const llvm::Type *CallTy; + const llvm::Type *SlotTy; + const llvm::Type *LookupFunctionTy; +public: + CGObjCEtoile(llvm::Module &Mp, + const llvm::Type *LLVMIntType, + const llvm::Type *LLVMLongType); + virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder, + const llvm::Type *ReturnTy, + llvm::Value *Sender, + llvm::Value *Receiver, + llvm::Value *Selector, + llvm::Value** ArgV, + unsigned ArgC); + llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder, + llvm::Value *SelName, + llvm::Value *SelTypes); + virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy, + const llvm::Type *SelfTy, + const llvm::Type **ArgTy, + unsigned ArgC, + bool isVarArg); +}; +} // end anonymous namespace + +CGObjCEtoile::CGObjCEtoile(llvm::Module &M, + const llvm::Type *LLVMIntType, + const llvm::Type *LLVMLongType) : + TheModule(M), + IntTy(LLVMIntType), + LongTy(LLVMLongType) +{ + // C string type. Used in lots of places. + PtrToInt8Ty = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + // Get the selector Type. + SelectorTy = llvm::Type::Int32Ty; + PtrToIntTy = llvm::PointerType::getUnqual(IntTy); + PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + + // Object type + llvm::OpaqueType *OpaqueObjTy = llvm::OpaqueType::get(); + llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy); + IdTy = llvm::PointerType::getUnqual(llvm::StructType::get(OpaqueIdTy, 0)); + OpaqueObjTy->refineAbstractTypeTo(IdTy); + + // Call structure type. + llvm::OpaqueType *OpaqueSlotTy = llvm::OpaqueType::get(); + CallTy = llvm::StructType::get(llvm::PointerType::getUnqual(OpaqueSlotTy), + SelectorTy, + IdTy, + 0); + //CallTy = llvm::PointerType::getUnqual(CallTy); + + // IMP type + std::vector IMPArgs; + IMPArgs.push_back(IdTy); + IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy)); + IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); + + // Slot type + SlotTy = llvm::StructType::get(IntTy, + IMPTy, + PtrToInt8Ty, + PtrToInt8Ty, + llvm::Type::Int32Ty, + 0); + OpaqueSlotTy->refineAbstractTypeTo(SlotTy); + SlotTy = llvm::PointerType::getUnqual(SlotTy); + + // Lookup function type + std::vector LookupFunctionArgs; + LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy)); + LookupFunctionArgs.push_back(IdTy); + LookupFunctionArgs.push_back(SelectorTy); + LookupFunctionArgs.push_back(IdTy); + LookupFunctionTy = llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false); + LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy); + +} + +// Looks up the selector for the specified name / type pair. +llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder, + llvm::Value *SelName, + llvm::Value *SelTypes) +{ + // Look up the selector. + if(SelTypes == 0) { + SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty); + } + llvm::Constant *SelFunction = + TheModule.getOrInsertFunction("lookup_typed_selector", + SelectorTy, + PtrToInt8Ty, + PtrToInt8Ty, + 0); + llvm::SmallVector Args; + Args.push_back(SelName); + Args.push_back(SelTypes); + return Builder.CreateCall(SelFunction, Args.begin(), Args.end()); +} + +#define SET(structure, index, value) do {\ + llvm::Value *element_ptr = Builder.CreateStructGEP(structure, index);\ + Builder.CreateStore(value, element_ptr);} while(0) +// Generate code for a message send expression on the Etoile runtime. +// BIG FAT WARNING: Much of this code will need factoring out later. +llvm::Value *CGObjCEtoile::generateMessageSend(llvm::LLVMFoldingBuilder &Builder, + const llvm::Type *ReturnTy, + llvm::Value *Sender, + llvm::Value *Receiver, + llvm::Value *Selector, + llvm::Value** ArgV, + unsigned ArgC) { + // FIXME: Selectors should be statically cached, not looked up on every call. + llvm::Value *cmd = getSelector(Builder, Selector, 0); + // TODO: [Polymorphic] inline caching + + // Get the lookup function for this object: + llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty); + llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty, + false, + llvm::GlobalValue::ExternalLinkage, + 0, + "lookup_offset", + &TheModule); + FunctionOffset = Builder.CreateLoad(FunctionOffset); + llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset); + llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy); + + // TODO: Remove this when the caller is providing sensible sender info + if(Sender == 0) { + Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy); + } + Receiver = Builder.CreateBitCast(Receiver, IdTy); + llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy); + Builder.CreateStore(Receiver, ReceiverAddr); + // Look up the method implementation. + llvm::SmallVector LookupArgs; + LookupArgs.push_back(ReceiverAddr); + LookupArgs.push_back(Receiver); + LookupArgs.push_back(cmd); + LookupArgs.push_back(Sender); + llvm::Value *Slot = Builder.CreateCall(Lookup, + LookupArgs.begin(), + LookupArgs.end()); + + // Create the call structure + llvm::Value *Call = Builder.CreateAlloca(CallTy); + SET(Call, 0, Slot); + SET(Call, 1, cmd); + SET(Call, 2, Sender); + + // Get the IMP from the slot and call it + // TODO: Property load / store optimisations + llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1); + // If the return type of the IMP is wrong, cast it so it isn't. + if(ReturnTy != IdTy) { + std::vector IMPArgs; + IMPArgs.push_back(IdTy); + IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy)); + llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true); + IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy)); + } + llvm::SmallVector Args; + Args.push_back(Receiver); + Args.push_back(Call); + Args.insert(Args.end(), ArgV, ArgV+ArgC); + return Builder.CreateCall(IMP, Args.begin(), Args.end()); +} + +llvm::Function *CGObjCEtoile::MethodPreamble( + const llvm::Type *ReturnTy, + const llvm::Type *SelfTy, + const llvm::Type **ArgTy, + unsigned ArgC, + bool isVarArg) { + std::vector Args; + //Args.push_back(SelfTy); + Args.push_back(IdTy); + Args.push_back(llvm::PointerType::getUnqual(CallTy)); + for (unsigned i=0; i