From 8dfd7c2d966f16dfaafdb269f83b19cc34e932cb Mon Sep 17 00:00:00 2001 From: Valentina Sona Date: Wed, 19 Apr 2023 22:06:19 +0200 Subject: [PATCH] Add custom opcode BooleanNot --- include/revng-c/Support/FunctionTags.h | 4 ++++ lib/Backend/DecompileFunction.cpp | 7 ++++++ .../OperatorPrecedenceResolutionPass.cpp | 23 ++++++++++++------- lib/InitModelTypes/InitModelTypes.cpp | 3 +++ lib/Support/FunctionTags.cpp | 14 +++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/include/revng-c/Support/FunctionTags.h b/include/revng-c/Support/FunctionTags.h index ffe72ba4e..15a4cf3c9 100644 --- a/include/revng-c/Support/FunctionTags.h +++ b/include/revng-c/Support/FunctionTags.h @@ -38,6 +38,7 @@ extern Tag WritesMemory; extern Tag SegmentRef; extern Tag UnaryMinus; extern Tag BinaryNot; +extern Tag BooleanNot; inline Tag LiftingArtifactsRemoved("LiftingArtifactsRemoved", Isolated); @@ -111,6 +112,9 @@ void initUnaryMinusPool(OpaqueFunctionsPool &Pool); /// Initializes a pool of binary_not functions void initBinaryNotPool(OpaqueFunctionsPool &Pool); +/// Initializes a pool of boolean_not functions +void initBooleanNotPool(OpaqueFunctionsPool &Pool); + /// ModelGEP functions are used to replace pointer arithmetic with a navigation /// of the Model. /// diff --git a/lib/Backend/DecompileFunction.cpp b/lib/Backend/DecompileFunction.cpp index 1182f83fd..e9427d22a 100644 --- a/lib/Backend/DecompileFunction.cpp +++ b/lib/Backend/DecompileFunction.cpp @@ -162,6 +162,7 @@ static bool isCallToCustomOpcode(const llvm::Instruction *I) { or isCallToTagged(I, FunctionTags::SegmentRef) or isCallToTagged(I, FunctionTags::UnaryMinus) or isCallToTagged(I, FunctionTags::BinaryNot) + or isCallToTagged(I, FunctionTags::BooleanNot) or isCallToTagged(I, FunctionTags::StringLiteral); } @@ -833,6 +834,12 @@ CCodeGenerator::getCustomOpcodeToken(const llvm::CallInst *Call) const { + ToNegate; } + if (isCallToTagged(Call, FunctionTags::BooleanNot)) { + auto Operand = Call->getArgOperand(0); + std::string ToNegate = rc_recur getToken(Operand); + rc_return ThePTMLCBuilder.getOperator(PTMLOperator::BoolNot) + ToNegate; + } + if (isCallToTagged(Call, FunctionTags::StringLiteral)) { const auto Operand = Call->getArgOperand(0); std::string StringLiteral = rc_recur getToken(Operand); diff --git a/lib/IRCanonicalization/OperatorPrecedenceResolutionPass.cpp b/lib/IRCanonicalization/OperatorPrecedenceResolutionPass.cpp index b10133949..b7e20397f 100644 --- a/lib/IRCanonicalization/OperatorPrecedenceResolutionPass.cpp +++ b/lib/IRCanonicalization/OperatorPrecedenceResolutionPass.cpp @@ -47,7 +47,8 @@ enum CustomInstruction : unsigned { Transparent = getInstructionLLVMOpcodeCount() + 7, SegmentRef = getInstructionLLVMOpcodeCount() + 8, UnaryMinus = getInstructionLLVMOpcodeCount() + 9, - BinaryNot = getInstructionLLVMOpcodeCount() + 10 + BinaryNot = getInstructionLLVMOpcodeCount() + 10, + BooleanNot = getInstructionLLVMOpcodeCount() + 11 }; struct InstToOpPrec { @@ -64,7 +65,7 @@ struct InstToOpPrec { }; // Table that maps LLVM opcodes to the equivalent C operator precedence priority -static constexpr std::array +static constexpr std::array LLVMOpcodeToCOpPrecedenceArray{ { { InstToOpPrec(CustomInstruction::Assignment, 0, RIGHT_TO_LEFT) }, { InstToOpPrec(CustomInstruction::LocalVariable, 10, LEFT_TO_RIGHT) }, @@ -101,10 +102,11 @@ static constexpr std::array { InstToOpPrec(CustomInstruction::Cast, 9, RIGHT_TO_LEFT) }, { InstToOpPrec(CustomInstruction::MemberAccess, 10, LEFT_TO_RIGHT) }, { InstToOpPrec(CustomInstruction::UnaryMinus, 9, RIGHT_TO_LEFT) }, - { InstToOpPrec(CustomInstruction::BinaryNot, 9, RIGHT_TO_LEFT) } }, + { InstToOpPrec(CustomInstruction::BinaryNot, 9, RIGHT_TO_LEFT) }, + { InstToOpPrec(CustomInstruction::BooleanNot, 9, RIGHT_TO_LEFT) } }, }; -static constexpr std::array +static constexpr std::array LLVMOpcodeToNopOpPrecedenceArray{ { { InstToOpPrec(CustomInstruction::Assignment, 0, RIGHT_TO_LEFT) }, { InstToOpPrec(CustomInstruction::LocalVariable, 0, LEFT_TO_RIGHT) }, @@ -141,11 +143,12 @@ static constexpr std::array { InstToOpPrec(CustomInstruction::Cast, 0, RIGHT_TO_LEFT) }, { InstToOpPrec(CustomInstruction::MemberAccess, 0, LEFT_TO_RIGHT) }, { InstToOpPrec(CustomInstruction::UnaryMinus, 2, RIGHT_TO_LEFT) }, - { InstToOpPrec(CustomInstruction::BinaryNot, 2, RIGHT_TO_LEFT) } }, + { InstToOpPrec(CustomInstruction::BinaryNot, 2, RIGHT_TO_LEFT) }, + { InstToOpPrec(CustomInstruction::BooleanNot, 2, RIGHT_TO_LEFT) } }, }; static auto -findOpcode(const std::array *Table, unsigned Opcode) { +findOpcode(const std::array *Table, unsigned Opcode) { return find_if(*Table, [&](const auto &Elem) { return Elem.InstructionOpcode == Opcode; }); @@ -165,7 +168,8 @@ static bool isCustomOpcode(Instruction *I) { || FunctionTags::AllocatesLocalVariable.isTagOf(CalledFunc) || FunctionTags::SegmentRef.isTagOf(CalledFunc) || FunctionTags::UnaryMinus.isTagOf(CalledFunc) - || FunctionTags::BinaryNot.isTagOf(CalledFunc)) + || FunctionTags::BinaryNot.isTagOf(CalledFunc) + || FunctionTags::BooleanNot.isTagOf(CalledFunc)) return true; return false; @@ -198,6 +202,8 @@ static unsigned getCustomOpcode(Instruction *I) { return CustomInstruction::UnaryMinus; } else if (FunctionTags::BinaryNot.isTagOf(CalledFunc)) { return CustomInstruction::BinaryNot; + } else if (FunctionTags::BooleanNot.isTagOf(CalledFunc)) { + return CustomInstruction::BooleanNot; } revng_abort(); @@ -235,7 +241,7 @@ static llvm::Value *traverseTransparentOpcode(llvm::Value *V) { struct OperatorPrecedenceResolutionPass : public llvm::FunctionPass { private: - const std::array + const std::array *LLVMOpcodeToLangOpPrecedenceArray = nullptr; public: @@ -306,6 +312,7 @@ bool OPRP::needsParentheses(Instruction *I, Use &U) { VerifyParentheses = (U.getOperandNo() == 1); break; case CustomInstruction::BinaryNot: + case CustomInstruction::BooleanNot: case CustomInstruction::UnaryMinus: VerifyParentheses = true; break; diff --git a/lib/InitModelTypes/InitModelTypes.cpp b/lib/InitModelTypes/InitModelTypes.cpp index a3ae437a2..8a3807d7d 100644 --- a/lib/InitModelTypes/InitModelTypes.cpp +++ b/lib/InitModelTypes/InitModelTypes.cpp @@ -236,6 +236,9 @@ static TypeVector getReturnTypes(FunctionMetadataCache &Cache, ReturnTypes.push_back(llvmIntToModelType(Arg->getType(), Model)); } else if (FunctionTags::BinaryNot.isTagOf(CalledFunc)) { ReturnTypes.push_back(llvmIntToModelType(Call->getType(), Model)); + } else if (FunctionTags::BooleanNot.isTagOf(CalledFunc)) { + auto IntType = llvm::IntegerType::getInt1Ty(CalledFunc->getContext()); + ReturnTypes.push_back(llvmIntToModelType(IntType, Model)); } else { revng_abort("Unknown non-isolated function"); } diff --git a/lib/Support/FunctionTags.cpp b/lib/Support/FunctionTags.cpp index 78da20b02..f6f77286e 100644 --- a/lib/Support/FunctionTags.cpp +++ b/lib/Support/FunctionTags.cpp @@ -39,6 +39,7 @@ Tag ReadsMemory("ReadsMemory"); Tag SegmentRef("SegmentRef"); Tag UnaryMinus("UnaryMinus"); Tag BinaryNot("BinaryNot"); +Tag BooleanNot("BooleanNot"); } // namespace FunctionTags static std::string makeTypeName(const llvm::Type *Ty) { @@ -223,6 +224,19 @@ void initBinaryNotPool(OpaqueFunctionsPool &Pool) { Pool.initializeFromReturnType(FunctionTags::BinaryNot); } +void initBooleanNotPool(OpaqueFunctionsPool &Pool) { + // Set attributes + Pool.addFnAttribute(llvm::Attribute::NoUnwind); + Pool.addFnAttribute(llvm::Attribute::WillReturn); + Pool.setMemoryEffects(llvm::MemoryEffects::none()); + + // Set revng tags + Pool.setTags({ &FunctionTags::BooleanNot }); + + // Initialize the pool from its internal llvm::Module if possible. + Pool.initializeFromNthArgType(FunctionTags::BooleanNot, 0); +} + void initSegmentRefPool(OpaqueFunctionsPool &Pool, llvm::Module *M) { // Set attributes