xref: /llvm-project/llvm/unittests/MC/AMDGPU/Disassembler.cpp (revision 03807aa2c5d924a2e88fad1cacda2470c5052f1c)
1e83e53b7SCarl Ritson //===- llvm/unittest/unittests/MC/AMDGPU/Disassembler.cpp -----------------===//
2e83e53b7SCarl Ritson //
3e83e53b7SCarl Ritson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e83e53b7SCarl Ritson // See https://llvm.org/LICENSE.txt for license information.
5e83e53b7SCarl Ritson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e83e53b7SCarl Ritson //
7e83e53b7SCarl Ritson //===----------------------------------------------------------------------===//
8e83e53b7SCarl Ritson 
9e83e53b7SCarl Ritson #include "llvm-c/Disassembler.h"
10e83e53b7SCarl Ritson #include "llvm/MC/MCAsmInfo.h"
11e83e53b7SCarl Ritson #include "llvm/MC/MCContext.h"
12e83e53b7SCarl Ritson #include "llvm/MC/MCDisassembler/MCDisassembler.h"
13e83e53b7SCarl Ritson #include "llvm/MC/MCDisassembler/MCSymbolizer.h"
14e83e53b7SCarl Ritson #include "llvm/MC/MCInst.h"
15e83e53b7SCarl Ritson #include "llvm/MC/MCInstPrinter.h"
16e83e53b7SCarl Ritson #include "llvm/MC/MCInstrInfo.h"
17e83e53b7SCarl Ritson #include "llvm/MC/MCRegisterInfo.h"
18e83e53b7SCarl Ritson #include "llvm/MC/MCSubtargetInfo.h"
19e83e53b7SCarl Ritson #include "llvm/MC/MCSymbol.h"
20e83e53b7SCarl Ritson #include "llvm/MC/MCTargetOptions.h"
21e83e53b7SCarl Ritson #include "llvm/MC/TargetRegistry.h"
22e83e53b7SCarl Ritson #include "llvm/Support/TargetSelect.h"
23e83e53b7SCarl Ritson #include "gtest/gtest.h"
24e83e53b7SCarl Ritson 
25e83e53b7SCarl Ritson using namespace llvm;
26e83e53b7SCarl Ritson 
symbolLookupCallback(void * DisInfo,uint64_t ReferenceValue,uint64_t * ReferenceType,uint64_t ReferencePC,const char ** ReferenceName)27e83e53b7SCarl Ritson static const char *symbolLookupCallback(void *DisInfo, uint64_t ReferenceValue,
28e83e53b7SCarl Ritson                                         uint64_t *ReferenceType,
29e83e53b7SCarl Ritson                                         uint64_t ReferencePC,
30e83e53b7SCarl Ritson                                         const char **ReferenceName) {
31e83e53b7SCarl Ritson   *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
32e83e53b7SCarl Ritson   return nullptr;
33e83e53b7SCarl Ritson }
34e83e53b7SCarl Ritson 
35e83e53b7SCarl Ritson static const char *TripleName = "amdgcn--amdpal";
36e83e53b7SCarl Ritson static const char *CPUName = "gfx1030";
37e83e53b7SCarl Ritson 
38e83e53b7SCarl Ritson // Basic smoke test.
TEST(AMDGPUDisassembler,Basic)39e83e53b7SCarl Ritson TEST(AMDGPUDisassembler, Basic) {
40e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetInfo();
41e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetMC();
42e83e53b7SCarl Ritson   LLVMInitializeAMDGPUDisassembler();
43e83e53b7SCarl Ritson 
44e83e53b7SCarl Ritson   uint8_t Bytes[] = {0x04, 0x00, 0x80, 0xb0};
45e83e53b7SCarl Ritson   uint8_t *BytesP = Bytes;
46e83e53b7SCarl Ritson   const char OutStringSize = 100;
47e83e53b7SCarl Ritson   char OutString[OutStringSize];
48e83e53b7SCarl Ritson   LLVMDisasmContextRef DCR = LLVMCreateDisasmCPU(
49e83e53b7SCarl Ritson       TripleName, CPUName, nullptr, 0, nullptr, symbolLookupCallback);
50e83e53b7SCarl Ritson 
51e83e53b7SCarl Ritson   // Skip test if AMDGPU not built.
52e83e53b7SCarl Ritson   if (!DCR)
53e83e53b7SCarl Ritson     GTEST_SKIP();
54e83e53b7SCarl Ritson 
55e83e53b7SCarl Ritson   size_t InstSize;
56e83e53b7SCarl Ritson   unsigned NumBytes = sizeof(Bytes);
57e83e53b7SCarl Ritson   unsigned PC = 0U;
58e83e53b7SCarl Ritson 
59e83e53b7SCarl Ritson   InstSize = LLVMDisasmInstruction(DCR, BytesP, NumBytes, PC, OutString,
60e83e53b7SCarl Ritson                                    OutStringSize);
61e83e53b7SCarl Ritson   EXPECT_EQ(InstSize, 4U);
62e83e53b7SCarl Ritson   EXPECT_EQ(StringRef(OutString), "\ts_version UC_VERSION_GFX10");
63e83e53b7SCarl Ritson 
64e83e53b7SCarl Ritson   LLVMDisasmDispose(DCR);
65e83e53b7SCarl Ritson }
66e83e53b7SCarl Ritson 
67e83e53b7SCarl Ritson // Check multiple disassemblers in same MCContext.
TEST(AMDGPUDisassembler,MultiDisassembler)68e83e53b7SCarl Ritson TEST(AMDGPUDisassembler, MultiDisassembler) {
69e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetInfo();
70e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetMC();
71e83e53b7SCarl Ritson   LLVMInitializeAMDGPUDisassembler();
72e83e53b7SCarl Ritson 
73e83e53b7SCarl Ritson   std::string Error;
74e83e53b7SCarl Ritson   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
75e83e53b7SCarl Ritson 
76e83e53b7SCarl Ritson   // Skip test if AMDGPU not built.
77e83e53b7SCarl Ritson   if (!TheTarget)
78e83e53b7SCarl Ritson     GTEST_SKIP();
79e83e53b7SCarl Ritson 
80e83e53b7SCarl Ritson   std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
81e83e53b7SCarl Ritson   std::unique_ptr<MCAsmInfo> MAI(
82e83e53b7SCarl Ritson       TheTarget->createMCAsmInfo(*MRI, TripleName, MCTargetOptions()));
83e83e53b7SCarl Ritson   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
84e83e53b7SCarl Ritson   std::unique_ptr<MCSubtargetInfo> STI(
85e83e53b7SCarl Ritson       TheTarget->createMCSubtargetInfo(TripleName, CPUName, ""));
86e83e53b7SCarl Ritson   auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(),
87e83e53b7SCarl Ritson                                          MRI.get(), STI.get());
88e83e53b7SCarl Ritson 
89e83e53b7SCarl Ritson   int AsmPrinterVariant = MAI->getAssemblerDialect();
90e83e53b7SCarl Ritson   std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
91e83e53b7SCarl Ritson       Triple(TripleName), AsmPrinterVariant, *MAI, *MII, *MRI));
92e83e53b7SCarl Ritson 
93e83e53b7SCarl Ritson   SmallVector<char, 64> InsnStr, AnnoStr;
94e83e53b7SCarl Ritson   raw_svector_ostream OS(InsnStr);
95e83e53b7SCarl Ritson   raw_svector_ostream Annotations(AnnoStr);
96e83e53b7SCarl Ritson   formatted_raw_ostream FormattedOS(OS);
97e83e53b7SCarl Ritson 
98e83e53b7SCarl Ritson   char StrBuffer[128];
99e83e53b7SCarl Ritson 
100e83e53b7SCarl Ritson   uint8_t Bytes[] = {0x04, 0x00, 0x80, 0xb0};
101*03807aa2SNico Weber   uint64_t InstSize = 0U;
102e83e53b7SCarl Ritson   MCInst Inst1, Inst2;
103e83e53b7SCarl Ritson   MCDisassembler::DecodeStatus Status;
104e83e53b7SCarl Ritson 
105e83e53b7SCarl Ritson   // Test disassembler works as expected.
106e83e53b7SCarl Ritson   AnnoStr.clear();
107e83e53b7SCarl Ritson   InsnStr.clear();
108e83e53b7SCarl Ritson   std::unique_ptr<MCDisassembler> DisAsm1(
109e83e53b7SCarl Ritson       TheTarget->createMCDisassembler(*STI, *Ctx));
110e83e53b7SCarl Ritson   Status = DisAsm1->getInstruction(Inst1, InstSize, Bytes, 0, Annotations);
111e83e53b7SCarl Ritson   ASSERT_TRUE(Status == MCDisassembler::Success);
112e83e53b7SCarl Ritson   EXPECT_EQ(InstSize, 4U);
113e83e53b7SCarl Ritson 
114e83e53b7SCarl Ritson   IP->printInst(&Inst1, 0U, Annotations.str(), *STI, FormattedOS);
115e83e53b7SCarl Ritson   ASSERT_TRUE(InsnStr.size() < (sizeof(StrBuffer) - 1));
116e83e53b7SCarl Ritson   std::memcpy(StrBuffer, InsnStr.data(), InsnStr.size());
117e83e53b7SCarl Ritson   StrBuffer[InsnStr.size()] = '\0';
118e83e53b7SCarl Ritson   EXPECT_EQ(StringRef(StrBuffer), "\ts_version UC_VERSION_GFX10");
119e83e53b7SCarl Ritson 
120e83e53b7SCarl Ritson   // Test that second disassembler in same context works as expected.
121e83e53b7SCarl Ritson   AnnoStr.clear();
122e83e53b7SCarl Ritson   InsnStr.clear();
123e83e53b7SCarl Ritson   std::unique_ptr<MCDisassembler> DisAsm2(
124e83e53b7SCarl Ritson       TheTarget->createMCDisassembler(*STI, *Ctx));
125e83e53b7SCarl Ritson   Status = DisAsm2->getInstruction(Inst2, InstSize, Bytes, 0, Annotations);
126e83e53b7SCarl Ritson   ASSERT_TRUE(Status == MCDisassembler::Success);
127e83e53b7SCarl Ritson   EXPECT_EQ(InstSize, 4U);
128e83e53b7SCarl Ritson 
129e83e53b7SCarl Ritson   IP->printInst(&Inst2, 0U, Annotations.str(), *STI, FormattedOS);
130e83e53b7SCarl Ritson   ASSERT_TRUE(InsnStr.size() < (sizeof(StrBuffer) - 1));
131e83e53b7SCarl Ritson   std::memcpy(StrBuffer, InsnStr.data(), InsnStr.size());
132e83e53b7SCarl Ritson   StrBuffer[InsnStr.size()] = '\0';
133e83e53b7SCarl Ritson   EXPECT_EQ(StringRef(StrBuffer), "\ts_version UC_VERSION_GFX10");
134e83e53b7SCarl Ritson }
135e83e53b7SCarl Ritson 
136e83e53b7SCarl Ritson // Test UC_VERSION symbols can be overriden without crashing.
137e83e53b7SCarl Ritson // There is no valid behaviour if symbols are redefined in this way.
TEST(AMDGPUDisassembler,UCVersionOverride)138e83e53b7SCarl Ritson TEST(AMDGPUDisassembler, UCVersionOverride) {
139e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetInfo();
140e83e53b7SCarl Ritson   LLVMInitializeAMDGPUTargetMC();
141e83e53b7SCarl Ritson   LLVMInitializeAMDGPUDisassembler();
142e83e53b7SCarl Ritson 
143e83e53b7SCarl Ritson   std::string Error;
144e83e53b7SCarl Ritson   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
145e83e53b7SCarl Ritson 
146e83e53b7SCarl Ritson   // Skip test if AMDGPU not built.
147e83e53b7SCarl Ritson   if (!TheTarget)
148e83e53b7SCarl Ritson     GTEST_SKIP();
149e83e53b7SCarl Ritson 
150e83e53b7SCarl Ritson   std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
151e83e53b7SCarl Ritson   std::unique_ptr<MCAsmInfo> MAI(
152e83e53b7SCarl Ritson       TheTarget->createMCAsmInfo(*MRI, TripleName, MCTargetOptions()));
153e83e53b7SCarl Ritson   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
154e83e53b7SCarl Ritson   std::unique_ptr<MCSubtargetInfo> STI(
155e83e53b7SCarl Ritson       TheTarget->createMCSubtargetInfo(TripleName, CPUName, ""));
156e83e53b7SCarl Ritson   auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(),
157e83e53b7SCarl Ritson                                          MRI.get(), STI.get());
158e83e53b7SCarl Ritson 
159e83e53b7SCarl Ritson   // Define custom UC_VERSION before initializing disassembler.
160e83e53b7SCarl Ritson   const uint8_t UC_VERSION_GFX10_DEFAULT = 0x04;
161e83e53b7SCarl Ritson   const uint8_t UC_VERSION_GFX10_NEW = 0x99;
162e83e53b7SCarl Ritson   auto Sym = Ctx->getOrCreateSymbol("UC_VERSION_GFX10");
163e83e53b7SCarl Ritson   Sym->setVariableValue(MCConstantExpr::create(UC_VERSION_GFX10_NEW, *Ctx));
164e83e53b7SCarl Ritson 
165e83e53b7SCarl Ritson   int AsmPrinterVariant = MAI->getAssemblerDialect();
166e83e53b7SCarl Ritson   std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
167e83e53b7SCarl Ritson       Triple(TripleName), AsmPrinterVariant, *MAI, *MII, *MRI));
168e83e53b7SCarl Ritson 
169e83e53b7SCarl Ritson   testing::internal::CaptureStderr();
170e83e53b7SCarl Ritson   std::unique_ptr<MCDisassembler> DisAsm(
171e83e53b7SCarl Ritson       TheTarget->createMCDisassembler(*STI, *Ctx));
172e83e53b7SCarl Ritson   std::string Output = testing::internal::GetCapturedStderr();
173e83e53b7SCarl Ritson   EXPECT_TRUE(Output.find("<unknown>:0: warning: unsupported redefinition of "
174e83e53b7SCarl Ritson                           "UC_VERSION_GFX10") != std::string::npos);
175e83e53b7SCarl Ritson 
176e83e53b7SCarl Ritson   SmallVector<char, 64> InsnStr, AnnoStr;
177e83e53b7SCarl Ritson   raw_svector_ostream OS(InsnStr);
178e83e53b7SCarl Ritson   raw_svector_ostream Annotations(AnnoStr);
179e83e53b7SCarl Ritson   formatted_raw_ostream FormattedOS(OS);
180e83e53b7SCarl Ritson 
181e83e53b7SCarl Ritson   char StrBuffer[128];
182e83e53b7SCarl Ritson 
183e83e53b7SCarl Ritson   // Decode S_VERSION instruction with original or custom version.
184e83e53b7SCarl Ritson   uint8_t Versions[] = {UC_VERSION_GFX10_DEFAULT, UC_VERSION_GFX10_NEW};
185e83e53b7SCarl Ritson   for (uint8_t Version : Versions) {
186e83e53b7SCarl Ritson     uint8_t Bytes[] = {Version, 0x00, 0x80, 0xb0};
187*03807aa2SNico Weber     uint64_t InstSize = 0U;
188e83e53b7SCarl Ritson     MCInst Inst;
189e83e53b7SCarl Ritson 
190e83e53b7SCarl Ritson     AnnoStr.clear();
191e83e53b7SCarl Ritson     InsnStr.clear();
192e83e53b7SCarl Ritson     MCDisassembler::DecodeStatus Status =
193e83e53b7SCarl Ritson         DisAsm->getInstruction(Inst, InstSize, Bytes, 0, Annotations);
194e83e53b7SCarl Ritson     ASSERT_TRUE(Status == MCDisassembler::Success);
195e83e53b7SCarl Ritson     EXPECT_EQ(InstSize, 4U);
196e83e53b7SCarl Ritson 
197e83e53b7SCarl Ritson     IP->printInst(&Inst, 0, Annotations.str(), *STI, FormattedOS);
198e83e53b7SCarl Ritson     ASSERT_TRUE(InsnStr.size() < (sizeof(StrBuffer) - 1));
199e83e53b7SCarl Ritson     std::memcpy(StrBuffer, InsnStr.data(), InsnStr.size());
200e83e53b7SCarl Ritson     StrBuffer[InsnStr.size()] = '\0';
201e83e53b7SCarl Ritson 
202e83e53b7SCarl Ritson     if (Version == UC_VERSION_GFX10_DEFAULT)
203e83e53b7SCarl Ritson       EXPECT_EQ(StringRef(StrBuffer), "\ts_version UC_VERSION_GFX10");
204e83e53b7SCarl Ritson     else
205e83e53b7SCarl Ritson       EXPECT_EQ(StringRef(StrBuffer), "\ts_version 153");
206e83e53b7SCarl Ritson   }
207e83e53b7SCarl Ritson }
208