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 } 208