Skip to content

Commit e83e53b

Browse files
authored
[AMDGPU][MC] Allow UC_VERSION_* constant reuse (#96461)
If more than one disassembler is created for a context then allow reuse of existing constants. Warn if constants values do not match.
1 parent f4c7811 commit e83e53b

File tree

3 files changed

+220
-2
lines changed

3 files changed

+220
-2
lines changed

llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,8 +2366,16 @@ const MCExpr *AMDGPUDisassembler::createConstantSymbolExpr(StringRef Id,
23662366
int64_t Val) {
23672367
MCContext &Ctx = getContext();
23682368
MCSymbol *Sym = Ctx.getOrCreateSymbol(Id);
2369-
assert(!Sym->isVariable());
2370-
Sym->setVariableValue(MCConstantExpr::create(Val, Ctx));
2369+
// Note: only set value to Val on a new symbol in case an dissassembler
2370+
// has already been initialized in this context.
2371+
if (!Sym->isVariable()) {
2372+
Sym->setVariableValue(MCConstantExpr::create(Val, Ctx));
2373+
} else {
2374+
int64_t Res = ~Val;
2375+
bool Valid = Sym->getVariableValue()->evaluateAsAbsolute(Res);
2376+
if (!Valid || Res != Val)
2377+
Ctx.reportWarning(SMLoc(), "unsupported redefinition of " + Id);
2378+
}
23712379
return MCSymbolRefExpr::create(Sym, Ctx);
23722380
}
23732381

llvm/unittests/MC/AMDGPU/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ include_directories(
66
set(LLVM_LINK_COMPONENTS
77
AMDGPUCodeGen
88
AMDGPUDesc
9+
AMDGPUDisassembler
910
AMDGPUInfo
1011
MC
12+
MCDisassembler
1113
Support
1214
TargetParser
1315
)
1416

1517
add_llvm_unittest(AMDGPUMCTests
18+
Disassembler.cpp
1619
DwarfRegMappings.cpp
1720
)
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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+
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.
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.
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+
size_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.
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+
size_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+
}

0 commit comments

Comments
 (0)