blob: 95c800d2d10d4f7091c5e0f977d6ac2ce2d9a1d8 [file] [log] [blame]
//===- unittest/Support/RemarksLinkingTest.cpp - Linking tests ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/Bitcode/BitcodeAnalyzer.h"
#include "llvm/Remarks/RemarkLinker.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <string>
using namespace llvm;
static void serializeAndCheck(remarks::RemarkLinker &RL,
remarks::Format OutputFormat,
StringRef ExpectedOutput) {
// 1. Create a serializer.
// 2. Serialize all the remarks from the linker.
// 3. Check that it matches the output.
std::string Buf;
raw_string_ostream OS(Buf);
Error E = RL.serialize(OS, OutputFormat);
EXPECT_FALSE(static_cast<bool>(E));
// For bitstream, run it through the analyzer.
if (OutputFormat == remarks::Format::Bitstream) {
std::string AnalyzeBuf;
raw_string_ostream AnalyzeOS(AnalyzeBuf);
BCDumpOptions O(AnalyzeOS);
O.ShowBinaryBlobs = true;
BitcodeAnalyzer BA(OS.str());
EXPECT_FALSE(BA.analyze(O)); // Expect no errors.
EXPECT_EQ(AnalyzeOS.str(), ExpectedOutput);
} else {
EXPECT_EQ(OS.str(), ExpectedOutput);
}
}
static void check(remarks::Format InputFormat, StringRef Input,
remarks::Format OutputFormat, StringRef ExpectedOutput) {
remarks::RemarkLinker RL;
EXPECT_FALSE(RL.link(Input, InputFormat));
serializeAndCheck(RL, OutputFormat, ExpectedOutput);
}
static void check(remarks::Format InputFormat, StringRef Input,
remarks::Format InputFormat2, StringRef Input2,
remarks::Format OutputFormat, StringRef ExpectedOutput) {
remarks::RemarkLinker RL;
EXPECT_FALSE(RL.link(Input, InputFormat));
EXPECT_FALSE(RL.link(Input2, InputFormat2));
serializeAndCheck(RL, OutputFormat, ExpectedOutput);
}
TEST(Remarks, LinkingGoodYAML) {
// One YAML remark.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n");
// Check that we don't keep remarks without debug locations.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"Function: foo\n"
"...\n",
remarks::Format::YAML, "");
// Check that we deduplicate remarks.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n"
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n");
}
TEST(Remarks, LinkingGoodBitstream) {
// One YAML remark.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
"</Remark>\n");
// Check that we deduplicate remarks.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n"
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::Bitstream,
"<BLOCKINFO_BLOCK/>\n"
"<Meta BlockID=8 NumWords=12 BlockCodeSize=3>\n"
" <Container info codeid=1 abbrevid=4 op0=0 op1=2/>\n"
" <Remark version codeid=2 abbrevid=5 op0=0/>\n"
" <String table codeid=3 abbrevid=6/> blob data = "
"'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"
"</Meta>\n"
"<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"
" <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"
" <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"
"</Remark>\n");
}
TEST(Remarks, LinkingGoodStrTab) {
// Check that remarks from different entries use the same strtab.
check(remarks::Format::YAML,
"--- !Missed\n"
"Pass: inline\n"
"Name: NoDefinition\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::YAML,
"--- !Passed\n"
"Pass: inline\n"
"Name: Ok\n"
"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
"Function: foo\n"
"...\n",
remarks::Format::YAMLStrTab,
StringRef("REMARKS\0\0\0\0\0\0\0\0\0\x22\0\0\0\0\0\0\0"
"inline\0NoDefinition\0foo\0file.c\0Ok\0"
"--- !Passed\n"
"Pass: 0\n"
"Name: 4\n"
"DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
"Function: 2\n"
"...\n"
"--- !Missed\n"
"Pass: 0\n"
"Name: 1\n"
"DebugLoc: { File: 3, Line: 3, Column: 12 }\n"
"Function: 2\n"
"...\n",
304));
}
// Check that we propagate parsing errors.
TEST(Remarks, LinkingError) {
remarks::RemarkLinker RL;
{
Error E = RL.link("badyaml", remarks::Format::YAML);
EXPECT_TRUE(static_cast<bool>(E));
EXPECT_EQ(toString(std::move(E)),
"YAML:1:1: error: document root is not of mapping type.\n"
"\n"
"badyaml\n"
"^~~~~~~\n"
"\n");
}
{
// Check that the prepend path is propagated and fails with the full path.
RL.setExternalFilePrependPath("/baddir/");
Error E = RL.link(
StringRef("REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml",
40),
remarks::Format::YAMLStrTab);
EXPECT_TRUE(static_cast<bool>(E));
std::string ErrorMessage = toString(std::move(E));
EXPECT_EQ(StringRef(ErrorMessage).lower(),
StringRef("'/baddir/badfile.opt.yaml': No such file or directory")
.lower());
}
}