127d8eeddSEvgeny Shulgin //===- unittests/Support/TimeProfilerTest.cpp -----------------------------===// 227d8eeddSEvgeny Shulgin // 327d8eeddSEvgeny Shulgin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 427d8eeddSEvgeny Shulgin // See https://llvm.org/LICENSE.txt for license information. 527d8eeddSEvgeny Shulgin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 627d8eeddSEvgeny Shulgin // 727d8eeddSEvgeny Shulgin //===----------------------------------------------------------------------===// 827d8eeddSEvgeny Shulgin 927d8eeddSEvgeny Shulgin #include "clang/Frontend/CompilerInstance.h" 1027d8eeddSEvgeny Shulgin #include "clang/Frontend/FrontendActions.h" 1127d8eeddSEvgeny Shulgin #include "clang/Lex/PreprocessorOptions.h" 1227d8eeddSEvgeny Shulgin 13ecaacd14SUtkarsh Saxena #include "llvm/ADT/StringMap.h" 1427d8eeddSEvgeny Shulgin #include "llvm/Support/JSON.h" 15ecaacd14SUtkarsh Saxena #include "llvm/Support/Path.h" 1627d8eeddSEvgeny Shulgin #include "llvm/Support/TimeProfiler.h" 17ecaacd14SUtkarsh Saxena #include "llvm/Support/VirtualFileSystem.h" 1848ef912eSNikita Popov #include <stack> 1927d8eeddSEvgeny Shulgin 2027d8eeddSEvgeny Shulgin #include "gtest/gtest.h" 21ecaacd14SUtkarsh Saxena #include <tuple> 2227d8eeddSEvgeny Shulgin 2327d8eeddSEvgeny Shulgin using namespace clang; 2427d8eeddSEvgeny Shulgin using namespace llvm; 2527d8eeddSEvgeny Shulgin 2627d8eeddSEvgeny Shulgin namespace { 2727d8eeddSEvgeny Shulgin 2827d8eeddSEvgeny Shulgin // Should be called before testing. 2927d8eeddSEvgeny Shulgin void setupProfiler() { 30ecaacd14SUtkarsh Saxena timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test", 31ecaacd14SUtkarsh Saxena /*TimeTraceVerbose=*/true); 3227d8eeddSEvgeny Shulgin } 3327d8eeddSEvgeny Shulgin 3427d8eeddSEvgeny Shulgin // Should be called after `compileFromString()`. 3527d8eeddSEvgeny Shulgin // Returns profiler's JSON dump. 3627d8eeddSEvgeny Shulgin std::string teardownProfiler() { 3727d8eeddSEvgeny Shulgin SmallVector<char, 1024> SmallVec; 3827d8eeddSEvgeny Shulgin raw_svector_ostream OS(SmallVec); 3927d8eeddSEvgeny Shulgin timeTraceProfilerWrite(OS); 4027d8eeddSEvgeny Shulgin timeTraceProfilerCleanup(); 4127d8eeddSEvgeny Shulgin return OS.str().str(); 4227d8eeddSEvgeny Shulgin } 4327d8eeddSEvgeny Shulgin 4427d8eeddSEvgeny Shulgin // Returns true if code compiles successfully. 4527d8eeddSEvgeny Shulgin // We only parse AST here. This is enough for constexpr evaluation. 46ecaacd14SUtkarsh Saxena bool compileFromString(StringRef Code, StringRef Standard, StringRef File, 47ecaacd14SUtkarsh Saxena llvm::StringMap<std::string> Headers = {}) { 4827d8eeddSEvgeny Shulgin 49ecaacd14SUtkarsh Saxena llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS( 50ecaacd14SUtkarsh Saxena new llvm::vfs::InMemoryFileSystem()); 51ecaacd14SUtkarsh Saxena FS->addFile(File, 0, MemoryBuffer::getMemBuffer(Code)); 52ecaacd14SUtkarsh Saxena for (const auto &Header : Headers) { 53ecaacd14SUtkarsh Saxena FS->addFile(Header.getKey(), 0, 54ecaacd14SUtkarsh Saxena MemoryBuffer::getMemBuffer(Header.getValue())); 55ecaacd14SUtkarsh Saxena } 56ecaacd14SUtkarsh Saxena llvm::IntrusiveRefCntPtr<FileManager> Files( 57ecaacd14SUtkarsh Saxena new FileManager(FileSystemOptions(), FS)); 58*df9a14d7SKadir Cetinkaya CompilerInstance Compiler; 59*df9a14d7SKadir Cetinkaya Compiler.createDiagnostics(Files->getVirtualFileSystem()); 60ecaacd14SUtkarsh Saxena Compiler.setFileManager(Files.get()); 61ecaacd14SUtkarsh Saxena 6227d8eeddSEvgeny Shulgin auto Invocation = std::make_shared<CompilerInvocation>(); 63ecaacd14SUtkarsh Saxena std::vector<const char *> Args = {Standard.data(), File.data()}; 6427d8eeddSEvgeny Shulgin CompilerInvocation::CreateFromArgs(*Invocation, Args, 6527d8eeddSEvgeny Shulgin Compiler.getDiagnostics()); 6627d8eeddSEvgeny Shulgin Compiler.setInvocation(std::move(Invocation)); 6727d8eeddSEvgeny Shulgin 6827d8eeddSEvgeny Shulgin class TestFrontendAction : public ASTFrontendAction { 6927d8eeddSEvgeny Shulgin private: 7027d8eeddSEvgeny Shulgin std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 7127d8eeddSEvgeny Shulgin StringRef InFile) override { 7227d8eeddSEvgeny Shulgin return std::make_unique<ASTConsumer>(); 7327d8eeddSEvgeny Shulgin } 7427d8eeddSEvgeny Shulgin } Action; 7527d8eeddSEvgeny Shulgin return Compiler.ExecuteAction(Action); 7627d8eeddSEvgeny Shulgin } 7727d8eeddSEvgeny Shulgin 78ecaacd14SUtkarsh Saxena std::string GetMetadata(json::Object *Event) { 79280b04f6SUtkarsh Saxena std::string M; 80280b04f6SUtkarsh Saxena llvm::raw_string_ostream OS(M); 81ecaacd14SUtkarsh Saxena if (json::Object *Args = Event->getObject("args")) { 82ecaacd14SUtkarsh Saxena if (auto Detail = Args->getString("detail")) 83ecaacd14SUtkarsh Saxena OS << Detail; 84ecaacd14SUtkarsh Saxena // Use only filename to not include os-specific path separators. 85ecaacd14SUtkarsh Saxena if (auto File = Args->getString("file")) 86280b04f6SUtkarsh Saxena OS << (M.empty() ? "" : ", ") << llvm::sys::path::filename(*File); 87ecaacd14SUtkarsh Saxena if (auto Line = Args->getInteger("line")) 88ecaacd14SUtkarsh Saxena OS << ":" << *Line; 89ecaacd14SUtkarsh Saxena } 90280b04f6SUtkarsh Saxena return M; 91ecaacd14SUtkarsh Saxena } 92ecaacd14SUtkarsh Saxena 9327d8eeddSEvgeny Shulgin // Returns pretty-printed trace graph. 9427d8eeddSEvgeny Shulgin std::string buildTraceGraph(StringRef Json) { 9527d8eeddSEvgeny Shulgin struct EventRecord { 9627d8eeddSEvgeny Shulgin int64_t TimestampBegin; 9727d8eeddSEvgeny Shulgin int64_t TimestampEnd; 98ecaacd14SUtkarsh Saxena std::string Name; 99ecaacd14SUtkarsh Saxena std::string Metadata; 10027d8eeddSEvgeny Shulgin }; 10127d8eeddSEvgeny Shulgin std::vector<EventRecord> Events; 10227d8eeddSEvgeny Shulgin 10327d8eeddSEvgeny Shulgin // Parse `EventRecord`s from JSON dump. 10427d8eeddSEvgeny Shulgin Expected<json::Value> Root = json::parse(Json); 10527d8eeddSEvgeny Shulgin if (!Root) 10627d8eeddSEvgeny Shulgin return ""; 10727d8eeddSEvgeny Shulgin for (json::Value &TraceEventValue : 10827d8eeddSEvgeny Shulgin *Root->getAsObject()->getArray("traceEvents")) { 10927d8eeddSEvgeny Shulgin json::Object *TraceEventObj = TraceEventValue.getAsObject(); 11027d8eeddSEvgeny Shulgin 11127d8eeddSEvgeny Shulgin int64_t TimestampBegin = TraceEventObj->getInteger("ts").value_or(0); 11227d8eeddSEvgeny Shulgin int64_t TimestampEnd = 11327d8eeddSEvgeny Shulgin TimestampBegin + TraceEventObj->getInteger("dur").value_or(0); 114ecaacd14SUtkarsh Saxena std::string Name = TraceEventObj->getString("name").value_or("").str(); 115ecaacd14SUtkarsh Saxena std::string Metadata = GetMetadata(TraceEventObj); 116ecaacd14SUtkarsh Saxena 117ecaacd14SUtkarsh Saxena // Source events are asynchronous events and may not perfectly nest the 118ecaacd14SUtkarsh Saxena // synchronous events. Skip testing them. 119ecaacd14SUtkarsh Saxena if (Name == "Source") 120ecaacd14SUtkarsh Saxena continue; 12127d8eeddSEvgeny Shulgin 12227d8eeddSEvgeny Shulgin // This is a "summary" event, like "Total PerformPendingInstantiations", 12327d8eeddSEvgeny Shulgin // skip it 12427d8eeddSEvgeny Shulgin if (TimestampBegin == 0) 12527d8eeddSEvgeny Shulgin continue; 12627d8eeddSEvgeny Shulgin 12727d8eeddSEvgeny Shulgin Events.emplace_back( 128ecaacd14SUtkarsh Saxena EventRecord{TimestampBegin, TimestampEnd, Name, Metadata}); 12927d8eeddSEvgeny Shulgin } 13027d8eeddSEvgeny Shulgin 13127d8eeddSEvgeny Shulgin // There can be nested events that are very fast, for example: 13227d8eeddSEvgeny Shulgin // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1} 13327d8eeddSEvgeny Shulgin // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1} 13427d8eeddSEvgeny Shulgin // Therefore we should reverse the events list, so that events that have 13527d8eeddSEvgeny Shulgin // started earlier are first in the list. 13627d8eeddSEvgeny Shulgin // Then do a stable sort, we need it for the trace graph. 13727d8eeddSEvgeny Shulgin std::reverse(Events.begin(), Events.end()); 13827d8eeddSEvgeny Shulgin std::stable_sort( 13927d8eeddSEvgeny Shulgin Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) { 14027d8eeddSEvgeny Shulgin return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) < 14127d8eeddSEvgeny Shulgin std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd); 14227d8eeddSEvgeny Shulgin }); 14327d8eeddSEvgeny Shulgin 14427d8eeddSEvgeny Shulgin std::stringstream Stream; 14527d8eeddSEvgeny Shulgin // Write a newline for better testing with multiline string literal. 14627d8eeddSEvgeny Shulgin Stream << "\n"; 14727d8eeddSEvgeny Shulgin 14827d8eeddSEvgeny Shulgin // Keep the current event stack. 14927d8eeddSEvgeny Shulgin std::stack<const EventRecord *> EventStack; 15027d8eeddSEvgeny Shulgin for (const auto &Event : Events) { 15127d8eeddSEvgeny Shulgin // Pop every event in the stack until meeting the parent event. 15227d8eeddSEvgeny Shulgin while (!EventStack.empty()) { 15327d8eeddSEvgeny Shulgin bool InsideCurrentEvent = 15427d8eeddSEvgeny Shulgin Event.TimestampBegin >= EventStack.top()->TimestampBegin && 15527d8eeddSEvgeny Shulgin Event.TimestampEnd <= EventStack.top()->TimestampEnd; 15627d8eeddSEvgeny Shulgin if (!InsideCurrentEvent) 15727d8eeddSEvgeny Shulgin EventStack.pop(); 15827d8eeddSEvgeny Shulgin else 15927d8eeddSEvgeny Shulgin break; 16027d8eeddSEvgeny Shulgin } 16127d8eeddSEvgeny Shulgin EventStack.push(&Event); 16227d8eeddSEvgeny Shulgin 16327d8eeddSEvgeny Shulgin // Write indentaion, name, detail, newline. 16427d8eeddSEvgeny Shulgin for (size_t i = 1; i < EventStack.size(); ++i) { 16527d8eeddSEvgeny Shulgin Stream << "| "; 16627d8eeddSEvgeny Shulgin } 16727d8eeddSEvgeny Shulgin Stream.write(Event.Name.data(), Event.Name.size()); 168ecaacd14SUtkarsh Saxena if (!Event.Metadata.empty()) { 16927d8eeddSEvgeny Shulgin Stream << " ("; 170ecaacd14SUtkarsh Saxena Stream.write(Event.Metadata.data(), Event.Metadata.size()); 17127d8eeddSEvgeny Shulgin Stream << ")"; 17227d8eeddSEvgeny Shulgin } 17327d8eeddSEvgeny Shulgin Stream << "\n"; 17427d8eeddSEvgeny Shulgin } 17527d8eeddSEvgeny Shulgin return Stream.str(); 17627d8eeddSEvgeny Shulgin } 17727d8eeddSEvgeny Shulgin 17827d8eeddSEvgeny Shulgin } // namespace 17927d8eeddSEvgeny Shulgin 1802bb50a55SEvgeny Shulgin TEST(TimeProfilerTest, ConstantEvaluationCxx20) { 181ecaacd14SUtkarsh Saxena std::string Code = R"( 18227d8eeddSEvgeny Shulgin void print(double value); 18327d8eeddSEvgeny Shulgin 18427d8eeddSEvgeny Shulgin namespace slow_namespace { 18527d8eeddSEvgeny Shulgin 18627d8eeddSEvgeny Shulgin consteval double slow_func() { 18727d8eeddSEvgeny Shulgin double d = 0.0; 18827d8eeddSEvgeny Shulgin for (int i = 0; i < 100; ++i) { // 8th line 18927d8eeddSEvgeny Shulgin d += i; // 9th line 19027d8eeddSEvgeny Shulgin } 19127d8eeddSEvgeny Shulgin return d; 19227d8eeddSEvgeny Shulgin } 19327d8eeddSEvgeny Shulgin 19427d8eeddSEvgeny Shulgin } // namespace slow_namespace 19527d8eeddSEvgeny Shulgin 19627d8eeddSEvgeny Shulgin void slow_test() { 19727d8eeddSEvgeny Shulgin constexpr auto slow_value = slow_namespace::slow_func(); // 17th line 19827d8eeddSEvgeny Shulgin print(slow_namespace::slow_func()); // 18th line 19927d8eeddSEvgeny Shulgin print(slow_value); 20027d8eeddSEvgeny Shulgin } 20127d8eeddSEvgeny Shulgin 20227d8eeddSEvgeny Shulgin int slow_arr[12 + 34 * 56 + // 22nd line 20327d8eeddSEvgeny Shulgin static_cast<int>(slow_namespace::slow_func())]; // 23rd line 20427d8eeddSEvgeny Shulgin 20527d8eeddSEvgeny Shulgin constexpr int slow_init_list[] = {1, 1, 2, 3, 5, 8, 13, 21}; // 25th line 20627d8eeddSEvgeny Shulgin )"; 20727d8eeddSEvgeny Shulgin 20827d8eeddSEvgeny Shulgin setupProfiler(); 2092bb50a55SEvgeny Shulgin ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc")); 21027d8eeddSEvgeny Shulgin std::string Json = teardownProfiler(); 211ecaacd14SUtkarsh Saxena ASSERT_EQ(R"( 212280b04f6SUtkarsh Saxena Frontend (test.cc) 213700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.cc:2:1) 214700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.cc:6:1) 215700d93b0SYing Yi | | ParseFunctionDefinition (slow_func) 216700d93b0SYing Yi | | | EvaluateAsRValue (<test.cc:8:21>) 217700d93b0SYing Yi | | | EvaluateForOverflow (<test.cc:8:21, col:25>) 218700d93b0SYing Yi | | | EvaluateForOverflow (<test.cc:8:30, col:32>) 219700d93b0SYing Yi | | | EvaluateAsRValue (<test.cc:9:14>) 220700d93b0SYing Yi | | | EvaluateForOverflow (<test.cc:9:9, col:14>) 221700d93b0SYing Yi | | | isPotentialConstantExpr (slow_namespace::slow_func) 222700d93b0SYing Yi | | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>) 223700d93b0SYing Yi | | | | EvaluateAsRValue (<test.cc:8:21, col:25>) 224700d93b0SYing Yi | | | EvaluateAsBooleanCondition (<test.cc:8:21, col:25>) 225700d93b0SYing Yi | | | | EvaluateAsRValue (<test.cc:8:21, col:25>) 226700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.cc:16:1) 227700d93b0SYing Yi | | ParseFunctionDefinition (slow_test) 228700d93b0SYing Yi | | | EvaluateAsInitializer (slow_value) 229700d93b0SYing Yi | | | EvaluateAsConstantExpr (<test.cc:17:33, col:59>) 230700d93b0SYing Yi | | | EvaluateAsConstantExpr (<test.cc:18:11, col:37>) 231700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.cc:22:1) 232700d93b0SYing Yi | | EvaluateAsConstantExpr (<test.cc:23:31, col:57>) 233700d93b0SYing Yi | | EvaluateAsRValue (<test.cc:22:14, line:23:58>) 234700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.cc:25:1) 235700d93b0SYing Yi | | EvaluateAsInitializer (slow_init_list) 23627d8eeddSEvgeny Shulgin | PerformPendingInstantiations 237ecaacd14SUtkarsh Saxena )", 238ecaacd14SUtkarsh Saxena buildTraceGraph(Json)); 239ecaacd14SUtkarsh Saxena } 24027d8eeddSEvgeny Shulgin 2411be64e54Sivanaivanovska TEST(TimeProfilerTest, ClassTemplateInstantiations) { 2421be64e54Sivanaivanovska std::string Code = R"( 2431be64e54Sivanaivanovska template<class T> 2441be64e54Sivanaivanovska struct S 2451be64e54Sivanaivanovska { 2461be64e54Sivanaivanovska void foo() {} 2471be64e54Sivanaivanovska void bar(); 2481be64e54Sivanaivanovska }; 2491be64e54Sivanaivanovska 2501be64e54Sivanaivanovska template struct S<double>; // explicit instantiation of S<double> 2511be64e54Sivanaivanovska 2521be64e54Sivanaivanovska void user() { 2531be64e54Sivanaivanovska S<int> a; // implicit instantiation of S<int> 2541be64e54Sivanaivanovska S<float>* b; 2551be64e54Sivanaivanovska b->foo(); // implicit instatiation of S<float> and S<float>::foo() 2561be64e54Sivanaivanovska } 2571be64e54Sivanaivanovska )"; 2581be64e54Sivanaivanovska 2591be64e54Sivanaivanovska setupProfiler(); 2601be64e54Sivanaivanovska ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc")); 2611be64e54Sivanaivanovska std::string Json = teardownProfiler(); 2621be64e54Sivanaivanovska ASSERT_EQ(R"( 2631be64e54Sivanaivanovska Frontend (test.cc) 2641be64e54Sivanaivanovska | ParseClass (S) 2651be64e54Sivanaivanovska | InstantiateClass (S<double>, test.cc:9) 2661be64e54Sivanaivanovska | InstantiateFunction (S<double>::foo, test.cc:5) 2671be64e54Sivanaivanovska | ParseDeclarationOrFunctionDefinition (test.cc:11:5) 2681be64e54Sivanaivanovska | | ParseFunctionDefinition (user) 2691be64e54Sivanaivanovska | | | InstantiateClass (S<int>, test.cc:3) 2701be64e54Sivanaivanovska | | | InstantiateClass (S<float>, test.cc:3) 2711be64e54Sivanaivanovska | | | DeferInstantiation (S<float>::foo) 2721be64e54Sivanaivanovska | PerformPendingInstantiations 2731be64e54Sivanaivanovska | | InstantiateFunction (S<float>::foo, test.cc:5) 2741be64e54Sivanaivanovska )", 2751be64e54Sivanaivanovska buildTraceGraph(Json)); 2761be64e54Sivanaivanovska } 2771be64e54Sivanaivanovska 278ecaacd14SUtkarsh Saxena TEST(TimeProfilerTest, TemplateInstantiations) { 279ecaacd14SUtkarsh Saxena std::string B_H = R"( 280ecaacd14SUtkarsh Saxena template <typename T> 2811be64e54Sivanaivanovska T fooC(T t) { 282ecaacd14SUtkarsh Saxena return T(); 283ecaacd14SUtkarsh Saxena } 284ecaacd14SUtkarsh Saxena 2851be64e54Sivanaivanovska template <typename T> 2861be64e54Sivanaivanovska constexpr T fooB(T t) { 2871be64e54Sivanaivanovska return fooC(t); 2881be64e54Sivanaivanovska } 2891be64e54Sivanaivanovska 290ecaacd14SUtkarsh Saxena #define MacroTemp(x) template <typename T> void foo##x(T) { T(); } 291ecaacd14SUtkarsh Saxena )"; 292ecaacd14SUtkarsh Saxena 293ecaacd14SUtkarsh Saxena std::string A_H = R"( 294ecaacd14SUtkarsh Saxena #include "b.h" 295ecaacd14SUtkarsh Saxena 296ecaacd14SUtkarsh Saxena MacroTemp(MTA) 297ecaacd14SUtkarsh Saxena 298ecaacd14SUtkarsh Saxena template <typename T> 299ecaacd14SUtkarsh Saxena void fooA(T t) { fooB(t); fooMTA(t); } 300ecaacd14SUtkarsh Saxena )"; 301ecaacd14SUtkarsh Saxena std::string Code = R"( 302ecaacd14SUtkarsh Saxena #include "a.h" 303ecaacd14SUtkarsh Saxena void user() { fooA(0); } 304ecaacd14SUtkarsh Saxena )"; 305ecaacd14SUtkarsh Saxena 306ecaacd14SUtkarsh Saxena setupProfiler(); 307ecaacd14SUtkarsh Saxena ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc", 308ecaacd14SUtkarsh Saxena /*Headers=*/{{"a.h", A_H}, {"b.h", B_H}})); 309ecaacd14SUtkarsh Saxena std::string Json = teardownProfiler(); 310ecaacd14SUtkarsh Saxena ASSERT_EQ(R"( 311280b04f6SUtkarsh Saxena Frontend (test.cc) 3121be64e54Sivanaivanovska | ParseFunctionDefinition (fooC) 313ecaacd14SUtkarsh Saxena | ParseFunctionDefinition (fooB) 314ecaacd14SUtkarsh Saxena | ParseFunctionDefinition (fooMTA) 315ecaacd14SUtkarsh Saxena | ParseFunctionDefinition (fooA) 316ecaacd14SUtkarsh Saxena | ParseDeclarationOrFunctionDefinition (test.cc:3:5) 317ecaacd14SUtkarsh Saxena | | ParseFunctionDefinition (user) 3181be64e54Sivanaivanovska | | | DeferInstantiation (fooA<int>) 319ecaacd14SUtkarsh Saxena | PerformPendingInstantiations 320ecaacd14SUtkarsh Saxena | | InstantiateFunction (fooA<int>, a.h:7) 3211be64e54Sivanaivanovska | | | InstantiateFunction (fooB<int>, b.h:8) 3221be64e54Sivanaivanovska | | | | DeferInstantiation (fooC<int>) 3231be64e54Sivanaivanovska | | | DeferInstantiation (fooMTA<int>) 3241be64e54Sivanaivanovska | | | InstantiateFunction (fooC<int>, b.h:3) 325ecaacd14SUtkarsh Saxena | | | InstantiateFunction (fooMTA<int>, a.h:4) 326ecaacd14SUtkarsh Saxena )", 327ecaacd14SUtkarsh Saxena buildTraceGraph(Json)); 32827d8eeddSEvgeny Shulgin } 3292bb50a55SEvgeny Shulgin 3302bb50a55SEvgeny Shulgin TEST(TimeProfilerTest, ConstantEvaluationC99) { 331ecaacd14SUtkarsh Saxena std::string Code = R"( 3322bb50a55SEvgeny Shulgin struct { 3332bb50a55SEvgeny Shulgin short quantval[4]; // 3rd line 3342bb50a55SEvgeny Shulgin } value; 3352bb50a55SEvgeny Shulgin )"; 3362bb50a55SEvgeny Shulgin 3372bb50a55SEvgeny Shulgin setupProfiler(); 3382bb50a55SEvgeny Shulgin ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c")); 3392bb50a55SEvgeny Shulgin std::string Json = teardownProfiler(); 340ecaacd14SUtkarsh Saxena ASSERT_EQ(R"( 341280b04f6SUtkarsh Saxena Frontend (test.c) 342700d93b0SYing Yi | ParseDeclarationOrFunctionDefinition (test.c:2:1) 343700d93b0SYing Yi | | isIntegerConstantExpr (<test.c:3:18>) 344700d93b0SYing Yi | | EvaluateKnownConstIntCheckOverflow (<test.c:3:18>) 3452bb50a55SEvgeny Shulgin | PerformPendingInstantiations 346ecaacd14SUtkarsh Saxena )", 347ecaacd14SUtkarsh Saxena buildTraceGraph(Json)); 3482bb50a55SEvgeny Shulgin } 349