Andrew Kaylor | 2d6d585 | 2012-10-04 20:29:44 +0000 | [diff] [blame] | 1 | //===- MCJITTestBase.h - Common base class for MCJIT Unit tests ----------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This class implements common functionality required by the MCJIT unit tests, |
| 11 | // as well as logic to skip tests on unsupported architectures and operating |
| 12 | // systems. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | |
| 17 | #ifndef MCJIT_TEST_BASE_H |
| 18 | #define MCJIT_TEST_BASE_H |
| 19 | |
| 20 | #include "llvm/ADT/Triple.h" |
| 21 | #include "llvm/ADT/SmallVector.h" |
| 22 | #include "llvm/Config/config.h" |
| 23 | #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| 24 | #include "llvm/Function.h" |
| 25 | #include "llvm/IRBuilder.h" |
| 26 | #include "llvm/LLVMContext.h" |
| 27 | #include "llvm/Module.h" |
| 28 | #include "llvm/Support/CodeGen.h" |
| 29 | #include "llvm/Support/Host.h" |
| 30 | #include "llvm/Support/TargetSelect.h" |
| 31 | #include "llvm/TypeBuilder.h" |
| 32 | |
| 33 | #include "SectionMemoryManager.h" |
| 34 | |
| 35 | // Used to skip tests on unsupported architectures and operating systems. |
| 36 | // To skip a test, add this macro at the top of a test-case in a suite that |
| 37 | // inherits from MCJITTestBase. See MCJITTest.cpp for examples. |
| 38 | #define SKIP_UNSUPPORTED_PLATFORM \ |
| 39 | do \ |
| 40 | if (!ArchSupportsMCJIT() || !OSSupportsMCJIT()) \ |
| 41 | return; \ |
| 42 | while(0); |
| 43 | |
| 44 | namespace llvm { |
| 45 | |
| 46 | class MCJITTestBase { |
| 47 | protected: |
| 48 | |
| 49 | MCJITTestBase() |
| 50 | : OptLevel(CodeGenOpt::None) |
| 51 | , RelocModel(Reloc::Default) |
| 52 | , CodeModel(CodeModel::Default) |
| 53 | , MArch("") |
| 54 | , Builder(Context) |
| 55 | , MM(new SectionMemoryManager) |
| 56 | , HostTriple(LLVM_HOSTTRIPLE) |
| 57 | { |
| 58 | InitializeNativeTarget(); |
| 59 | InitializeNativeTargetAsmPrinter(); |
| 60 | |
| 61 | #ifdef LLVM_ON_WIN32 |
| 62 | // On Windows, generate ELF objects by specifying "-elf" in triple |
| 63 | HostTriple += "-elf"; |
| 64 | #endif // LLVM_ON_WIN32 |
| 65 | HostTriple = Triple::normalize(HostTriple); |
| 66 | |
| 67 | // The architectures below are known to be compatible with MCJIT as they |
| 68 | // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be |
| 69 | // kept in sync. |
| 70 | SupportedArchs.push_back(Triple::arm); |
| 71 | SupportedArchs.push_back(Triple::mips); |
| 72 | SupportedArchs.push_back(Triple::x86); |
| 73 | SupportedArchs.push_back(Triple::x86_64); |
| 74 | |
| 75 | // The operating systems below are known to be incompatible with MCJIT as |
| 76 | // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and |
| 77 | // should be kept in sync. |
| 78 | UnsupportedOSs.push_back(Triple::Cygwin); |
| 79 | UnsupportedOSs.push_back(Triple::Darwin); |
| 80 | } |
| 81 | |
| 82 | /// Returns true if the host architecture is known to support MCJIT |
| 83 | bool ArchSupportsMCJIT() { |
| 84 | Triple Host(HostTriple); |
| 85 | if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch()) |
| 86 | == SupportedArchs.end()) { |
| 87 | return false; |
| 88 | } |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | /// Returns true if the host OS is known to support MCJIT |
| 93 | bool OSSupportsMCJIT() { |
| 94 | Triple Host(HostTriple); |
| 95 | if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS()) |
| 96 | == UnsupportedOSs.end()) { |
| 97 | return true; |
| 98 | } |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | Module *createEmptyModule(StringRef Name) { |
| 103 | Module * M = new Module(Name, Context); |
| 104 | M->setTargetTriple(Triple::normalize(HostTriple)); |
| 105 | return M; |
| 106 | } |
| 107 | |
| 108 | template<typename FuncType> |
| 109 | Function *startFunction(Module *M, StringRef Name) { |
| 110 | Function *Result = Function::Create( |
| 111 | TypeBuilder<FuncType, false>::get(Context), |
| 112 | GlobalValue::ExternalLinkage, Name, M); |
| 113 | |
| 114 | BasicBlock *BB = BasicBlock::Create(Context, Name, Result); |
| 115 | Builder.SetInsertPoint(BB); |
| 116 | |
| 117 | return Result; |
| 118 | } |
| 119 | |
| 120 | void endFunctionWithRet(Function *Func, Value *RetValue) { |
| 121 | Builder.CreateRet(RetValue); |
| 122 | } |
| 123 | |
| 124 | // Inserts a simple function that invokes Callee and takes the same arguments: |
| 125 | // int Caller(...) { return Callee(...); } |
| 126 | template<typename Signature> |
| 127 | Function *insertSimpleCallFunction(Module *M, Function *Callee) { |
| 128 | Function *Result = startFunction<Signature>(M, "caller"); |
| 129 | |
| 130 | SmallVector<Value*, 1> CallArgs; |
| 131 | |
| 132 | Function::arg_iterator arg_iter = Result->arg_begin(); |
| 133 | for(;arg_iter != Result->arg_end(); ++arg_iter) |
| 134 | CallArgs.push_back(arg_iter); |
| 135 | |
| 136 | Value *ReturnCode = Builder.CreateCall(Callee, CallArgs); |
| 137 | Builder.CreateRet(ReturnCode); |
| 138 | return Result; |
| 139 | } |
| 140 | |
| 141 | // Inserts a function named 'main' that returns a uint32_t: |
| 142 | // int32_t main() { return X; } |
| 143 | // where X is given by returnCode |
| 144 | Function *insertMainFunction(Module *M, uint32_t returnCode) { |
| 145 | Function *Result = startFunction<int32_t(void)>(M, "main"); |
| 146 | |
| 147 | Value *ReturnVal = ConstantInt::get(Context, APInt(32, returnCode)); |
| 148 | endFunctionWithRet(Result, ReturnVal); |
| 149 | |
| 150 | return Result; |
| 151 | } |
| 152 | |
| 153 | // Inserts a function |
| 154 | // int32_t add(int32_t a, int32_t b) { return a + b; } |
| 155 | // in the current module and returns a pointer to it. |
| 156 | Function *insertAddFunction(Module *M, StringRef Name = "add") { |
| 157 | Function *Result = startFunction<int32_t(int32_t, int32_t)>(M, Name); |
| 158 | |
| 159 | Function::arg_iterator args = Result->arg_begin(); |
| 160 | Value *Arg1 = args; |
| 161 | Value *Arg2 = ++args; |
| 162 | Value *AddResult = Builder.CreateAdd(Arg1, Arg2); |
| 163 | |
| 164 | endFunctionWithRet(Result, AddResult); |
| 165 | |
| 166 | return Result; |
| 167 | } |
| 168 | |
| 169 | // Inserts an declaration to a function defined elsewhere |
| 170 | Function *insertExternalReferenceToFunction(Module *M, StringRef Name, |
| 171 | FunctionType *FuncTy) { |
| 172 | Function *Result = Function::Create(FuncTy, |
| 173 | GlobalValue::ExternalLinkage, |
| 174 | Name, M); |
| 175 | return Result; |
| 176 | } |
| 177 | |
| 178 | // Inserts an declaration to a function defined elsewhere |
| 179 | Function *insertExternalReferenceToFunction(Module *M, Function *Func) { |
| 180 | Function *Result = Function::Create(Func->getFunctionType(), |
| 181 | GlobalValue::AvailableExternallyLinkage, |
| 182 | Func->getName(), M); |
| 183 | return Result; |
| 184 | } |
| 185 | |
| 186 | // Inserts a global variable of type int32 |
| 187 | GlobalVariable *insertGlobalInt32(Module *M, |
| 188 | StringRef name, |
| 189 | int32_t InitialValue) { |
| 190 | Type *GlobalTy = TypeBuilder<types::i<32>, true>::get(Context); |
| 191 | Constant *IV = ConstantInt::get(Context, APInt(32, InitialValue)); |
| 192 | GlobalVariable *Global = new GlobalVariable(*M, |
| 193 | GlobalTy, |
| 194 | false, |
| 195 | GlobalValue::ExternalLinkage, |
| 196 | IV, |
| 197 | name); |
| 198 | return Global; |
| 199 | } |
| 200 | |
| 201 | void createJIT(Module *M) { |
| 202 | |
| 203 | // Due to the EngineBuilder constructor, it is required to have a Module |
| 204 | // in order to construct an ExecutionEngine (i.e. MCJIT) |
| 205 | assert(M != 0 && "a non-null Module must be provided to create MCJIT"); |
| 206 | |
| 207 | EngineBuilder EB(M); |
| 208 | std::string Error; |
| 209 | TheJIT.reset(EB.setEngineKind(EngineKind::JIT) |
| 210 | .setUseMCJIT(true) /* can this be folded into the EngineKind enum? */ |
| 211 | .setJITMemoryManager(MM) |
| 212 | .setErrorStr(&Error) |
| 213 | .setOptLevel(CodeGenOpt::None) |
| 214 | .setAllocateGVsWithCode(false) /*does this do anything?*/ |
| 215 | .setCodeModel(CodeModel::JITDefault) |
| 216 | .setRelocationModel(Reloc::Default) |
| 217 | .setMArch(MArch) |
| 218 | .setMCPU(sys::getHostCPUName()) |
| 219 | //.setMAttrs(MAttrs) |
| 220 | .create()); |
| 221 | // At this point, we cannot modify the module any more. |
| 222 | assert(TheJIT.get() != NULL && "error creating MCJIT with EngineBuilder"); |
| 223 | } |
| 224 | |
| 225 | LLVMContext Context; |
| 226 | CodeGenOpt::Level OptLevel; |
| 227 | Reloc::Model RelocModel; |
| 228 | CodeModel::Model CodeModel; |
| 229 | StringRef MArch; |
| 230 | SmallVector<std::string, 1> MAttrs; |
| 231 | OwningPtr<TargetMachine> TM; |
| 232 | OwningPtr<ExecutionEngine> TheJIT; |
| 233 | IRBuilder<> Builder; |
| 234 | JITMemoryManager *MM; |
| 235 | |
| 236 | std::string HostTriple; |
| 237 | SmallVector<Triple::ArchType, 4> SupportedArchs; |
| 238 | SmallVector<Triple::OSType, 4> UnsupportedOSs; |
| 239 | |
| 240 | OwningPtr<Module> M; |
| 241 | }; |
| 242 | |
| 243 | } // namespace llvm |
| 244 | |
| 245 | #endif // MCJIT_TEST_H |