brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · bdf5a23 Raw
234 lines · cpp
1//===- unittests/Frontend/FrontendActionTest.cpp  FrontendAction tests-----===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Frontend/CompilerInstance.h"10#include "flang/Frontend/CompilerInvocation.h"11#include "flang/Frontend/FrontendOptions.h"12#include "flang/FrontendTool/Utils.h"13#include "llvm/Support/FileSystem.h"14#include "llvm/Support/TargetSelect.h"15#include "llvm/Support/raw_ostream.h"16#include "llvm/TargetParser/Host.h"17#include "llvm/TargetParser/Triple.h"18 19#include "gtest/gtest.h"20 21using namespace Fortran::frontend;22 23namespace {24 25class FrontendActionTest : public ::testing::Test {26protected:27  // AllSources (which is used to manage files inside every compiler28  // instance), works with paths. So we need a filename and a path for the29  // input file.30  // TODO: We could use `-` for inputFilePath, but then we'd need a way to31  // write to stdin that's then read by AllSources. Ideally, AllSources should32  // be capable of reading from any stream.33  std::string inputFileName;34  std::string inputFilePath;35  // The output stream for the input file. Use this to populate the input.36  std::unique_ptr<llvm::raw_fd_ostream> inputFileOs;37 38  std::error_code ec;39 40  CompilerInstance compInst;41  std::shared_ptr<CompilerInvocation> invoc;42 43  void SetUp() override {44    // Generate a unique test file name.45    const testing::TestInfo *const testInfo =46        testing::UnitTest::GetInstance()->current_test_info();47    inputFileName = std::string(testInfo->name()) + "_test-file.f90";48 49    // Create the input file stream. Note that this stream is populated50    // separately in every test (i.e. the input is test specific).51    inputFileOs = std::make_unique<llvm::raw_fd_ostream>(52        inputFileName, ec, llvm::sys::fs::OF_None);53    if (ec)54      FAIL() << "Failed to create the input file";55 56    // Get the path of the input file.57    llvm::SmallString<256> cwd;58    if (std::error_code ec = llvm::sys::fs::current_path(cwd))59      FAIL() << "Failed to obtain the current working directory";60    inputFilePath = cwd.c_str();61    inputFilePath += "/" + inputFileName;62 63    // Prepare the compiler (CompilerInvocation + CompilerInstance)64    compInst.createDiagnostics();65    invoc = std::make_shared<CompilerInvocation>();66 67    // Set-up default target triple and initialize LLVM Targets so that the68    // target data layout can be passed to the frontend.69    invoc->getTargetOpts().triple =70        llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());71    llvm::InitializeAllTargets();72    llvm::InitializeAllTargetMCs();73 74    compInst.setInvocation(std::move(invoc));75    compInst.getFrontendOpts().inputs.push_back(76        FrontendInputFile(inputFilePath, Language::Fortran));77  }78 79  void TearDown() override {80    // Clear the input file.81    llvm::sys::fs::remove(inputFileName);82 83    // Clear the output files.84    // Note that these tests use an output buffer (as opposed to an output85    // file), hence there are no physical output files to delete and86    // `EraseFiles` is set to `false`. Also, some actions (e.g.87    // `ParseSyntaxOnly`) don't generated output. In such cases there's no88    // output to clear and `ClearOutputFile` returns immediately.89    compInst.clearOutputFiles(/*EraseFiles=*/false);90  }91};92 93TEST_F(FrontendActionTest, TestInputOutput) {94  // Populate the input file with the pre-defined input and flush it.95  *(inputFileOs) << "End Program arithmetic";96  inputFileOs.reset();97 98  // Set-up the action kind.99  compInst.getInvocation().getFrontendOpts().programAction = InputOutputTest;100 101  // Set-up the output stream. Using output buffer wrapped as an output102  // stream, as opposed to an actual file (or a file descriptor).103  llvm::SmallVector<char, 256> outputFileBuffer;104  std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(105      new llvm::raw_svector_ostream(outputFileBuffer));106  compInst.setOutputStream(std::move(outputFileStream));107 108  // Execute the action.109  bool success = executeCompilerInvocation(&compInst);110 111  // Validate the expected output.112  EXPECT_TRUE(success);113  EXPECT_TRUE(!outputFileBuffer.empty());114  EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data())115                  .starts_with("End Program arithmetic"));116}117 118TEST_F(FrontendActionTest, PrintPreprocessedInput) {119  // Populate the input file with the pre-defined input and flush it.120  *(inputFileOs) << "#ifdef NEW\n"121                 << "  Program A \n"122                 << "#else\n"123                 << "  Program B\n"124                 << "#endif";125  inputFileOs.reset();126 127  // Set-up the action kind.128  compInst.getInvocation().getFrontendOpts().programAction =129      PrintPreprocessedInput;130  compInst.getInvocation().getPreprocessorOpts().noReformat = true;131 132  // Set-up the output stream. We are using output buffer wrapped as an output133  // stream, as opposed to an actual file (or a file descriptor).134  llvm::SmallVector<char, 256> outputFileBuffer;135  std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(136      new llvm::raw_svector_ostream(outputFileBuffer));137  compInst.setOutputStream(std::move(outputFileStream));138 139  // Execute the action.140  bool success = executeCompilerInvocation(&compInst);141 142  // Validate the expected output.143  EXPECT_TRUE(success);144  EXPECT_TRUE(!outputFileBuffer.empty());145  EXPECT_TRUE(146      llvm::StringRef(outputFileBuffer.data()).starts_with(" program b\n"));147}148 149TEST_F(FrontendActionTest, ParseSyntaxOnly) {150  // Populate the input file with the pre-defined input and flush it.151  *(inputFileOs) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n"152                 << "END";153  inputFileOs.reset();154 155  // Set-up the action kind.156  compInst.getInvocation().getFrontendOpts().programAction = ParseSyntaxOnly;157 158  // Set-up the output stream for the semantic diagnostics.159  llvm::SmallVector<char, 256> outputDiagBuffer;160  std::unique_ptr<llvm::raw_pwrite_stream> outputStream(161      new llvm::raw_svector_ostream(outputDiagBuffer));162  compInst.setSemaOutputStream(std::move(outputStream));163 164  // Execute the action.165  bool success = executeCompilerInvocation(&compInst);166 167  // Validate the expected output.168  EXPECT_FALSE(success);169  EXPECT_TRUE(!outputDiagBuffer.empty());170  EXPECT_TRUE(171      llvm::StringRef(outputDiagBuffer.data())172          .contains(173              ":1:14: error: IF statement is not allowed in IF statement\n"));174}175 176TEST_F(FrontendActionTest, EmitLLVM) {177  // Populate the input file with the pre-defined input and flush it.178  *(inputFileOs) << "end program";179  inputFileOs.reset();180 181  // Set-up the action kind.182  compInst.getInvocation().getFrontendOpts().programAction = EmitLLVM;183 184  // Initialise LLVM backend185  llvm::InitializeAllAsmPrinters();186 187  // Set-up the output stream. We are using output buffer wrapped as an output188  // stream, as opposed to an actual file (or a file descriptor).189  llvm::SmallVector<char> outputFileBuffer;190  std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(191      new llvm::raw_svector_ostream(outputFileBuffer));192  compInst.setOutputStream(std::move(outputFileStream));193 194  // Execute the action.195  bool success = executeCompilerInvocation(&compInst);196 197  // Validate the expected output.198  EXPECT_TRUE(success);199  EXPECT_TRUE(!outputFileBuffer.empty());200 201  EXPECT_TRUE(llvm::StringRef(outputFileBuffer.begin(), outputFileBuffer.size())202                  .contains("define void @_QQmain()"));203}204 205TEST_F(FrontendActionTest, EmitAsm) {206  // Populate the input file with the pre-defined input and flush it.207  *(inputFileOs) << "end program";208  inputFileOs.reset();209 210  // Set-up the action kind.211  compInst.getInvocation().getFrontendOpts().programAction = EmitAssembly;212 213  // Initialise LLVM backend214  llvm::InitializeAllAsmPrinters();215 216  // Set-up the output stream. We are using output buffer wrapped as an output217  // stream, as opposed to an actual file (or a file descriptor).218  llvm::SmallVector<char, 256> outputFileBuffer;219  std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(220      new llvm::raw_svector_ostream(outputFileBuffer));221  compInst.setOutputStream(std::move(outputFileStream));222 223  // Execute the action.224  bool success = executeCompilerInvocation(&compInst);225 226  // Validate the expected output.227  EXPECT_TRUE(success);228  EXPECT_TRUE(!outputFileBuffer.empty());229 230  EXPECT_TRUE(llvm::StringRef(outputFileBuffer.begin(), outputFileBuffer.size())231                  .contains("_QQmain"));232}233} // namespace234