448 lines · cpp
1//===- MachineOperandTest.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/CodeGen/MachineOperand.h"10#include "llvm/ADT/ilist_node.h"11#include "llvm/CodeGen/CodeGenTargetMachineImpl.h"12#include "llvm/CodeGen/MachineFunction.h"13#include "llvm/CodeGen/MachineModuleInfo.h"14#include "llvm/CodeGen/TargetFrameLowering.h"15#include "llvm/CodeGen/TargetInstrInfo.h"16#include "llvm/CodeGen/TargetLowering.h"17#include "llvm/CodeGenTypes/LowLevelType.h"18#include "llvm/IR/Constants.h"19#include "llvm/IR/InstrTypes.h"20#include "llvm/IR/LLVMContext.h"21#include "llvm/IR/Module.h"22#include "llvm/IR/ModuleSlotTracker.h"23#include "llvm/MC/MCAsmInfo.h"24#include "llvm/MC/MCContext.h"25#include "llvm/MC/TargetRegistry.h"26#include "llvm/Support/raw_ostream.h"27#include "gtest/gtest.h"28 29using namespace llvm;30 31namespace {32 33// Include helper functions to ease the manipulation of MachineFunctions.34#include "MFCommon.inc"35 36TEST(MachineOperandTest, ChangeToTargetIndexTest) {37 // Creating a MachineOperand to change it to TargetIndex38 MachineOperand MO = MachineOperand::CreateImm(50);39 40 // Checking some precondition on the newly created41 // MachineOperand.42 ASSERT_TRUE(MO.isImm());43 ASSERT_TRUE(MO.getImm() == 50);44 ASSERT_FALSE(MO.isTargetIndex());45 46 // Changing to TargetIndex with some arbitrary values47 // for index, offset and flags.48 MO.ChangeToTargetIndex(74, 57, 12);49 50 // Checking that the mutation to TargetIndex happened51 // correctly.52 ASSERT_TRUE(MO.isTargetIndex());53 ASSERT_TRUE(MO.getIndex() == 74);54 ASSERT_TRUE(MO.getOffset() == 57);55 ASSERT_TRUE(MO.getTargetFlags() == 12);56}57 58TEST(MachineOperandTest, PrintRegisterMask) {59 LLVMContext Ctx;60 Module Mod("Module", Ctx);61 auto MF = createMachineFunction(Ctx, Mod);62 63 uint32_t *Dummy = MF->allocateRegMask();64 MachineOperand MO = MachineOperand::CreateRegMask(Dummy);65 66 // Checking some preconditions on the newly created67 // MachineOperand.68 ASSERT_TRUE(MO.isRegMask());69 ASSERT_TRUE(MO.getRegMask() == Dummy);70 71 // Print a MachineOperand containing a RegMask. Here we check that without a72 // TRI we still print a less detailed regmask.73 std::string str;74 raw_string_ostream OS(str);75 MO.print(OS, /*TRI=*/nullptr);76 ASSERT_TRUE(str == "<regmask ...>");77}78 79TEST(MachineOperandTest, PrintSubReg) {80 // Create a MachineOperand with RegNum=1 and SubReg=5.81 MachineOperand MO = MachineOperand::CreateReg(82 /*Reg=*/1, /*isDef=*/false, /*isImp=*/false, /*isKill=*/false,83 /*isDead=*/false, /*isUndef=*/false, /*isEarlyClobber=*/false,84 /*SubReg=*/5, /*isDebug=*/false, /*isInternalRead=*/false);85 86 // Checking some preconditions on the newly created87 // MachineOperand.88 ASSERT_TRUE(MO.isReg());89 ASSERT_TRUE(MO.getReg() == 1);90 ASSERT_TRUE(MO.getSubReg() == 5);91 92 // Print a MachineOperand containing a SubReg. Here we check that without a93 // TRI we can still print the subreg index.94 std::string str;95 raw_string_ostream OS(str);96 MO.print(OS, /*TRI=*/nullptr);97 ASSERT_TRUE(str == "$physreg1.subreg5");98}99 100TEST(MachineOperandTest, PrintCImm) {101 LLVMContext Context;102 APInt Int(128, UINT64_MAX);103 ++Int;104 ConstantInt *CImm = ConstantInt::get(Context, Int);105 // Create a MachineOperand with an Imm=(UINT64_MAX + 1)106 MachineOperand MO = MachineOperand::CreateCImm(CImm);107 108 // Checking some preconditions on the newly created109 // MachineOperand.110 ASSERT_TRUE(MO.isCImm());111 ASSERT_TRUE(MO.getCImm() == CImm);112 ASSERT_TRUE(MO.getCImm()->getValue() == Int);113 114 // Print a MachineOperand containing a SubReg. Here we check that without a115 // TRI we can still print the subreg index.116 std::string str;117 raw_string_ostream OS(str);118 MO.print(OS, /*TRI=*/nullptr);119 ASSERT_TRUE(str == "i128 18446744073709551616");120}121 122TEST(MachineOperandTest, PrintSubRegIndex) {123 // Create a MachineOperand with an immediate and print it as a subreg index.124 MachineOperand MO = MachineOperand::CreateImm(3);125 126 // Checking some preconditions on the newly created127 // MachineOperand.128 ASSERT_TRUE(MO.isImm());129 ASSERT_TRUE(MO.getImm() == 3);130 131 // Print a MachineOperand containing a SubRegIdx. Here we check that without a132 // TRI we can print the operand as a subreg index.133 std::string str;134 raw_string_ostream OS(str);135 MachineOperand::printSubRegIdx(OS, MO.getImm(), nullptr);136 ASSERT_TRUE(str == "%subreg.3");137}138 139TEST(MachineOperandTest, PrintCPI) {140 // Create a MachineOperand with a constant pool index and print it.141 MachineOperand MO = MachineOperand::CreateCPI(0, 8);142 143 // Checking some preconditions on the newly created144 // MachineOperand.145 ASSERT_TRUE(MO.isCPI());146 ASSERT_TRUE(MO.getIndex() == 0);147 ASSERT_TRUE(MO.getOffset() == 8);148 149 // Print a MachineOperand containing a constant pool index and a positive150 // offset.151 std::string str;152 {153 raw_string_ostream OS(str);154 MO.print(OS, /*TRI=*/nullptr);155 ASSERT_TRUE(str == "%const.0 + 8");156 }157 158 str.clear();159 160 MO.setOffset(-12);161 162 // Print a MachineOperand containing a constant pool index and a negative163 // offset.164 {165 raw_string_ostream OS(str);166 MO.print(OS, /*TRI=*/nullptr);167 ASSERT_TRUE(str == "%const.0 - 12");168 }169}170 171TEST(MachineOperandTest, PrintTargetIndexName) {172 // Create a MachineOperand with a target index and print it.173 MachineOperand MO = MachineOperand::CreateTargetIndex(0, 8);174 175 // Checking some preconditions on the newly created176 // MachineOperand.177 ASSERT_TRUE(MO.isTargetIndex());178 ASSERT_TRUE(MO.getIndex() == 0);179 ASSERT_TRUE(MO.getOffset() == 8);180 181 // Print a MachineOperand containing a target index and a positive offset.182 std::string str;183 {184 raw_string_ostream OS(str);185 MO.print(OS, /*TRI=*/nullptr);186 ASSERT_TRUE(str == "target-index(<unknown>) + 8");187 }188 189 str.clear();190 191 MO.setOffset(-12);192 193 // Print a MachineOperand containing a target index and a negative offset.194 {195 raw_string_ostream OS(str);196 MO.print(OS, /*TRI=*/nullptr);197 ASSERT_TRUE(str == "target-index(<unknown>) - 12");198 }199}200 201TEST(MachineOperandTest, PrintJumpTableIndex) {202 // Create a MachineOperand with a jump-table index and print it.203 MachineOperand MO = MachineOperand::CreateJTI(3);204 205 // Checking some preconditions on the newly created206 // MachineOperand.207 ASSERT_TRUE(MO.isJTI());208 ASSERT_TRUE(MO.getIndex() == 3);209 210 // Print a MachineOperand containing a jump-table index.211 std::string str;212 raw_string_ostream OS(str);213 MO.print(OS, /*TRI=*/nullptr);214 ASSERT_TRUE(str == "%jump-table.3");215}216 217TEST(MachineOperandTest, PrintExternalSymbol) {218 // Create a MachineOperand with an external symbol and print it.219 MachineOperand MO = MachineOperand::CreateES("foo");220 221 // Checking some preconditions on the newly created222 // MachineOperand.223 ASSERT_TRUE(MO.isSymbol());224 ASSERT_TRUE(MO.getSymbolName() == StringRef("foo"));225 226 // Print a MachineOperand containing an external symbol and no offset.227 std::string str;228 {229 raw_string_ostream OS(str);230 MO.print(OS, /*TRI=*/nullptr);231 ASSERT_TRUE(str == "&foo");232 }233 234 str.clear();235 MO.setOffset(12);236 237 // Print a MachineOperand containing an external symbol and a positive offset.238 {239 raw_string_ostream OS(str);240 MO.print(OS, /*TRI=*/nullptr);241 ASSERT_TRUE(str == "&foo + 12");242 }243 244 str.clear();245 MO.setOffset(-12);246 247 // Print a MachineOperand containing an external symbol and a negative offset.248 {249 raw_string_ostream OS(str);250 MO.print(OS, /*TRI=*/nullptr);251 ASSERT_TRUE(str == "&foo - 12");252 }253}254 255TEST(MachineOperandTest, PrintGlobalAddress) {256 LLVMContext Ctx;257 Module M("MachineOperandGVTest", Ctx);258 M.getOrInsertGlobal("foo", Type::getInt32Ty(Ctx));259 260 GlobalValue *GV = M.getNamedValue("foo");261 262 // Create a MachineOperand with a global address and a positive offset and263 // print it.264 MachineOperand MO = MachineOperand::CreateGA(GV, 12);265 266 // Checking some preconditions on the newly created267 // MachineOperand.268 ASSERT_TRUE(MO.isGlobal());269 ASSERT_TRUE(MO.getGlobal() == GV);270 ASSERT_TRUE(MO.getOffset() == 12);271 272 std::string str;273 // Print a MachineOperand containing a global address and a positive offset.274 {275 raw_string_ostream OS(str);276 MO.print(OS, /*TRI=*/nullptr);277 ASSERT_TRUE(str == "@foo + 12");278 }279 280 str.clear();281 MO.setOffset(-12);282 283 // Print a MachineOperand containing a global address and a negative offset.284 {285 raw_string_ostream OS(str);286 MO.print(OS, /*TRI=*/nullptr);287 ASSERT_TRUE(str == "@foo - 12");288 }289}290 291TEST(MachineOperandTest, PrintRegisterLiveOut) {292 // Create a MachineOperand with a register live out list and print it.293 uint32_t Mask = 0;294 MachineOperand MO = MachineOperand::CreateRegLiveOut(&Mask);295 296 // Checking some preconditions on the newly created297 // MachineOperand.298 ASSERT_TRUE(MO.isRegLiveOut());299 ASSERT_TRUE(MO.getRegLiveOut() == &Mask);300 301 std::string str;302 // Print a MachineOperand containing a register live out list without a TRI.303 raw_string_ostream OS(str);304 MO.print(OS, /*TRI=*/nullptr);305 ASSERT_TRUE(str == "liveout(<unknown>)");306}307 308TEST(MachineOperandTest, PrintMetadata) {309 LLVMContext Ctx;310 Module M("MachineOperandMDNodeTest", Ctx);311 NamedMDNode *MD = M.getOrInsertNamedMetadata("namedmd");312 ModuleSlotTracker MST(&M);313 Metadata *MDS = MDString::get(Ctx, "foo");314 MDNode *Node = MDNode::get(Ctx, MDS);315 MD->addOperand(Node);316 317 // Create a MachineOperand with a metadata and print it.318 MachineOperand MO = MachineOperand::CreateMetadata(Node);319 320 // Checking some preconditions on the newly created321 // MachineOperand.322 ASSERT_TRUE(MO.isMetadata());323 ASSERT_TRUE(MO.getMetadata() == Node);324 325 std::string str;326 // Print a MachineOperand containing a metadata node.327 raw_string_ostream OS(str);328 MO.print(OS, MST, LLT{}, /*OpIdx*/ ~0U, /*PrintDef=*/false,329 /*IsStandalone=*/false,330 /*ShouldPrintRegisterTies=*/false, 0, /*TRI=*/nullptr);331 ASSERT_TRUE(str == "!0");332}333 334TEST(MachineOperandTest, PrintMCSymbol) {335 MCAsmInfo MAI;336 Triple T = Triple("unknown-unknown-unknown");337 MCContext Ctx(T, &MAI, /*MRI=*/nullptr, /*MSTI=*/nullptr);338 MCSymbol *Sym = Ctx.getOrCreateSymbol("foo");339 340 // Create a MachineOperand with a metadata and print it.341 MachineOperand MO = MachineOperand::CreateMCSymbol(Sym);342 343 // Checking some preconditions on the newly created344 // MachineOperand.345 ASSERT_TRUE(MO.isMCSymbol());346 ASSERT_TRUE(MO.getMCSymbol() == Sym);347 348 std::string str;349 // Print a MachineOperand containing a metadata node.350 raw_string_ostream OS(str);351 MO.print(OS, /*TRI=*/nullptr);352 ASSERT_TRUE(str == "<mcsymbol foo>");353}354 355TEST(MachineOperandTest, PrintCFI) {356 // Create a MachineOperand with a CFI index but no function and print it.357 MachineOperand MO = MachineOperand::CreateCFIIndex(8);358 359 // Checking some preconditions on the newly created360 // MachineOperand.361 ASSERT_TRUE(MO.isCFIIndex());362 ASSERT_TRUE(MO.getCFIIndex() == 8);363 364 std::string str;365 // Print a MachineOperand containing a CFI Index node but no machine function366 // attached to it.367 raw_string_ostream OS(str);368 MO.print(OS, /*TRI=*/nullptr);369 ASSERT_TRUE(str == "<cfi directive>");370}371 372TEST(MachineOperandTest, PrintIntrinsicID) {373 // Create a MachineOperand with a generic intrinsic ID.374 MachineOperand MO = MachineOperand::CreateIntrinsicID(Intrinsic::bswap);375 376 // Checking some preconditions on the newly created377 // MachineOperand.378 ASSERT_TRUE(MO.isIntrinsicID());379 ASSERT_TRUE(MO.getIntrinsicID() == Intrinsic::bswap);380 381 std::string str;382 {383 // Print a MachineOperand containing a generic intrinsic ID.384 raw_string_ostream OS(str);385 MO.print(OS, /*TRI=*/nullptr);386 ASSERT_TRUE(str == "intrinsic(@llvm.bswap)");387 }388 389 str.clear();390 // Set a target-specific intrinsic.391 MO = MachineOperand::CreateIntrinsicID((Intrinsic::ID)-1);392 {393 // Print a MachineOperand containing a target-specific intrinsic ID but not394 // IntrinsicInfo.395 raw_string_ostream OS(str);396 MO.print(OS, /*TRI=*/nullptr);397 ASSERT_TRUE(str == "intrinsic(4294967295)");398 }399}400 401TEST(MachineOperandTest, PrintPredicate) {402 // Create a MachineOperand with a generic intrinsic ID.403 MachineOperand MO = MachineOperand::CreatePredicate(CmpInst::ICMP_EQ);404 405 // Checking some preconditions on the newly created406 // MachineOperand.407 ASSERT_TRUE(MO.isPredicate());408 ASSERT_TRUE(MO.getPredicate() == CmpInst::ICMP_EQ);409 410 std::string str;411 // Print a MachineOperand containing a int predicate ICMP_EQ.412 raw_string_ostream OS(str);413 MO.print(OS, /*TRI=*/nullptr);414 ASSERT_TRUE(str == "intpred(eq)");415}416 417TEST(MachineOperandTest, HashValue) {418 char SymName1[] = "test";419 char SymName2[] = "test";420 MachineOperand MO1 = MachineOperand::CreateES(SymName1);421 MachineOperand MO2 = MachineOperand::CreateES(SymName2);422 ASSERT_NE(SymName1, SymName2);423 ASSERT_EQ(hash_value(MO1), hash_value(MO2));424 ASSERT_TRUE(MO1.isIdenticalTo(MO2));425}426 427TEST(MachineOperandTest, RegisterLiveOutHashValue) {428 LLVMContext Ctx;429 Module Mod("Module", Ctx);430 auto MF = createMachineFunction(Ctx, Mod);431 MachineBasicBlock *MBB = MF->CreateMachineBasicBlock();432 MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};433 auto *MI1 = MF->CreateMachineInstr(MCID, DebugLoc());434 auto *MI2 = MF->CreateMachineInstr(MCID, DebugLoc());435 MBB->insert(MBB->begin(), MI1);436 MBB->insert(MBB->begin(), MI2);437 uint32_t Mask1 = 0;438 uint32_t Mask2 = 0;439 MI1->addOperand(*MF, MachineOperand::CreateRegLiveOut(&Mask1));440 MI2->addOperand(*MF, MachineOperand::CreateRegLiveOut(&Mask2));441 auto MO1 = MI1->getOperand(0);442 auto MO2 = MI2->getOperand(0);443 EXPECT_EQ(hash_value(MO1), hash_value(MO2));444 EXPECT_TRUE(MO1.isIdenticalTo(MO2));445}446 447} // end namespace448