1 //=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/AST/ASTConsumer.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/Basic/TargetInfo.h" 13 #include "clang/CodeGen/ModuleBuilder.h" 14 #include "clang/Frontend/CompilerInstance.h" 15 #include "clang/Interpreter/Interpreter.h" 16 #include "clang/Lex/Preprocessor.h" 17 #include "clang/Parse/Parser.h" 18 #include "clang/Sema/Sema.h" 19 20 #include "llvm/ExecutionEngine/Orc/LLJIT.h" 21 #include "llvm/IR/LLVMContext.h" 22 #include "llvm/IR/Module.h" 23 #include "llvm/Support/MemoryBuffer.h" 24 #include "llvm/TargetParser/Host.h" 25 #include "llvm/TargetParser/Triple.h" 26 #include "gtest/gtest.h" 27 28 #include <memory> 29 30 #if defined(_AIX) || defined(__MVS__) 31 #define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT 32 #endif 33 34 using namespace llvm; 35 using namespace clang; 36 37 namespace { 38 39 // Incremental processing produces several modules, all using the same "main 40 // file". Make sure CodeGen can cope with that, e.g. for static initializers. 41 const char TestProgram1[] = "extern \"C\" int funcForProg1() { return 17; }\n" 42 "struct EmitCXXGlobalInitFunc1 {\n" 43 " EmitCXXGlobalInitFunc1() {}\n" 44 "} test1;"; 45 46 const char TestProgram2[] = "extern \"C\" int funcForProg2() { return 42; }\n" 47 "struct EmitCXXGlobalInitFunc2 {\n" 48 " EmitCXXGlobalInitFunc2() {}\n" 49 "} test2;"; 50 51 const Function *getGlobalInit(llvm::Module *M) { 52 for (const auto &Func : *M) 53 if (Func.hasName() && Func.getName().starts_with("_GLOBAL__sub_I_")) 54 return &Func; 55 56 return nullptr; 57 } 58 59 #ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT 60 TEST(IncrementalProcessing, DISABLED_EmitCXXGlobalInitFunc) { 61 #else 62 TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) { 63 #endif 64 if (!HostSupportsJit()) 65 GTEST_SKIP(); 66 67 std::vector<const char *> ClangArgv = {"-Xclang", "-emit-llvm-only"}; 68 auto CB = clang::IncrementalCompilerBuilder(); 69 CB.SetCompilerArgs(ClangArgv); 70 auto CI = cantFail(CB.CreateCpp()); 71 auto Interp = llvm::cantFail(Interpreter::create(std::move(CI))); 72 73 std::array<clang::PartialTranslationUnit *, 2> PTUs; 74 75 PTUs[0] = &llvm::cantFail(Interp->Parse(TestProgram1)); 76 ASSERT_TRUE(PTUs[0]->TheModule); 77 ASSERT_TRUE(PTUs[0]->TheModule->getFunction("funcForProg1")); 78 79 PTUs[1] = &llvm::cantFail(Interp->Parse(TestProgram2)); 80 ASSERT_TRUE(PTUs[1]->TheModule); 81 ASSERT_TRUE(PTUs[1]->TheModule->getFunction("funcForProg2")); 82 // First code should not end up in second module: 83 ASSERT_FALSE(PTUs[1]->TheModule->getFunction("funcForProg1")); 84 85 // Make sure global inits exist and are unique: 86 const Function *GlobalInit1 = getGlobalInit(PTUs[0]->TheModule.get()); 87 ASSERT_TRUE(GlobalInit1); 88 89 const Function *GlobalInit2 = getGlobalInit(PTUs[1]->TheModule.get()); 90 ASSERT_TRUE(GlobalInit2); 91 92 ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName()); 93 } 94 95 } // end anonymous namespace 96