1 //===- llvm/unittest/unittests/MC/AMDGPU/Disassembler.cpp -----------------===//
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
7 //===----------------------------------------------------------------------===//
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"
27 static const char *symbolLookupCallback(void *DisInfo
, uint64_t ReferenceValue
,
28 uint64_t *ReferenceType
,
30 const char **ReferenceName
) {
31 *ReferenceType
= LLVMDisassembler_ReferenceType_InOut_None
;
35 static const char *TripleName
= "amdgcn--amdpal";
36 static const char *CPUName
= "gfx1030";
39 TEST(AMDGPUDisassembler
, Basic
) {
40 LLVMInitializeAMDGPUTargetInfo();
41 LLVMInitializeAMDGPUTargetMC();
42 LLVMInitializeAMDGPUDisassembler();
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
);
51 // Skip test if AMDGPU not built.
56 unsigned NumBytes
= sizeof(Bytes
);
59 InstSize
= LLVMDisasmInstruction(DCR
, BytesP
, NumBytes
, PC
, OutString
,
61 EXPECT_EQ(InstSize
, 4U);
62 EXPECT_EQ(StringRef(OutString
), "\ts_version UC_VERSION_GFX10");
64 LLVMDisasmDispose(DCR
);
67 // Check multiple disassemblers in same MCContext.
68 TEST(AMDGPUDisassembler
, MultiDisassembler
) {
69 LLVMInitializeAMDGPUTargetInfo();
70 LLVMInitializeAMDGPUTargetMC();
71 LLVMInitializeAMDGPUDisassembler();
74 const Target
*TheTarget
= TargetRegistry::lookupTarget(TripleName
, Error
);
76 // Skip test if AMDGPU not built.
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());
89 int AsmPrinterVariant
= MAI
->getAssemblerDialect();
90 std::unique_ptr
<MCInstPrinter
> IP(TheTarget
->createMCInstPrinter(
91 Triple(TripleName
), AsmPrinterVariant
, *MAI
, *MII
, *MRI
));
93 SmallVector
<char, 64> InsnStr
, AnnoStr
;
94 raw_svector_ostream
OS(InsnStr
);
95 raw_svector_ostream
Annotations(AnnoStr
);
96 formatted_raw_ostream
FormattedOS(OS
);
100 uint8_t Bytes
[] = {0x04, 0x00, 0x80, 0xb0};
101 uint64_t InstSize
= 0U;
103 MCDisassembler::DecodeStatus Status
;
105 // Test disassembler works as expected.
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);
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");
120 // Test that second disassembler in same context works as expected.
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);
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");
136 // Test UC_VERSION symbols can be overriden without crashing.
137 // There is no valid behaviour if symbols are redefined in this way.
138 TEST(AMDGPUDisassembler
, UCVersionOverride
) {
139 LLVMInitializeAMDGPUTargetInfo();
140 LLVMInitializeAMDGPUTargetMC();
141 LLVMInitializeAMDGPUDisassembler();
144 const Target
*TheTarget
= TargetRegistry::lookupTarget(TripleName
, Error
);
146 // Skip test if AMDGPU not built.
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());
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
));
165 int AsmPrinterVariant
= MAI
->getAssemblerDialect();
166 std::unique_ptr
<MCInstPrinter
> IP(TheTarget
->createMCInstPrinter(
167 Triple(TripleName
), AsmPrinterVariant
, *MAI
, *MII
, *MRI
));
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
);
176 SmallVector
<char, 64> InsnStr
, AnnoStr
;
177 raw_svector_ostream
OS(InsnStr
);
178 raw_svector_ostream
Annotations(AnnoStr
);
179 formatted_raw_ostream
FormattedOS(OS
);
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;
192 MCDisassembler::DecodeStatus Status
=
193 DisAsm
->getInstruction(Inst
, InstSize
, Bytes
, 0, Annotations
);
194 ASSERT_TRUE(Status
== MCDisassembler::Success
);
195 EXPECT_EQ(InstSize
, 4U);
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';
202 if (Version
== UC_VERSION_GFX10_DEFAULT
)
203 EXPECT_EQ(StringRef(StrBuffer
), "\ts_version UC_VERSION_GFX10");
205 EXPECT_EQ(StringRef(StrBuffer
), "\ts_version 153");