Merge branch feature/promote-init-csv-to-undef

This commit is contained in:
Pietro Fezzardi
2022-05-31 12:51:59 +02:00
10 changed files with 196 additions and 57 deletions
+1
View File
@@ -106,3 +106,4 @@ ${CMAKE_BINARY_DIR}/${ASSETS_DIR}/recompilation-headers/
-Wno-incompatible-pointer-types
-Wno-null-pointer-arithmetic
-Wno-non-literal-null-conversion
-Wno-null-dereference
+75 -47
View File
@@ -192,22 +192,18 @@ static StringToken buildAddressExpr(const llvm::Twine &Expr) {
static StringToken buildCastExpr(StringRef ExprToCast,
const model::QualifiedType &SrcType,
const model::QualifiedType &DestType) {
StringToken Result = ExprToCast;
if (SrcType == DestType or not SrcType.UnqualifiedType.isValid()
or not SrcType.UnqualifiedType.isValid())
return ExprToCast;
return Result;
StringToken CastString;
revng_assert((SrcType.isScalar() or SrcType.isPointer())
and (DestType.isScalar() or DestType.isPointer()));
if ((SrcType.isScalar() or SrcType.isPointer())
and (DestType.isScalar() or DestType.isPointer()))
CastString = (addParentheses(getTypeName(DestType))
+ addParentheses(ExprToCast))
.str();
else
CastString = buildDerefExpr(addParentheses(getTypeName(DestType) + " *")
+ buildAddressExpr(ExprToCast));
Result.assign(addParentheses(getTypeName(DestType)));
Result.append(addParentheses(ExprToCast));
return CastString;
return Result;
}
/// Return a string that represents a C assignment:
@@ -231,7 +227,7 @@ static StringToken buildAssignmentExpr(const model::QualifiedType &LHSType,
AssignmentStr += LHSToken;
AssignmentStr += " = ";
AssignmentStr += buildCastExpr(RHSToken, LHSType, RHSType);
AssignmentStr += buildCastExpr(RHSToken, RHSType, LHSType);
return AssignmentStr;
}
@@ -467,15 +463,27 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) {
}
revng_assert(not Operand->getType()->isVoidTy());
if (auto *Undef = dyn_cast<llvm::UndefValue>(Operand)) {
revng_assert(Undef->getType()->isIntOrPtrTy());
TokenMap[Operand] = "0 /* undef */";
rc_return true;
}
if (auto *Null = dyn_cast<llvm::ConstantPointerNull>(Operand)) {
TokenMap[Operand] = "NULL";
rc_return true;
}
if (auto *Glob = dyn_cast<llvm::GlobalVariable>(Operand)) {
TokenMap[Operand] = Glob->getNameOrAsOperand();
rc_return true;
}
if (auto *Const = dyn_cast<llvm::ConstantInt>(Operand)) {
llvm::APInt Value = Const->getValue();
if (Value.isIntN(64)) {
// TODO: Decide how to print constants
Value.toString(TokenMap[Operand],
/*radix=*/10,
/*signed=*/false,
/*formatAsCLiteral=*/true);
TokenMap[Operand] = to_string(Value.getLimitedValue());
} else {
// In C, even if you can have 128-bit variables, you cannot have 128-bit
// literals, so we need this hack to assign a big constant value to a
@@ -500,13 +508,10 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) {
TokenMap[Operand] = addParentheses(CompositeConstant).str();
}
} else if (auto *Null = dyn_cast<llvm::ConstantPointerNull>(Operand)) {
TokenMap[Operand] = "NULL";
rc_return true;
}
} else if (auto *Glob = dyn_cast<llvm::GlobalVariable>(Operand)) {
TokenMap[Operand] = Glob->getNameOrAsOperand();
} else if (auto *ConstExpr = dyn_cast<llvm::ConstantExpr>(Operand)) {
if (auto *ConstExpr = dyn_cast<llvm::ConstantExpr>(Operand)) {
// A constant expression might have its own uninitialized constant operands
for (const llvm::Value *Op : ConstExpr->operand_values())
rc_recur addOperandToken(Op);
@@ -532,11 +537,10 @@ CCodeGenerator::addOperandToken(const llvm::Value *Operand) {
rc_return false;
}
} else {
rc_return false;
rc_return true;
}
rc_return true;
rc_return false;
}
StringToken CCodeGenerator::handleSpecialFunction(const llvm::CallInst *Call) {
@@ -877,32 +881,56 @@ StringToken CCodeGenerator::buildExpression(const llvm::Instruction &I) {
const llvm::Value *PointerOp = Store->getPointerOperand();
const llvm::Value *ValueOp = Store->getValueOperand();
// The LHS side of a store has the same type of the object pointed by the
// pointer operand
const QualifiedType PointedType = dropPointer(TypeMap.at(PointerOp));
const QualifiedType &PointerType = TypeMap.at(PointerOp);
const QualifiedType &StoredType = TypeMap.at(ValueOp);
if (StoredType.UnqualifiedType.isValid() and StoredType.isScalar()
and not PointedType.is(model::TypeKind::PrimitiveType)) {
// If we are storing a scalar value into a pointer to a struct, union or
// pointer, cast the LHS to the scalar type before assigning it
QualifiedType StoredPtrType = StoredType;
addPointerQualifier(StoredPtrType, Model);
StringToken CastedToken = buildCastExpr(TokenMap.at(PointerOp),
TypeMap.at(PointerOp),
StoredPtrType);
Expression = buildAssignmentExpr(StoredType,
buildDerefExpr(CastedToken),
StoredType,
TokenMap.at(ValueOp),
/*WithDeclaration=*/false);
StringToken PointerOperandExpr = TokenMap.at(PointerOp);
QualifiedType DerefPointedType;
StringToken PointerExprToDeref;
// This may be false if the pointer is null, because in that case we emit
// NULL, whose type is integer
bool PointerOperandIsInteger = not PointerType.isPointer();
if (PointerOperandIsInteger) {
// The pointer operand does not contain enough information to figure out
// the type of the pointee. In this sense the pointer is integer, because
// it's just a bag of bytes without useful type information. In this case
// we want the stored value to determine the type pointed-to by the
// pointer.
DerefPointedType = StoredType;
QualifiedType DerefPointerType = DerefPointedType;
addPointerQualifier(DerefPointerType, Model);
revng_assert(DerefPointerType.verify());
PointerExprToDeref = buildCastExpr(PointerOperandExpr,
PointerType,
DerefPointerType);
} else {
Expression = buildAssignmentExpr(PointedType,
buildDerefExpr(TokenMap.at(PointerOp)),
StoredType,
TokenMap.at(ValueOp),
/*WithDeclaration=*/false);
// Otherwise the type pointed-to by the pointer operand can be obtained
// just dropping the pointer qualifier.
DerefPointedType = dropPointer(PointerType);
PointerExprToDeref = PointerOperandExpr;
if (StoredType.UnqualifiedType.isValid() and StoredType.isScalar()
and not DerefPointedType.is(model::TypeKind::PrimitiveType)) {
// If we are storing a scalar value into a pointer to a struct, union or
// pointer, cast the LHS to the scalar type before assigning it
DerefPointedType = StoredType;
QualifiedType DerefPointerType = StoredType;
addPointerQualifier(DerefPointerType, Model);
revng_assert(DerefPointerType.verify());
PointerExprToDeref = buildCastExpr(PointerOperandExpr,
PointerType,
DerefPointerType);
}
}
revng_assert(DerefPointedType.verify());
Expression = buildAssignmentExpr(DerefPointedType,
buildDerefExpr(PointerExprToDeref),
StoredType,
TokenMap.at(ValueOp),
/*WithDeclaration=*/false);
} else if (auto *Select = dyn_cast<llvm::SelectInst>(&I)) {
@@ -1927,6 +1927,16 @@ makeGEPReplacements(llvm::Function &F, const model::Binary &Model) {
}
}
// Skip null pointer constants, and undefs, since they cannot be valid
// addresses
// TODO: if we ever need to support memory mapped at address 0 we can
// probably work around this, but this is not top priority for now.
if (isa<llvm::UndefValue>(U.get())
or isa<llvm::ConstantPointerNull>(U.get())) {
revng_log(ModelGEPLog, "Skipping null pointer address");
continue;
}
ModelGEPSummation GEPSum = GEPSumCache.getGEPSummation(U, PointerTypes);
revng_log(ModelGEPLog, "GEPSum " << GEPSum);
+12 -5
View File
@@ -128,10 +128,11 @@ static RecursiveCoroutine<bool> addOperandType(const llvm::Value *Operand,
}
}
} else if (isa<llvm::ConstantInt>(Operand)
or isa<llvm::GlobalVariable>(Operand)) {
or isa<llvm::GlobalVariable>(Operand)
or isa<llvm::UndefValue>(Operand)) {
// For constants and globals, fallback to the LLVM type
revng_assert(not Operand->getType()->isVoidTy());
revng_assert(Operand->getType()->isIntOrPtrTy());
auto ConstType = llvmIntToModelType(Operand->getType(), Model);
// Skip if it's not a pointer and we are only interested in pointers
if (not PointersOnly or ConstType.isPointer()) {
@@ -139,9 +140,15 @@ static RecursiveCoroutine<bool> addOperandType(const llvm::Value *Operand,
}
rc_return true;
} else if (isa<llvm::ConstantPointerNull>(Operand)) {
if (not PointersOnly)
TypeMap.insert({ Operand, {} });
} else if (auto *NullPtr = dyn_cast<llvm::ConstantPointerNull>(Operand)) {
if (not PointersOnly) {
auto PtrSize = model::Architecture::getPointerSize(Model.Architecture);
auto NullPointerType = model::QualifiedType{
Model.getPrimitiveType(model::PrimitiveTypeKind::Generic, PtrSize),
/*Qualifiers*/ {}
};
TypeMap.insert({ Operand, NullPointerType });
}
rc_return true;
}
@@ -580,7 +580,12 @@ private:
// Find old call instruction
CallInst *OldCall = findAssociatedCall(SSACSCall);
revng_assert(OldCall != nullptr);
if (not OldCall) {
// We can't find the original call, it might have been DCE'd away
return;
}
IRBuilder<> Builder(OldCall);
//
+1 -1
View File
@@ -3,7 +3,7 @@
#
revng_add_analyses_library(revngcRemoveLiftingArtifacts revngc
RemoveLiftingArtifacts.cpp)
PromoteInitCSVToUndef.cpp RemoveLiftingArtifacts.cpp)
target_link_libraries(
revngcRemoveLiftingArtifacts revngcSupport revng::revngModel
@@ -0,0 +1,60 @@
//
// Copyright (c) rev.ng Labs Srl. See LICENSE.md for details.
//
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/FunctionTags.h"
#include "revng-c/Support/FunctionTags.h"
#include "revng-c/Support/IRHelpers.h"
using namespace llvm;
static bool makeInitRegsUndef(Function &F) {
bool Changed = false;
for (auto &BB : F) {
for (auto &I : BB) {
auto *Call = dyn_cast<CallInst>(&I);
if (not Call)
continue;
auto *Callee = Call->getCalledFunction();
if (not Callee or not FunctionTags::OpaqueCSVValue.isTagOf(Callee))
continue;
Call->replaceAllUsesWith(llvm::UndefValue::get(Call->getType()));
Changed = true;
}
}
return Changed;
}
struct PromoteInitCSVToUndefPass : public FunctionPass {
public:
static char ID;
PromoteInitCSVToUndefPass() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
if (FunctionTags::Isolated.isTagOf(&F))
return makeInitRegsUndef(F);
return false;
}
};
char PromoteInitCSVToUndefPass::ID = 0;
static constexpr const char *Flag = "promote-init-csv-to-undef";
using Reg = RegisterPass<PromoteInitCSVToUndefPass>;
static Reg X(Flag, "Promotes calls to init_* functions for CSV to undefs");
@@ -131,10 +131,33 @@ static bool makeEnvNull(Function &F) {
return Changed;
}
static bool makeInitRegsUndef(Function &F) {
bool Changed = false;
for (auto &BB : F) {
for (auto &I : BB) {
auto *Call = dyn_cast<CallInst>(&I);
if (not Call)
continue;
auto *Callee = Call->getCalledFunction();
if (not Callee or not FunctionTags::OpaqueCSVValue.isTagOf(Callee))
continue;
Call->replaceAllUsesWith(llvm::UndefValue::get(Call->getType()));
Changed = true;
}
}
return Changed;
}
static bool removeLiftingArtifacts(Function &F) {
bool Changed = removeCallsToArtifacts(F);
Changed |= removeStoresToCPULoopExiting(F);
Changed |= makeEnvNull(F);
Changed |= makeInitRegsUndef(F);
return Changed;
}
+7 -3
View File
@@ -138,9 +138,13 @@ dropPointer(const model::QualifiedType &QT) {
if (It != NewQT.Qualifiers.rend()) {
std::erase(NewQT.Qualifiers, *It);
} else if (auto *TD = dyn_cast<TypedefType>(NewQT.UnqualifiedType.get())) {
rc_return rc_recur dropPointer(TD->UnderlyingType);
rc_return NewQT;
}
rc_return NewQT;
if (auto *TD = dyn_cast<TypedefType>(NewQT.UnqualifiedType.getConst()))
rc_return rc_recur dropPointer(TD->UnderlyingType);
revng_abort("Cannot dropPointer, QT does not have pointer qualifiers");
rc_return{};
}
@@ -11,4 +11,5 @@ Steps:
UsedContainers: [module.ll]
Passes:
- remove-lifting-artifacts
- promote-init-csv-to-undef