13338ef93Speter klausler //===- unittests/Frontend/FrontendActionTest.cpp FrontendAction tests-----===//
2db2195bcSAndrzej Warzynski //
3db2195bcSAndrzej Warzynski // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4db2195bcSAndrzej Warzynski // See https://llvm.org/LICENSE.txt for license information.
5db2195bcSAndrzej Warzynski // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6db2195bcSAndrzej Warzynski //
7db2195bcSAndrzej Warzynski //===----------------------------------------------------------------------===//
8db2195bcSAndrzej Warzynski
9db2195bcSAndrzej Warzynski #include "flang/Frontend/CompilerInstance.h"
1044e74c75SAndrzej Warzynski #include "flang/Frontend/CompilerInvocation.h"
11db2195bcSAndrzej Warzynski #include "flang/Frontend/FrontendOptions.h"
12db2195bcSAndrzej Warzynski #include "flang/FrontendTool/Utils.h"
13db2195bcSAndrzej Warzynski #include "llvm/Support/FileSystem.h"
1438101b4eSAndrzej Warzynski #include "llvm/Support/TargetSelect.h"
15db2195bcSAndrzej Warzynski #include "llvm/Support/raw_ostream.h"
16d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h"
1762c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
18db2195bcSAndrzej Warzynski
19b564b12bSAndrzej Warzynski #include "gtest/gtest.h"
20b564b12bSAndrzej Warzynski
21db2195bcSAndrzej Warzynski using namespace Fortran::frontend;
22db2195bcSAndrzej Warzynski
23db2195bcSAndrzej Warzynski namespace {
24db2195bcSAndrzej Warzynski
2544e74c75SAndrzej Warzynski class FrontendActionTest : public ::testing::Test {
2644e74c75SAndrzej Warzynski protected:
2744e74c75SAndrzej Warzynski // AllSources (which is used to manage files inside every compiler
2844e74c75SAndrzej Warzynski // instance), works with paths. So we need a filename and a path for the
2944e74c75SAndrzej Warzynski // input file.
301e462fafSAndrzej Warzynski // TODO: We could use `-` for inputFilePath, but then we'd need a way to
3144e74c75SAndrzej Warzynski // write to stdin that's then read by AllSources. Ideally, AllSources should
3244e74c75SAndrzej Warzynski // be capable of reading from any stream.
331e462fafSAndrzej Warzynski std::string inputFileName;
341e462fafSAndrzej Warzynski std::string inputFilePath;
3544e74c75SAndrzej Warzynski // The output stream for the input file. Use this to populate the input.
361e462fafSAndrzej Warzynski std::unique_ptr<llvm::raw_fd_ostream> inputFileOs;
37db2195bcSAndrzej Warzynski
381e462fafSAndrzej Warzynski std::error_code ec;
39db2195bcSAndrzej Warzynski
401e462fafSAndrzej Warzynski CompilerInstance compInst;
411e462fafSAndrzej Warzynski std::shared_ptr<CompilerInvocation> invoc;
4244e74c75SAndrzej Warzynski
SetUp()4344e74c75SAndrzej Warzynski void SetUp() override {
4444e74c75SAndrzej Warzynski // Generate a unique test file name.
451e462fafSAndrzej Warzynski const testing::TestInfo *const testInfo =
4644e74c75SAndrzej Warzynski testing::UnitTest::GetInstance()->current_test_info();
471e462fafSAndrzej Warzynski inputFileName = std::string(testInfo->name()) + "_test-file.f90";
4844e74c75SAndrzej Warzynski
4944e74c75SAndrzej Warzynski // Create the input file stream. Note that this stream is populated
5044e74c75SAndrzej Warzynski // separately in every test (i.e. the input is test specific).
511e462fafSAndrzej Warzynski inputFileOs = std::make_unique<llvm::raw_fd_ostream>(
521e462fafSAndrzej Warzynski inputFileName, ec, llvm::sys::fs::OF_None);
531e462fafSAndrzej Warzynski if (ec)
5444e74c75SAndrzej Warzynski FAIL() << "Failed to create the input file";
5544e74c75SAndrzej Warzynski
5644e74c75SAndrzej Warzynski // Get the path of the input file.
5744e74c75SAndrzej Warzynski llvm::SmallString<256> cwd;
581e462fafSAndrzej Warzynski if (std::error_code ec = llvm::sys::fs::current_path(cwd))
5944e74c75SAndrzej Warzynski FAIL() << "Failed to obtain the current working directory";
601e462fafSAndrzej Warzynski inputFilePath = cwd.c_str();
611e462fafSAndrzej Warzynski inputFilePath += "/" + inputFileName;
6244e74c75SAndrzej Warzynski
6344e74c75SAndrzej Warzynski // Prepare the compiler (CompilerInvocation + CompilerInstance)
641e462fafSAndrzej Warzynski compInst.createDiagnostics();
651e462fafSAndrzej Warzynski invoc = std::make_shared<CompilerInvocation>();
6644e74c75SAndrzej Warzynski
67e59e8488SjeanPerier // Set-up default target triple and initialize LLVM Targets so that the
68e59e8488SjeanPerier // target data layout can be passed to the frontend.
69e59e8488SjeanPerier invoc->getTargetOpts().triple =
70e59e8488SjeanPerier llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
71e59e8488SjeanPerier llvm::InitializeAllTargets();
72e59e8488SjeanPerier llvm::InitializeAllTargetMCs();
73e59e8488SjeanPerier
741e462fafSAndrzej Warzynski compInst.setInvocation(std::move(invoc));
751e462fafSAndrzej Warzynski compInst.getFrontendOpts().inputs.push_back(
761e462fafSAndrzej Warzynski FrontendInputFile(inputFilePath, Language::Fortran));
7744e74c75SAndrzej Warzynski }
7844e74c75SAndrzej Warzynski
TearDown()7944e74c75SAndrzej Warzynski void TearDown() override {
8044e74c75SAndrzej Warzynski // Clear the input file.
811e462fafSAndrzej Warzynski llvm::sys::fs::remove(inputFileName);
8244e74c75SAndrzej Warzynski
8344e74c75SAndrzej Warzynski // Clear the output files.
8444e74c75SAndrzej Warzynski // Note that these tests use an output buffer (as opposed to an output
8544e74c75SAndrzej Warzynski // file), hence there are no physical output files to delete and
8644e74c75SAndrzej Warzynski // `EraseFiles` is set to `false`. Also, some actions (e.g.
8744e74c75SAndrzej Warzynski // `ParseSyntaxOnly`) don't generated output. In such cases there's no
8844e74c75SAndrzej Warzynski // output to clear and `ClearOutputFile` returns immediately.
891e462fafSAndrzej Warzynski compInst.clearOutputFiles(/*EraseFiles=*/false);
9044e74c75SAndrzej Warzynski }
9144e74c75SAndrzej Warzynski };
9244e74c75SAndrzej Warzynski
TEST_F(FrontendActionTest,TestInputOutput)93b564b12bSAndrzej Warzynski TEST_F(FrontendActionTest, TestInputOutput) {
94b564b12bSAndrzej Warzynski // Populate the input file with the pre-defined input and flush it.
951e462fafSAndrzej Warzynski *(inputFileOs) << "End Program arithmetic";
961e462fafSAndrzej Warzynski inputFileOs.reset();
97b564b12bSAndrzej Warzynski
98b564b12bSAndrzej Warzynski // Set-up the action kind.
991e462fafSAndrzej Warzynski compInst.getInvocation().getFrontendOpts().programAction = InputOutputTest;
100b564b12bSAndrzej Warzynski
101b564b12bSAndrzej Warzynski // Set-up the output stream. Using output buffer wrapped as an output
102b564b12bSAndrzej Warzynski // stream, as opposed to an actual file (or a file descriptor).
103b564b12bSAndrzej Warzynski llvm::SmallVector<char, 256> outputFileBuffer;
104b564b12bSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
105b564b12bSAndrzej Warzynski new llvm::raw_svector_ostream(outputFileBuffer));
1061e462fafSAndrzej Warzynski compInst.setOutputStream(std::move(outputFileStream));
107b564b12bSAndrzej Warzynski
108b564b12bSAndrzej Warzynski // Execute the action.
1091e462fafSAndrzej Warzynski bool success = executeCompilerInvocation(&compInst);
110b564b12bSAndrzej Warzynski
111b564b12bSAndrzej Warzynski // Validate the expected output.
112b564b12bSAndrzej Warzynski EXPECT_TRUE(success);
113b564b12bSAndrzej Warzynski EXPECT_TRUE(!outputFileBuffer.empty());
114b564b12bSAndrzej Warzynski EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data())
11511efcceaSKazu Hirata .starts_with("End Program arithmetic"));
116b564b12bSAndrzej Warzynski }
117b564b12bSAndrzej Warzynski
TEST_F(FrontendActionTest,PrintPreprocessedInput)11844e74c75SAndrzej Warzynski TEST_F(FrontendActionTest, PrintPreprocessedInput) {
119db2195bcSAndrzej Warzynski // Populate the input file with the pre-defined input and flush it.
1201e462fafSAndrzej Warzynski *(inputFileOs) << "#ifdef NEW\n"
121db2195bcSAndrzej Warzynski << " Program A \n"
122db2195bcSAndrzej Warzynski << "#else\n"
123db2195bcSAndrzej Warzynski << " Program B\n"
124db2195bcSAndrzej Warzynski << "#endif";
1251e462fafSAndrzej Warzynski inputFileOs.reset();
126db2195bcSAndrzej Warzynski
12744e74c75SAndrzej Warzynski // Set-up the action kind.
1281e462fafSAndrzej Warzynski compInst.getInvocation().getFrontendOpts().programAction =
1291e462fafSAndrzej Warzynski PrintPreprocessedInput;
1301e462fafSAndrzej Warzynski compInst.getInvocation().getPreprocessorOpts().noReformat = true;
131db2195bcSAndrzej Warzynski
13244e74c75SAndrzej Warzynski // Set-up the output stream. We are using output buffer wrapped as an output
133db2195bcSAndrzej Warzynski // stream, as opposed to an actual file (or a file descriptor).
134db2195bcSAndrzej Warzynski llvm::SmallVector<char, 256> outputFileBuffer;
135db2195bcSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
136db2195bcSAndrzej Warzynski new llvm::raw_svector_ostream(outputFileBuffer));
1371e462fafSAndrzej Warzynski compInst.setOutputStream(std::move(outputFileStream));
138db2195bcSAndrzej Warzynski
13944e74c75SAndrzej Warzynski // Execute the action.
1401e462fafSAndrzej Warzynski bool success = executeCompilerInvocation(&compInst);
141db2195bcSAndrzej Warzynski
14244e74c75SAndrzej Warzynski // Validate the expected output.
143db2195bcSAndrzej Warzynski EXPECT_TRUE(success);
144db2195bcSAndrzej Warzynski EXPECT_TRUE(!outputFileBuffer.empty());
145db2195bcSAndrzej Warzynski EXPECT_TRUE(
14611efcceaSKazu Hirata llvm::StringRef(outputFileBuffer.data()).starts_with(" program b\n"));
147db2195bcSAndrzej Warzynski }
148db2195bcSAndrzej Warzynski
TEST_F(FrontendActionTest,ParseSyntaxOnly)14944e74c75SAndrzej Warzynski TEST_F(FrontendActionTest, ParseSyntaxOnly) {
150db2195bcSAndrzej Warzynski // Populate the input file with the pre-defined input and flush it.
1511e462fafSAndrzej Warzynski *(inputFileOs) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n"
152db2195bcSAndrzej Warzynski << "END";
1531e462fafSAndrzej Warzynski inputFileOs.reset();
154db2195bcSAndrzej Warzynski
15544e74c75SAndrzej Warzynski // Set-up the action kind.
1561e462fafSAndrzej Warzynski compInst.getInvocation().getFrontendOpts().programAction = ParseSyntaxOnly;
157db2195bcSAndrzej Warzynski
15844e74c75SAndrzej Warzynski // Set-up the output stream for the semantic diagnostics.
159db2195bcSAndrzej Warzynski llvm::SmallVector<char, 256> outputDiagBuffer;
160db2195bcSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> outputStream(
161db2195bcSAndrzej Warzynski new llvm::raw_svector_ostream(outputDiagBuffer));
1621e462fafSAndrzej Warzynski compInst.setSemaOutputStream(std::move(outputStream));
163db2195bcSAndrzej Warzynski
16444e74c75SAndrzej Warzynski // Execute the action.
1651e462fafSAndrzej Warzynski bool success = executeCompilerInvocation(&compInst);
166db2195bcSAndrzej Warzynski
16744e74c75SAndrzej Warzynski // Validate the expected output.
168db2195bcSAndrzej Warzynski EXPECT_FALSE(success);
169db2195bcSAndrzej Warzynski EXPECT_TRUE(!outputDiagBuffer.empty());
170db2195bcSAndrzej Warzynski EXPECT_TRUE(
171db2195bcSAndrzej Warzynski llvm::StringRef(outputDiagBuffer.data())
1726110e771Speter klausler .contains(
17344e74c75SAndrzej Warzynski ":1:14: error: IF statement is not allowed in IF statement\n"));
174db2195bcSAndrzej Warzynski }
175e993b20cSAndrzej Warzynski
TEST_F(FrontendActionTest,EmitLLVM)176e993b20cSAndrzej Warzynski TEST_F(FrontendActionTest, EmitLLVM) {
177e993b20cSAndrzej Warzynski // Populate the input file with the pre-defined input and flush it.
1781e462fafSAndrzej Warzynski *(inputFileOs) << "end program";
1791e462fafSAndrzej Warzynski inputFileOs.reset();
180e993b20cSAndrzej Warzynski
181e993b20cSAndrzej Warzynski // Set-up the action kind.
1821e462fafSAndrzej Warzynski compInst.getInvocation().getFrontendOpts().programAction = EmitLLVM;
18302fb5b77SAndrzej Warzynski
18481181089SMats Petersson // Initialise LLVM backend
18581181089SMats Petersson llvm::InitializeAllAsmPrinters();
18681181089SMats Petersson
187e993b20cSAndrzej Warzynski // Set-up the output stream. We are using output buffer wrapped as an output
188e993b20cSAndrzej Warzynski // stream, as opposed to an actual file (or a file descriptor).
189e993b20cSAndrzej Warzynski llvm::SmallVector<char> outputFileBuffer;
190e993b20cSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
191e993b20cSAndrzej Warzynski new llvm::raw_svector_ostream(outputFileBuffer));
1921e462fafSAndrzej Warzynski compInst.setOutputStream(std::move(outputFileStream));
193e993b20cSAndrzej Warzynski
194e993b20cSAndrzej Warzynski // Execute the action.
1951e462fafSAndrzej Warzynski bool success = executeCompilerInvocation(&compInst);
196e993b20cSAndrzej Warzynski
197e993b20cSAndrzej Warzynski // Validate the expected output.
198e993b20cSAndrzej Warzynski EXPECT_TRUE(success);
199e993b20cSAndrzej Warzynski EXPECT_TRUE(!outputFileBuffer.empty());
200e993b20cSAndrzej Warzynski
201*aa26faf0SKrzysztof Parzyszek EXPECT_TRUE(llvm::StringRef(outputFileBuffer.begin(), outputFileBuffer.size())
202e993b20cSAndrzej Warzynski .contains("define void @_QQmain()"));
203e993b20cSAndrzej Warzynski }
20438101b4eSAndrzej Warzynski
TEST_F(FrontendActionTest,EmitAsm)20538101b4eSAndrzej Warzynski TEST_F(FrontendActionTest, EmitAsm) {
20638101b4eSAndrzej Warzynski // Populate the input file with the pre-defined input and flush it.
2071e462fafSAndrzej Warzynski *(inputFileOs) << "end program";
2081e462fafSAndrzej Warzynski inputFileOs.reset();
20938101b4eSAndrzej Warzynski
21038101b4eSAndrzej Warzynski // Set-up the action kind.
2111e462fafSAndrzej Warzynski compInst.getInvocation().getFrontendOpts().programAction = EmitAssembly;
21202fb5b77SAndrzej Warzynski
21338101b4eSAndrzej Warzynski // Initialise LLVM backend
21438101b4eSAndrzej Warzynski llvm::InitializeAllAsmPrinters();
21538101b4eSAndrzej Warzynski
21638101b4eSAndrzej Warzynski // Set-up the output stream. We are using output buffer wrapped as an output
21738101b4eSAndrzej Warzynski // stream, as opposed to an actual file (or a file descriptor).
21838101b4eSAndrzej Warzynski llvm::SmallVector<char, 256> outputFileBuffer;
21938101b4eSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
22038101b4eSAndrzej Warzynski new llvm::raw_svector_ostream(outputFileBuffer));
2211e462fafSAndrzej Warzynski compInst.setOutputStream(std::move(outputFileStream));
22238101b4eSAndrzej Warzynski
22338101b4eSAndrzej Warzynski // Execute the action.
2241e462fafSAndrzej Warzynski bool success = executeCompilerInvocation(&compInst);
22538101b4eSAndrzej Warzynski
22638101b4eSAndrzej Warzynski // Validate the expected output.
22738101b4eSAndrzej Warzynski EXPECT_TRUE(success);
22838101b4eSAndrzej Warzynski EXPECT_TRUE(!outputFileBuffer.empty());
22938101b4eSAndrzej Warzynski
230*aa26faf0SKrzysztof Parzyszek EXPECT_TRUE(llvm::StringRef(outputFileBuffer.begin(), outputFileBuffer.size())
231*aa26faf0SKrzysztof Parzyszek .contains("_QQmain"));
23238101b4eSAndrzej Warzynski }
233db2195bcSAndrzej Warzynski } // namespace
234