263 lines · cpp
1//===- unittest/Support/RemarksLinkingTest.cpp - Linking 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 "llvm/Bitcode/BitcodeAnalyzer.h"10#include "llvm/Remarks/RemarkLinker.h"11#include "llvm/Remarks/RemarkSerializer.h"12#include "llvm/Support/raw_ostream.h"13#include "gtest/gtest.h"14#include <string>15 16using namespace llvm;17 18static void serializeAndCheck(remarks::RemarkLinker &RL,19 remarks::Format OutputFormat,20 StringRef ExpectedOutput) {21 // 1. Create a serializer.22 // 2. Serialize all the remarks from the linker.23 // 3. Check that it matches the output.24 std::string Buf;25 raw_string_ostream OS(Buf);26 Error E = RL.serialize(OS, OutputFormat);27 EXPECT_FALSE(static_cast<bool>(E));28 29 // For bitstream, run it through the analyzer.30 if (OutputFormat == remarks::Format::Bitstream) {31 std::string AnalyzeBuf;32 raw_string_ostream AnalyzeOS(AnalyzeBuf);33 BCDumpOptions O(AnalyzeOS);34 O.ShowBinaryBlobs = true;35 BitcodeAnalyzer BA(OS.str());36 EXPECT_FALSE(BA.analyze(O)); // Expect no errors.37 EXPECT_EQ(AnalyzeOS.str(), ExpectedOutput);38 } else {39 EXPECT_EQ(OS.str(), ExpectedOutput);40 }41}42 43static void check(remarks::Format InputFormat, StringRef Input,44 remarks::Format OutputFormat, StringRef ExpectedOutput,45 std::optional<bool> KeepAllRemarks = {}) {46 remarks::RemarkLinker RL;47 if (KeepAllRemarks)48 RL.setKeepAllRemarks(*KeepAllRemarks);49 EXPECT_FALSE(RL.link(Input, InputFormat));50 serializeAndCheck(RL, OutputFormat, ExpectedOutput);51}52 53static void check(remarks::Format InputFormat, StringRef Input,54 remarks::Format InputFormat2, StringRef Input2,55 remarks::Format OutputFormat, StringRef ExpectedOutput) {56 remarks::RemarkLinker RL;57 EXPECT_FALSE(RL.link(Input, InputFormat));58 EXPECT_FALSE(RL.link(Input2, InputFormat2));59 serializeAndCheck(RL, OutputFormat, ExpectedOutput);60}61 62TEST(Remarks, LinkingGoodYAML) {63 // One YAML remark.64 check(remarks::Format::YAML,65 "--- !Missed\n"66 "Pass: inline\n"67 "Name: NoDefinition\n"68 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"69 "Function: foo\n"70 "...\n",71 remarks::Format::YAML,72 "--- !Missed\n"73 "Pass: inline\n"74 "Name: NoDefinition\n"75 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"76 "Function: foo\n"77 "...\n");78 79 // Check that we don't keep remarks without debug locations, unless80 // KeepAllRemarks is set.81 check(remarks::Format::YAML,82 "--- !Missed\n"83 "Pass: inline\n"84 "Name: NoDefinition\n"85 "Function: foo\n"86 "...\n",87 remarks::Format::YAML, "",88 /*KeepAllRemarks=*/false);89 check(remarks::Format::YAML,90 "--- !Missed\n"91 "Pass: inline\n"92 "Name: NoDefinition\n"93 "Function: foo\n"94 "...\n",95 remarks::Format::YAML,96 "--- !Missed\n"97 "Pass: inline\n"98 "Name: NoDefinition\n"99 "Function: foo\n"100 "...\n");101 102 // Check that we deduplicate remarks.103 check(remarks::Format::YAML,104 "--- !Missed\n"105 "Pass: inline\n"106 "Name: NoDefinition\n"107 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"108 "Function: foo\n"109 "...\n"110 "--- !Missed\n"111 "Pass: inline\n"112 "Name: NoDefinition\n"113 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"114 "Function: foo\n"115 "...\n",116 remarks::Format::YAML,117 "--- !Missed\n"118 "Pass: inline\n"119 "Name: NoDefinition\n"120 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"121 "Function: foo\n"122 "...\n");123}124 125TEST(Remarks, LinkingGoodBitstream) {126 // One YAML remark.127 check(remarks::Format::YAML,128 "--- !Missed\n"129 "Pass: inline\n"130 "Name: NoDefinition\n"131 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"132 "Function: foo\n"133 "...\n",134 remarks::Format::Bitstream,135 "<BLOCKINFO_BLOCK/>\n"136 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"137 " <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"138 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"139 "</Meta>\n"140 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"141 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"142 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"143 "</Remark>\n"144 "<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"145 " <String table codeid=3 abbrevid=6/> blob data = "146 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"147 "</Meta>\n");148 149 // Check that we keep remarks without debug info.150 check(remarks::Format::YAML,151 "--- !Missed\n"152 "Pass: inline\n"153 "Name: NoDefinition\n"154 "Function: foo\n"155 "...\n",156 remarks::Format::Bitstream,157 "<BLOCKINFO_BLOCK/>\n"158 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"159 " <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"160 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"161 "</Meta>\n"162 "<Remark BlockID=9 NumWords=1 BlockCodeSize=4>\n"163 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"164 "</Remark>\n"165 "<Meta BlockID=8 NumWords=8 BlockCodeSize=3>\n"166 " <String table codeid=3 abbrevid=6/> blob data = "167 "'inline\\x00NoDefinition\\x00foo\\x00'\n"168 "</Meta>\n");169 170 // Check that we deduplicate remarks.171 check(remarks::Format::YAML,172 "--- !Missed\n"173 "Pass: inline\n"174 "Name: NoDefinition\n"175 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"176 "Function: foo\n"177 "...\n"178 "--- !Missed\n"179 "Pass: inline\n"180 "Name: NoDefinition\n"181 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"182 "Function: foo\n"183 "...\n",184 remarks::Format::Bitstream,185 "<BLOCKINFO_BLOCK/>\n"186 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"187 " <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"188 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"189 "</Meta>\n"190 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"191 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"192 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"193 "</Remark>\n"194 "<Meta BlockID=8 NumWords=10 BlockCodeSize=3>\n"195 " <String table codeid=3 abbrevid=6/> blob data = "196 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00'\n"197 "</Meta>\n");198}199 200TEST(Remarks, LinkingGoodStrTab) {201 // Check that remarks from different entries use the same strtab.202 check(remarks::Format::YAML,203 "--- !Missed\n"204 "Pass: inline\n"205 "Name: NoDefinition\n"206 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"207 "Function: foo\n"208 "...\n",209 remarks::Format::YAML,210 "--- !Passed\n"211 "Pass: inline\n"212 "Name: Ok\n"213 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"214 "Function: foo\n"215 "...\n",216 remarks::Format::Bitstream,217 "<BLOCKINFO_BLOCK/>\n"218 "<Meta BlockID=8 NumWords=3 BlockCodeSize=3>\n"219 " <Container info codeid=1 abbrevid=4 op0=1 op1=1/>\n"220 " <Remark version codeid=2 abbrevid=5 op0=0/>\n"221 "</Meta>\n"222 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"223 " <Remark header codeid=5 abbrevid=4 op0=1 op1=4 op2=0 op3=2/>\n"224 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"225 "</Remark>\n"226 "<Remark BlockID=9 NumWords=4 BlockCodeSize=4>\n"227 " <Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>\n"228 " <Remark debug location codeid=6 abbrevid=5 op0=3 op1=3 op2=12/>\n"229 "</Remark>\n"230 "<Meta BlockID=8 NumWords=11 BlockCodeSize=3>\n"231 " <String table codeid=3 abbrevid=6/> blob data = "232 "'inline\\x00NoDefinition\\x00foo\\x00file.c\\x00Ok\\x00'\n"233 "</Meta>\n");234}235 236// Check that we propagate parsing errors.237TEST(Remarks, LinkingError) {238 remarks::RemarkLinker RL;239 {240 Error E = RL.link("badyaml", remarks::Format::YAML);241 EXPECT_TRUE(static_cast<bool>(E));242 EXPECT_EQ(toString(std::move(E)),243 "YAML:1:1: error: document root is not of mapping type.\n"244 "\n"245 "badyaml\n"246 "^~~~~~~\n"247 "\n");248 }249 250 {251 // Check that the prepend path is propagated and fails with the full path.252 // Also ensures that the remark format is correctly auto-detected.253 RL.setExternalFilePrependPath("/baddir/");254 Error E = RL.link(StringRef(255 "REMARKS\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0badfile.opt.yaml", 40));256 EXPECT_TRUE(static_cast<bool>(E));257 std::string ErrorMessage = toString(std::move(E));258 EXPECT_EQ(StringRef(ErrorMessage).lower(),259 StringRef("'/baddir/badfile.opt.yaml': No such file or directory")260 .lower());261 }262}263