Files
revng-revng/lib/Lift/PostLiftVerifyPass.cpp
Alessandro Di Federico b1feb5b989 Introduce libtcg
This commit drops libptc in favor of its new form libtcg.

It brings several improvements, among which:

* The QEMU version we work on has been upgraded.
* CPUStateAccessAnalysis has been reimplemented in a way that makes it
  easier to debug and solves some limitations (e.g., tracking leaking
  pointers).
* Identification of pieces of the CPU state that are read by each helper
  and fixing access to the CPU state is now performed at build-time.
* We no longer mmap the code we need to translate, dropping all the
  issues related to code that needed to be mapped where something is
  already present.
* We now have two distinct flavors of helper modules: the full one and
  the "slim" one. The latter contains the definition only of functions
  we intend to inline. It is used in most of the pipeline, a good thing
  since we spend less time optimizing code we don't really care about.
  The full module is only used on the re-compilation branch of the
  pipeline.
* We no longer split the `cpu_loop` function.
* We change MetaAddress to rely on architectures from `model::` as
  opposed to the LLVM ones.
* We no longer attach debug info to LLVM IR containing the original
  assembly.
* We now verify that the lifted code only contains code we expect.
2025-10-31 14:49:05 +01:00

126 lines
3.2 KiB
C++

/// \file PostLiftVerifyPass.cpp
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "revng/Support/Assert.h"
#include "PostLiftVerifyPass.h"
using namespace llvm;
bool PostLiftVerifyPass::runOnModule(Module &M) {
Function *RootFunction = M.getFunction("root");
revng_assert(RootFunction != nullptr);
llvm::ModuleSlotTracker MST(&M, false);
for (BasicBlock &BB : *RootFunction) {
// Ignore some special basic blocks
if (BB.getName() == "dispatcher.default"
or BB.getName() == "serialize_and_jump_out"
or BB.getName() == "return_from_external" or BB.getName() == "setjmp"
or BB.getName() == "dispatcher.external")
continue;
for (Instruction &I : BB) {
bool Good = false;
switch (I.getOpcode()) {
case Instruction::Store:
case Instruction::Load:
Good = true;
break;
case Instruction::IntToPtr:
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
case Instruction::SRem:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
case Instruction::ZExt:
case Instruction::Trunc:
case Instruction::SExt:
case Instruction::ICmp:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::Shl:
case Instruction::Select:
Good = true;
break;
case Instruction::Br:
case Instruction::Switch:
case Instruction::Unreachable:
Good = true;
break;
case Instruction::PHI:
Good = true;
break;
case Instruction::ExtractValue:
Good = true;
break;
case Instruction::Call:
// Make further checks
auto *Call = cast<CallInst>(&I);
Value *CalledOperand = Call->getCalledOperand();
Function *Callee = dyn_cast_or_null<Function>(CalledOperand);
StringRef CalleeName;
if (Callee != nullptr)
CalleeName = Callee->getName();
Good = (CalleeName == "newpc" or CalleeName == "jump_to_symbol"
or CalleeName.startswith("helper_")
or CalleeName == "function_call"
or CalleeName == "helper_initialize_env"
or CalleeName == "revng_abort");
switch (Callee->getIntrinsicID()) {
case Intrinsic::fshl:
case Intrinsic::fshr:
case Intrinsic::bswap:
case Intrinsic::abs:
case Intrinsic::umin:
case Intrinsic::umax:
case Intrinsic::smin:
case Intrinsic::smax:
case Intrinsic::ctlz:
case Intrinsic::cttz:
Good = true;
}
break;
}
if (not Good) {
std::string Buffer;
{
llvm::raw_string_ostream Stream(Buffer);
Stream << "Unexpected instruction: ";
I.print(Stream, MST);
Stream << "\n";
}
revng_abort(Buffer.c_str());
}
}
}
return false;
}
char PostLiftVerifyPass::ID;