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