Skip to content

Commit 1280232

Browse files
committed
Add tests for UC_VERSION override at assembly and in custom disassembly.
1 parent bb5c510 commit 1280232

File tree

5 files changed

+271
-14
lines changed

5 files changed

+271
-14
lines changed

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

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ AMDGPUDisassembler::AMDGPUDisassembler(const MCSubtargetInfo &STI,
5555
report_fatal_error("Disassembly not yet supported for subtarget");
5656

5757
for (auto [Symbol, Code] : AMDGPU::UCVersion::getGFXVersions())
58-
createConstantSymbolExpr(Symbol, Code);
58+
UCVersionSymbols.push_back(createConstantSymbolExpr(Symbol, Code));
5959

6060
UCVersionW64Expr = createConstantSymbolExpr("UC_VERSION_W64_BIT", 0x2000);
6161
UCVersionW32Expr = createConstantSymbolExpr("UC_VERSION_W32_BIT", 0x4000);
@@ -1755,18 +1755,25 @@ MCOperand AMDGPUDisassembler::decodeVersionImm(unsigned Imm) const {
17551755
if (Encoding::encode(Version, W64, W32, MDP) != Imm)
17561756
return MCOperand::createImm(Imm);
17571757

1758-
const auto &Versions = AMDGPU::UCVersion::getGFXVersions();
1759-
auto I = find_if(Versions,
1760-
[Version = Version](const AMDGPU::UCVersion::GFXVersion &V) {
1761-
return V.Code == Version;
1762-
});
1758+
// Locate UC_VERSION symbol matching Version.
17631759
MCContext &Ctx = getContext();
1764-
const MCExpr *E;
1765-
if (I == Versions.end())
1760+
const MCExpr *E = nullptr;
1761+
for (auto *VersionSym : UCVersionSymbols) {
1762+
int64_t Val;
1763+
if (!VersionSym->evaluateAsAbsolute(Val))
1764+
continue;
1765+
if (Val != (int64_t)Version)
1766+
continue;
1767+
auto *Sym = Ctx.getOrCreateSymbol(VersionSym->getSymbol().getName());
1768+
E = MCSymbolRefExpr::create(Sym, Ctx);
1769+
break;
1770+
}
1771+
1772+
// Default to constant value if not found.
1773+
if (!E)
17661774
E = MCConstantExpr::create(Version, Ctx);
1767-
else
1768-
E = MCSymbolRefExpr::create(Ctx.getOrCreateSymbol(I->Symbol), Ctx);
17691775

1776+
// Apply bits.
17701777
if (W64)
17711778
E = MCBinaryExpr::createOr(E, UCVersionW64Expr, Ctx);
17721779
if (W32)
@@ -2362,15 +2369,17 @@ Expected<bool> AMDGPUDisassembler::onSymbolStart(SymbolInfoTy &Symbol,
23622369
return false;
23632370
}
23642371

2365-
const MCExpr *AMDGPUDisassembler::createConstantSymbolExpr(StringRef Id,
2366-
int64_t Val) {
2372+
const MCSymbolRefExpr *
2373+
AMDGPUDisassembler::createConstantSymbolExpr(StringRef Id, int64_t Val) {
23672374
MCContext &Ctx = getContext();
23682375
MCSymbol *Sym = Ctx.getOrCreateSymbol(Id);
23692376
// Note: only set value to Val on a new symbol.
23702377
// Existing symbol may potentially have a different value to the one
23712378
// requested, which allows for user redefinition of symbols.
2372-
if (!Sym->isVariable())
2379+
if (!Sym->isVariable()) {
2380+
Sym->setRedefinable(true);
23732381
Sym->setVariableValue(MCConstantExpr::create(Val, Ctx));
2382+
}
23742383
return MCSymbolRefExpr::create(Sym, Ctx);
23752384
}
23762385

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class MCAsmInfo;
3030
class MCInst;
3131
class MCOperand;
3232
class MCSubtargetInfo;
33+
class MCSymbolRefExpr;
3334
class Twine;
3435

3536
// Exposes an interface expected by autogenerated code in
@@ -105,8 +106,9 @@ class AMDGPUDisassembler : public MCDisassembler {
105106
const MCExpr *UCVersionW64Expr;
106107
const MCExpr *UCVersionW32Expr;
107108
const MCExpr *UCVersionMDPExpr;
109+
SmallVector<const MCSymbolRefExpr *> UCVersionSymbols;
108110

109-
const MCExpr *createConstantSymbolExpr(StringRef Id, int64_t Val);
111+
const MCSymbolRefExpr *createConstantSymbolExpr(StringRef Id, int64_t Val);
110112

111113
public:
112114
AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: llvm-mc -triple=amdgcn -show-encoding -mcpu=gfx1010 %s | FileCheck --check-prefix=GFX10 %s
2+
3+
// Test that UC_VERSION* symbols can be redefined.
4+
5+
.set UC_VERSION_GFX10, 99
6+
7+
s_version UC_VERSION_GFX10
8+
// GFX10: encoding: [0x63,0x00,0x80,0xb0]
9+
10+
s_version UC_VERSION_GFX10 | UC_VERSION_W32_BIT
11+
// GFX10: encoding: [0x63,0x40,0x80,0xb0]
12+
13+
s_version UC_VERSION_GFX10 | UC_VERSION_W64_BIT
14+
// GFX10: encoding: [0x63,0x20,0x80,0xb0]
15+
16+
s_version UC_VERSION_GFX10 | UC_VERSION_MDP_BIT
17+
// GFX10: encoding: [0x63,0x80,0x80,0xb0]
18+
19+
s_version UC_VERSION_GFX10 | UC_VERSION_W64_BIT | UC_VERSION_MDP_BIT
20+
// GFX10: encoding: [0x63,0xa0,0x80,0xb0]
21+
22+
.set UC_VERSION_GFX10, 100
23+
.set UC_VERSION_W32_BIT, 0
24+
.set UC_VERSION_W64_BIT, 0
25+
.set UC_VERSION_MDP_BIT, 0
26+
27+
s_version UC_VERSION_GFX10
28+
// GFX10: encoding: [0x64,0x00,0x80,0xb0]
29+
30+
s_version UC_VERSION_GFX10 | UC_VERSION_W32_BIT
31+
// GFX10: encoding: [0x64,0x00,0x80,0xb0]
32+
33+
s_version UC_VERSION_GFX10 | UC_VERSION_W64_BIT
34+
// GFX10: encoding: [0x64,0x00,0x80,0xb0]
35+
36+
s_version UC_VERSION_GFX10 | UC_VERSION_MDP_BIT
37+
// GFX10: encoding: [0x64,0x00,0x80,0xb0]
38+
39+
s_version UC_VERSION_GFX10 | UC_VERSION_W64_BIT | UC_VERSION_MDP_BIT
40+
// GFX10: encoding: [0x64,0x00,0x80,0xb0]
41+

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: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
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.
137+
TEST(AMDGPUDisassembler, UCVersionOverride) {
138+
LLVMInitializeAMDGPUTargetInfo();
139+
LLVMInitializeAMDGPUTargetMC();
140+
LLVMInitializeAMDGPUDisassembler();
141+
142+
std::string Error;
143+
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
144+
145+
// Skip test if AMDGPU not built.
146+
if (!TheTarget)
147+
GTEST_SKIP();
148+
149+
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
150+
std::unique_ptr<MCAsmInfo> MAI(
151+
TheTarget->createMCAsmInfo(*MRI, TripleName, MCTargetOptions()));
152+
std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
153+
std::unique_ptr<MCSubtargetInfo> STI(
154+
TheTarget->createMCSubtargetInfo(TripleName, CPUName, ""));
155+
auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(),
156+
MRI.get(), STI.get());
157+
158+
// Define custom UC_VERSION before initializing disassembler.
159+
const uint8_t UC_VERSION_GFX10_DEFAULT = 0x04;
160+
const uint8_t UC_VERSION_GFX10_NEW = 0x99;
161+
auto Sym = Ctx->getOrCreateSymbol("UC_VERSION_GFX10");
162+
Sym->setVariableValue(MCConstantExpr::create(UC_VERSION_GFX10_NEW, *Ctx));
163+
164+
int AsmPrinterVariant = MAI->getAssemblerDialect();
165+
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
166+
Triple(TripleName), AsmPrinterVariant, *MAI, *MII, *MRI));
167+
168+
std::unique_ptr<MCDisassembler> DisAsm(
169+
TheTarget->createMCDisassembler(*STI, *Ctx));
170+
171+
SmallVector<char, 64> InsnStr, AnnoStr;
172+
raw_svector_ostream OS(InsnStr);
173+
raw_svector_ostream Annotations(AnnoStr);
174+
formatted_raw_ostream FormattedOS(OS);
175+
176+
char StrBuffer[128];
177+
178+
// Decode S_VERSION instruction with original or custom version.
179+
uint8_t Versions[] = {UC_VERSION_GFX10_DEFAULT, UC_VERSION_GFX10_NEW};
180+
for (uint8_t Version : Versions) {
181+
uint8_t Bytes[] = {Version, 0x00, 0x80, 0xb0};
182+
size_t InstSize = 0U;
183+
MCInst Inst;
184+
185+
AnnoStr.clear();
186+
InsnStr.clear();
187+
MCDisassembler::DecodeStatus Status =
188+
DisAsm->getInstruction(Inst, InstSize, Bytes, 0, Annotations);
189+
ASSERT_TRUE(Status == MCDisassembler::Success);
190+
EXPECT_EQ(InstSize, 4U);
191+
192+
IP->printInst(&Inst, 0, Annotations.str(), *STI, FormattedOS);
193+
ASSERT_TRUE(InsnStr.size() < (sizeof(StrBuffer) - 1));
194+
std::memcpy(StrBuffer, InsnStr.data(), InsnStr.size());
195+
StrBuffer[InsnStr.size()] = '\0';
196+
197+
if (Version == UC_VERSION_GFX10_DEFAULT)
198+
EXPECT_EQ(StringRef(StrBuffer), "\ts_version 4");
199+
else
200+
EXPECT_EQ(StringRef(StrBuffer), "\ts_version UC_VERSION_GFX10");
201+
}
202+
}

0 commit comments

Comments
 (0)