blob: 9eedcb76f49a84e64ac0964a8cb8d04329f8a6e4 [file] [log] [blame]
//===---- DriverTests.cpp -------------------------------------------------===//
//
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//===----------------------------------------------------------------------===//
#include <iostream>
#include <map>
#include <set>
#include <stdarg.h>
#include "Driver.h"
#include "Compilation.h"
#include "gtest/gtest.h"
#include "DiffUtils.h"
using namespace llvm;
using namespace gollvm::driver;
using namespace goBackendUnitTests;
namespace {
inline std::vector<const char *> A(const char *arg, ...) {
va_list ap;
va_start(ap, arg);
std::vector<const char *> result;
while(arg != nullptr) {
result.push_back(arg);
arg = va_arg(ap, const char *);
}
return result;
}
class DrvTestHarness {
public:
explicit DrvTestHarness(const std::vector<const char *> args)
: args_(args) { }
// Returns non-zero on error, zero for success.
unsigned Perform();
// Test that a dump of driver actions matches the expeced result.
bool expectActions(const ExpectedDump &ed);
private:
const std::vector<const char *> args_;
std::string actionsDump_;
};
unsigned DrvTestHarness::Perform()
{
std::unique_ptr<opt::OptTable> opts =
gollvm::options::createGollvmDriverOptTable();
unsigned missingArgIndex, missingArgCount;
ArrayRef<const char *> argvv = makeArrayRef(args_);
opt::InputArgList args =
opts->ParseArgs(argvv, missingArgIndex, missingArgCount);
// Complain about missing arguments.
if (missingArgIndex != 0) {
errs() << "error: argument to '"
<< args.getArgString(missingArgIndex)
<< "' option missing, expected "
<< missingArgCount << " value(s)\n";
return 1;
}
// Look for unknown options.
for (const opt::Arg *arg : args.filtered(gollvm::options::OPT_UNKNOWN)) {
errs() << "error: unrecognized command line option '"
<< arg->getAsString(args) << "'\n";
return 2;
}
// Create driver.
Driver driver(args, opts.get(), "llvm-goc", true);
driver.setUnitTesting();
// Set up driver, select target and toolchain.
ToolChain *toolchain = driver.setup();
if (toolchain == nullptr)
return 1;
// Build compilation; construct actions for this compile.
std::unique_ptr<Compilation> compilation =
driver.buildCompilation(*toolchain);
if (!driver.buildActions(*compilation))
return 2;
if (!driver.processActions(*compilation))
return 3;
actionsDump_ = driver.dumpActions(*compilation);
return 0;
}
bool DrvTestHarness::expectActions(const ExpectedDump &ed)
{
const std::string &expected = ed.content;
std::string reason;
auto actual = actionsDump_;
bool equal = difftokens(expected, actual, reason);
if (! equal)
complainOnNequal(reason, ed, actual);
return equal;
}
TEST(DriverTests, SimpleCompile) {
DrvTestHarness h(A("-c", "foo.go", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile+assemble
inputs:
inputfile Artifact arg(foo.go)
output:
Artifact file(foo.o)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, NoIntegAsmCompile) {
DrvTestHarness h(A("-c", "-fno-integrated-as", "foo.go", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile
inputs:
inputfile Artifact arg(foo.go)
output:
Artifact file(/tmp/out.compile.0)
Action assemble
inputs:
compile
output:
Artifact file(foo.o)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, CompileToAsm) {
DrvTestHarness h(A("-S", "foo.go", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile
inputs:
inputfile Artifact arg(foo.go)
output:
Artifact file(foo.s)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, CompileToLllvmBitcode) {
DrvTestHarness h(A("-emit-llvm", "-c", "foo.go", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile
inputs:
inputfile Artifact arg(foo.go)
output:
Artifact file(foo.bc)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, CompileToLllvmIRAsm) {
DrvTestHarness h(A("-emit-llvm", "-S", "foo.go", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile
inputs:
inputfile Artifact arg(foo.go)
output:
Artifact file(foo.ll)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, AssembleAction) {
DrvTestHarness h(A("-c", "foo.s", "-o", "blah.o", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action assemble
inputs:
inputfile Artifact arg(foo.s)
output:
Artifact arg(blah.o)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
TEST(DriverTests, CompileAndLinkAction) {
DrvTestHarness h(A("foo1.go", "foo2.go", "-o", "foo.exe", nullptr));
DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT(
Action compile+assemble
inputs:
inputfile Artifact arg(foo1.go)
inputfile Artifact arg(foo2.go)
output:
Artifact file(/tmp/out.compile+assemble.0)
Action link
inputs:
compile+assemble
output:
Artifact arg(foo.exe)
)RAW_RESULT");
unsigned res = h.Perform();
ASSERT_TRUE(res == 0 && "Setup failed");
bool isOK = h.expectActions(exp);
EXPECT_TRUE(isOK && "Actions dump does not have expected contents");
}
} // namespace