209 lines · cpp
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-exception6//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 25using namespace llvm;26 27static 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 35static constexpr char TripleName[] = "amdgcn--amdpal";36static constexpr char CPUName[] = "gfx1030";37 38// Basic smoke test.39TEST(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.68TEST(AMDGPUDisassembler, MultiDisassembler) {69 LLVMInitializeAMDGPUTargetInfo();70 LLVMInitializeAMDGPUTargetMC();71 LLVMInitializeAMDGPUDisassembler();72 73 std::string Error;74 Triple TT(TripleName);75 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);76 77 // Skip test if AMDGPU not built.78 if (!TheTarget)79 GTEST_SKIP();80 81 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));82 std::unique_ptr<MCAsmInfo> MAI(83 TheTarget->createMCAsmInfo(*MRI, TT, MCTargetOptions()));84 std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());85 std::unique_ptr<MCSubtargetInfo> STI(86 TheTarget->createMCSubtargetInfo(TT, CPUName, ""));87 auto Ctx = std::make_unique<MCContext>(TT, MAI.get(), MRI.get(), STI.get());88 89 int AsmPrinterVariant = MAI->getAssemblerDialect();90 std::unique_ptr<MCInstPrinter> IP(91 TheTarget->createMCInstPrinter(TT, 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.138TEST(AMDGPUDisassembler, UCVersionOverride) {139 LLVMInitializeAMDGPUTargetInfo();140 LLVMInitializeAMDGPUTargetMC();141 LLVMInitializeAMDGPUDisassembler();142 143 Triple TT(TripleName);144 145 std::string Error;146 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);147 148 // Skip test if AMDGPU not built.149 if (!TheTarget)150 GTEST_SKIP();151 152 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));153 std::unique_ptr<MCAsmInfo> MAI(154 TheTarget->createMCAsmInfo(*MRI, TT, MCTargetOptions()));155 std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());156 std::unique_ptr<MCSubtargetInfo> STI(157 TheTarget->createMCSubtargetInfo(TT, CPUName, ""));158 auto Ctx = std::make_unique<MCContext>(TT, MAI.get(), MRI.get(), STI.get());159 160 // Define custom UC_VERSION before initializing disassembler.161 const uint8_t UC_VERSION_GFX10_DEFAULT = 0x04;162 const uint8_t UC_VERSION_GFX10_NEW = 0x99;163 auto Sym = Ctx->getOrCreateSymbol("UC_VERSION_GFX10");164 Sym->setVariableValue(MCConstantExpr::create(UC_VERSION_GFX10_NEW, *Ctx));165 166 int AsmPrinterVariant = MAI->getAssemblerDialect();167 std::unique_ptr<MCInstPrinter> IP(168 TheTarget->createMCInstPrinter(TT, AsmPrinterVariant, *MAI, *MII, *MRI));169 170 testing::internal::CaptureStderr();171 std::unique_ptr<MCDisassembler> DisAsm(172 TheTarget->createMCDisassembler(*STI, *Ctx));173 std::string Output = testing::internal::GetCapturedStderr();174 EXPECT_TRUE(Output.find("<unknown>:0: warning: unsupported redefinition of "175 "UC_VERSION_GFX10") != std::string::npos);176 177 SmallVector<char, 64> InsnStr, AnnoStr;178 raw_svector_ostream OS(InsnStr);179 raw_svector_ostream Annotations(AnnoStr);180 formatted_raw_ostream FormattedOS(OS);181 182 char StrBuffer[128];183 184 // Decode S_VERSION instruction with original or custom version.185 uint8_t Versions[] = {UC_VERSION_GFX10_DEFAULT, UC_VERSION_GFX10_NEW};186 for (uint8_t Version : Versions) {187 uint8_t Bytes[] = {Version, 0x00, 0x80, 0xb0};188 uint64_t InstSize = 0U;189 MCInst Inst;190 191 AnnoStr.clear();192 InsnStr.clear();193 MCDisassembler::DecodeStatus Status =194 DisAsm->getInstruction(Inst, InstSize, Bytes, 0, Annotations);195 ASSERT_TRUE(Status == MCDisassembler::Success);196 EXPECT_EQ(InstSize, 4U);197 198 IP->printInst(&Inst, 0, Annotations.str(), *STI, FormattedOS);199 ASSERT_TRUE(InsnStr.size() < (sizeof(StrBuffer) - 1));200 std::memcpy(StrBuffer, InsnStr.data(), InsnStr.size());201 StrBuffer[InsnStr.size()] = '\0';202 203 if (Version == UC_VERSION_GFX10_DEFAULT)204 EXPECT_EQ(StringRef(StrBuffer), "\ts_version UC_VERSION_GFX10");205 else206 EXPECT_EQ(StringRef(StrBuffer), "\ts_version 153");207 }208}209