Index: include/llvm/CodeGen/TargetMachineVerifier.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/TargetMachineVerifier.h @@ -0,0 +1,82 @@ +//===-- TargetMachineVerifier.h - Machine Code Verifier -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Pass to verify target specific details of machine code. +// +// Based on MachineVerifier. Like that pass, it runs when -verify-machineinstrs +// is given and when MachineFunction::verify() is called. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TARGETMACHINEVERIFIER_H +#define LLVM_CODEGEN_TARGETMACHINEVERIFIER_H + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" + +namespace llvm { +class TargetMachineVerifier { +public: + TargetMachineVerifier(const char *Banner) : Banner(Banner) {} + virtual ~TargetMachineVerifier() {} + + /// Verify a given MF as well as the MBB's and MI's inside it. + unsigned verify(const MachineFunction &MF, const char *CallBanner = nullptr); + + /// Override this to add MF verification + virtual void verifyMF(const MachineFunction &MF, + const char *CallBanner = nullptr) {} + /// Override this to add MBB verification + virtual void verifyMBB(const MachineFunction &MF, + const MachineBasicBlock &MBB, + const char *CallBanner = nullptr) {} + /// Override this to add MI verification + virtual void verifyMI(const MachineFunction &MF, const MachineBasicBlock &MBB, + const MachineInstr &MI, + const char *CallBanner = nullptr) {} + +protected: + /// A banner to emit on error messages. + const char *Banner; + /// The number of errors discovered so far. + unsigned FoundErrors; + + /// These functions report a verification issue with the given object and + /// prints the error message along with the scope and parent scopes. + void report(const char *CallBanner, const char *Msg, + const MachineFunction &MF); + void report(const char *CallBanner, const char *Msg, + const MachineBasicBlock &MBB); + void report(const char *CallBanner, const char *Msg, const MachineInstr &MI); + void report(const char *CallBanner, const char *Msg, + const MachineOperand &MO); +}; + +template +struct TargetMachineVerifierPass : public MachineFunctionPass { + const std::string Banner; + + TargetMachineVerifierPass(char &ID, std::string banner = std::string()) + : MachineFunctionPass(ID), Banner(std::move(banner)) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + bool runOnMachineFunction(MachineFunction &MF) override { + unsigned FoundErrors = VerifierClass(Banner.c_str()).verify(MF); + if (FoundErrors) + report_fatal_error("Found " + Twine(FoundErrors) + + " machine code errors."); + return false; + } +}; +} // end namespace llvm + +#endif // ifndef LLVM_CODEGEN_TARGETMACHINEVERIFIER_H Index: include/llvm/CodeGen/TargetPassConfig.h =================================================================== --- include/llvm/CodeGen/TargetPassConfig.h +++ include/llvm/CodeGen/TargetPassConfig.h @@ -306,6 +306,10 @@ /// verification is enabled. void addVerifyPass(const std::string &Banner); + /// Add a pass to perform target specific verification of the machine function + /// if verification is enabled. + virtual void addTargetVerifyPass(const std::string &Banner) {} + /// Check whether or not GlobalISel should abort on error. /// When this is disabled, GlobalISel will fall back on SDISel instead of /// erroring out. Index: include/llvm/Target/TargetMachine.h =================================================================== --- include/llvm/Target/TargetMachine.h +++ include/llvm/Target/TargetMachine.h @@ -45,6 +45,7 @@ class TargetLoweringObjectFile; class TargetPassConfig; class TargetSubtargetInfo; +class TargetMachineVerifier; // The old pass manager infrastructure is hidden in a legacy namespace now. namespace legacy { @@ -362,6 +363,11 @@ /// EXPENSIVE_CHECKS is enabled. virtual bool isMachineVerifierClean() const { return true; } + // Return a TargetMachineVerifier* that MachineFunction::verify() can use. + virtual TargetMachineVerifier *getTargetMachineVerifier() const { + return nullptr; + } + /// Adds an AsmPrinter pass to the pipeline that prints assembly or /// machine code from the MI representation. bool addAsmPrinter(PassManagerBase &PM, raw_pwrite_stream &Out, Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -152,6 +152,7 @@ TargetInstrInfo.cpp TargetLoweringBase.cpp TargetLoweringObjectFileImpl.cpp + TargetMachineVerifier.cpp TargetOptionsImpl.cpp TargetPassConfig.cpp TargetRegisterInfo.cpp Index: lib/CodeGen/MachineVerifier.cpp =================================================================== --- lib/CodeGen/MachineVerifier.cpp +++ lib/CodeGen/MachineVerifier.cpp @@ -52,6 +52,7 @@ #include "llvm/CodeGen/SlotIndexes.h" #include "llvm/CodeGen/StackMaps.h" #include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetMachineVerifier.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -325,12 +326,22 @@ return new MachineVerifierPass(Banner); } -bool MachineFunction::verify(Pass *p, const char *Banner, bool AbortOnErrors) - const { +bool MachineFunction::verify(Pass *p, const char *Banner, + bool AbortOnErrors) const { MachineFunction &MF = const_cast(*this); unsigned FoundErrors = MachineVerifier(p, Banner).verify(MF); if (AbortOnErrors && FoundErrors) - report_fatal_error("Found "+Twine(FoundErrors)+" machine code errors."); + report_fatal_error("Found " + Twine(FoundErrors) + " machine code errors."); + + const LLVMTargetMachine &Target = MF.getTarget(); + TargetMachineVerifier *Verifier = Target.getTargetMachineVerifier(); + if (Verifier) { + FoundErrors = Verifier->verify(MF, Banner); + if (AbortOnErrors && FoundErrors) + report_fatal_error("Found " + Twine(FoundErrors) + + " target machine code errors."); + } + return FoundErrors == 0; } Index: lib/CodeGen/TargetMachineVerifier.cpp =================================================================== --- /dev/null +++ lib/CodeGen/TargetMachineVerifier.cpp @@ -0,0 +1,92 @@ +//===-- TargetMachineVerifier.cpp - Machine Code Verifier -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Interface to verify Target specific details of machine code. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/TargetMachineVerifier.h" + +using namespace llvm; + +unsigned TargetMachineVerifier::verify(const MachineFunction &MF, + const char *CallBanner) { + FoundErrors = 0; + + for (const auto &MBB : MF) { + verifyMBB(MF, MBB, CallBanner); + for (const auto &MI : MBB) + verifyMI(MF, MBB, MI, CallBanner); + } + + return FoundErrors; +} + +void TargetMachineVerifier::report(const char *CallBanner, const char *Msg, + const MachineFunction &MF) { + errs() << '\n'; + if (!FoundErrors++) { + if (Banner) + errs() << "# " << Banner << '\n'; + if (CallBanner) + errs() << "# " << CallBanner << '\n'; + } + errs() << "*** Bad machine code: " << Msg << " ***\n" + << "- function: " << MF.getName() << "\n"; +} + +void TargetMachineVerifier::report(const char *CallBanner, const char *Msg, + const MachineBasicBlock &MBB) { + errs() << '\n'; + if (!FoundErrors++) { + if (Banner) + errs() << "# " << Banner << '\n'; + if (CallBanner) + errs() << "# " << CallBanner << '\n'; + } + const MachineFunction &MF = *MBB.getParent(); + errs() << "*** Bad machine code: " << Msg << " ***\n" + << "- function: " << MF.getName() << "\n" + << "- basic block: " << MBB.getFullName() << "\n"; +} + +void TargetMachineVerifier::report(const char *CallBanner, const char *Msg, + const MachineInstr &MI) { + errs() << '\n'; + if (!FoundErrors++) { + if (Banner) + errs() << "# " << Banner << '\n'; + if (CallBanner) + errs() << "# " << CallBanner << '\n'; + } + const MachineBasicBlock &MBB = *MI.getParent(); + const MachineFunction &MF = *MBB.getParent(); + errs() << "*** Bad machine code: " << Msg << " ***\n" + << "- function: " << MF.getName() << "\n" + << "- basic block: " << MBB.getFullName() << "\n" + << "- instruction: " << MI; +} + +void TargetMachineVerifier::report(const char *CallBanner, const char *Msg, + const MachineOperand &MO) { + errs() << '\n'; + if (!FoundErrors++) { + if (Banner) + errs() << "# " << Banner << '\n'; + if (CallBanner) + errs() << "# " << CallBanner << '\n'; + } + const MachineInstr &MI = *MO.getParent(); + const MachineBasicBlock &MBB = *MI.getParent(); + const MachineFunction &MF = *MBB.getParent(); + errs() << "*** Bad machine code: " << Msg << " ***\n" + << "- function: " << MF.getName() << "\n" + << "- basic block: " << MBB.getFullName() << "\n" + << "- instruction: " << MI + << "- operand: " << MO << "\n"; +} Index: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -598,8 +598,10 @@ if (VerifyMachineCode == cl::BOU_UNSET) Verify = TM->isMachineVerifierClean(); #endif - if (Verify) + if (Verify) { PM->add(createMachineVerifierPass(Banner)); + addTargetVerifyPass(Banner); + } } /// Add common target configurable passes that perform LLVM IR to IR transforms Index: lib/Target/AArch64/AArch64.h =================================================================== --- lib/Target/AArch64/AArch64.h +++ lib/Target/AArch64/AArch64.h @@ -56,6 +56,7 @@ createAArch64InstructionSelector(const AArch64TargetMachine &, AArch64Subtarget &, AArch64RegisterBankInfo &); FunctionPass *createAArch64PreLegalizeCombiner(); +FunctionPass *createAArch64MachineVerifier(const std::string &Banner); void initializeAArch64A53Fix835769Pass(PassRegistry&); void initializeAArch64A57FPLoadBalancingPass(PassRegistry&); @@ -78,6 +79,7 @@ void initializeFalkorHWPFFixPass(PassRegistry&); void initializeFalkorMarkStridedAccessesLegacyPass(PassRegistry&); void initializeLDTLSCleanupPass(PassRegistry&); +void initializeAArch64MachineVerifierPassPass(PassRegistry&); } // end namespace llvm #endif Index: lib/Target/AArch64/AArch64MachineVerifier.h =================================================================== --- /dev/null +++ lib/Target/AArch64/AArch64MachineVerifier.h @@ -0,0 +1,32 @@ +//===-- AArch64MachineVerifier.h - Machine Code Verifier -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Pass to verify AArch64 specific details of machine code. +// +// Based on MachineVerifier. Like that pass, it runs when -verify-machineinstrs +// is given and when MachineFunction::verify() is called. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEVERIFIER_H +#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEVERIFIER_H + +#include "llvm/CodeGen/TargetMachineVerifier.h" + +namespace llvm { +struct AArch64MachineVerifier : public TargetMachineVerifier { + AArch64MachineVerifier(const char *Banner) : TargetMachineVerifier(Banner) {} + + void verifyMI(const MachineFunction &MF, const MachineBasicBlock &MBB, + const MachineInstr &MI, const char *CallBanner) override; + void verifyBitFieldMove(const MachineInstr &MI, unsigned SizeInBits, + const char *CallBanner); +}; +} // end namespace llvm + +#endif // ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEVERIFIER_H Index: lib/Target/AArch64/AArch64MachineVerifier.cpp =================================================================== --- /dev/null +++ lib/Target/AArch64/AArch64MachineVerifier.cpp @@ -0,0 +1,94 @@ +//===-- AArch64MachineVerifier.cpp - Machine Code Verifier -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Pass to verify AArch64 specific details of machine code. +// +// Based on MachineVerifier. Like that pass, it runs when -verify-machineinstrs +// is given and when MachineFunction::verify() is called. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetMachineVerifier.h" +#include "llvm/InitializePasses.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "AArch64.h" +#include "AArch64TargetMachine.h" + +using namespace llvm; + +namespace { +struct AArch64MachineVerifierPass : public TargetMachineVerifierPass { + static char ID; // Pass ID, replacement for typeid + + AArch64MachineVerifierPass(std::string Banner = std::string()) + : TargetMachineVerifierPass(ID, std::move(Banner)) { + initializeAArch64MachineVerifierPassPass(*PassRegistry::getPassRegistry()); + } +}; +char AArch64MachineVerifierPass::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS(AArch64MachineVerifierPass, "aarch64-machineverifier", + "Verify generated AArch64 machine code", false, false) + +FunctionPass *llvm::createAArch64MachineVerifier(const std::string &Banner) { + return new AArch64MachineVerifierPass(Banner); +} + +TargetMachineVerifier * +AArch64TargetMachine::getTargetMachineVerifier() const { + if (TgtMachineVerifier) + return TgtMachineVerifier.get(); + TgtMachineVerifier = make_unique(nullptr); + return TgtMachineVerifier.get(); +} +void AArch64MachineVerifier::verifyBitFieldMove(const MachineInstr &MI, + unsigned SizeInBits, + const char *CallBanner) { + if (MI.getOperand(2).isImm()) { + unsigned ImmR = MI.getOperand(2).getImm(); + if (ImmR < 0 || ImmR >= SizeInBits) + report(CallBanner, + ("Expected immediate in range 0 - " + to_string(SizeInBits - 1)) + .c_str(), + MI.getOperand(2)); + } else + report(CallBanner, "Expected immediate", MI.getOperand(2)); + + if (MI.getOperand(3).isImm()) { + unsigned ImmS = MI.getOperand(3).getImm(); + + if (ImmS < 0 || ImmS >= SizeInBits) + report(CallBanner, + ("Expected immediate in range 0 - " + to_string(SizeInBits - 1)) + .c_str(), + MI.getOperand(3)); + } else + report(CallBanner, "Expected immediate", MI.getOperand(3)); +} + +void AArch64MachineVerifier::verifyMI(const MachineFunction &MF, + const MachineBasicBlock &MBB, + const MachineInstr &MI, + const char *CallBanner) { + switch (MI.getOpcode()) { + case AArch64::SBFMWri: + case AArch64::UBFMWri: + verifyBitFieldMove(MI, 32, CallBanner); + break; + case AArch64::SBFMXri: + case AArch64::UBFMXri: + verifyBitFieldMove(MI, 64, CallBanner); + break; + } +} + Index: lib/Target/AArch64/AArch64TargetMachine.h =================================================================== --- lib/Target/AArch64/AArch64TargetMachine.h +++ lib/Target/AArch64/AArch64TargetMachine.h @@ -15,6 +15,7 @@ #include "AArch64InstrInfo.h" #include "AArch64Subtarget.h" +#include "AArch64MachineVerifier.h" #include "llvm/IR/DataLayout.h" #include "llvm/Target/TargetMachine.h" @@ -26,6 +27,7 @@ protected: std::unique_ptr TLOF; mutable StringMap> SubtargetMap; + mutable std::unique_ptr TgtMachineVerifier = nullptr; public: AArch64TargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -49,6 +51,9 @@ return TLOF.get(); } + TargetMachineVerifier * + getTargetMachineVerifier() const override; + private: bool isLittle; }; Index: lib/Target/AArch64/AArch64TargetMachine.cpp =================================================================== --- lib/Target/AArch64/AArch64TargetMachine.cpp +++ lib/Target/AArch64/AArch64TargetMachine.cpp @@ -385,6 +385,7 @@ void addPostRegAlloc() override; void addPreSched2() override; void addPreEmitPass() override; + void addTargetVerifyPass(const std::string &Banner) override; std::unique_ptr getCSEConfig() const override; }; @@ -610,3 +611,7 @@ TM->getTargetTriple().isOSBinFormatMachO()) addPass(createAArch64CollectLOHPass()); } + +void AArch64PassConfig::addTargetVerifyPass(const std::string &Banner) { + addPass(createAArch64MachineVerifier(Banner), false, false); +} Index: lib/Target/AArch64/CMakeLists.txt =================================================================== --- lib/Target/AArch64/CMakeLists.txt +++ lib/Target/AArch64/CMakeLists.txt @@ -61,6 +61,7 @@ AArch64TargetObjectFile.cpp AArch64TargetTransformInfo.cpp AArch64SIMDInstrOpt.cpp + AArch64MachineVerifier.cpp DEPENDS intrinsics_gen Index: test/Verifier/AArch64/lit.local.cfg =================================================================== --- /dev/null +++ test/Verifier/AArch64/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'AArch64' in config.root.targets: + config.unsupported = True Index: test/Verifier/AArch64/sbfm_ubfm.mir =================================================================== --- /dev/null +++ test/Verifier/AArch64/sbfm_ubfm.mir @@ -0,0 +1,107 @@ +# RUN: not llc -mtriple=aarch64-- -run-pass=none -verify-machineinstrs %s -o - 2>%t +# RUN: FileCheck %s < %t + +--- +name: fn +body: | + bb.0: + liveins: $w0, $w1, $x0, $x1 + + %0:gpr32 = COPY $w0 + %1:gpr32 = COPY $w1 + %2:gpr32 = SBFMWri %0, 2, 1 + $w0 = COPY %2:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, %vreg1, 1 + ; CHECK-NEXT: operand: %vreg1 + %3:gpr32 = SBFMWri %0, %1, 1 + $w1 = COPY %3:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, 2, %vreg1 + ; CHECK-NEXT: operand: %vreg1 + %3:gpr32 = SBFMWri %0, 2, %1 + $w1 = COPY %3:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, 32, 1 + ; CHECK-NEXT: operand: 32 + %3:gpr32 = SBFMWri %0, 32, 1 + $w1 = COPY %3:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, 0, 32 + ; CHECK-NEXT: operand: 32 + %3:gpr32 = SBFMWri %0, 0, 32 + $w1 = COPY %3:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, 64, 1 + ; CHECK-NEXT: operand: 64 + %3:gpr32 = SBFMWri %0, 64, 1 + $w1 = COPY %3:gpr32 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg3 = SBFMWri %vreg0, 0, 64 + ; CHECK-NEXT: operand: 64 + %3:gpr32 = SBFMWri %0, 0, 64 + $w1 = COPY %3:gpr32 + + %4:gpr64 = COPY $x0 + %5:gpr64 = COPY $x1 + %6:gpr64 = UBFMXri %4, 2, 1 + $x0 = COPY %6:gpr64 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg7 = UBFMXri %vreg4, %vreg5, 1 + ; CHECK-NEXT: operand: %vreg5 + %7:gpr64 = UBFMXri %4, %5, 1 + $x1 = COPY %7:gpr64 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg7 = UBFMXri %vreg4, 2, %vreg5 + ; CHECK-NEXT: operand: %vreg5 + %7:gpr64 = UBFMXri %4, 2, %5 + $x1 = COPY %7:gpr64 + + %7:gpr64 = UBFMXri %4, 32, 1 + $x1 = COPY %7:gpr64 + + %7:gpr64 = UBFMXri %4, 0, 32 + $x1 = COPY %7:gpr64 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg7 = UBFMXri %vreg4, 64, 1 + ; CHECK-NEXT: operand: 64 + %7:gpr64 = UBFMXri %4, 64, 1 + $x1 = COPY %7:gpr64 + + ; CHECK: Bad machine code: Expected immediate + ; CHECK-NEXT: function: fn + ; CHECK-NEXT: basic block: fn:BB0 + ; CHECK-NEXT: instruction: %vreg7 = UBFMXri %vreg4, 0, 64 + ; CHECK-NEXT: operand: 64 + %7:gpr64 = UBFMXri %4, 0, 64 + $x1 = COPY %7:gpr64 + + ; CHECK: LLVM ERROR: Found 10 target machine code errors. +... Index: unittests/CodeGen/GlobalISel/PatternMatchTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -509,6 +509,28 @@ match = mi_match(MIBAdd.getReg(0), MRI, m_OneUse(m_GAdd(m_Reg(), m_Reg()))); EXPECT_FALSE(match); } + +// This test isn't a pattern matcher but the boiler plate would be an exact +// duplicate of the code so lets just put it here. +TEST(TargetMachineVerifier, MachineFunctionVerify) { + LLVMContext Context; + std::unique_ptr TM = createTargetMachine(); + if (!TM) + return; + + auto ModuleMMIPair = createDummyModule(Context, *TM, R"MIR( + %4:gpr64 = COPY %0 + %5:gpr64 = SBFMXri %4, 63, 1 +)MIR"); + MachineFunction *MF = + getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get()); + MachineBasicBlock &MBB = *MF->begin(); + MachineInstr &MI = *(std::prev(MBB.end())); + // Break the instruction by changing the immediate to be out of range + MI.getOperand(2).setImm(64); + EXPECT_FALSE(MF->verify(nullptr, "Banner", false)); +} + } // namespace int main(int argc, char **argv) {