From cecb02f3da2ed40d9699fb2bc17d1b38446e4651 Mon Sep 17 00:00:00 2001 From: Pietro Fezzardi Date: Mon, 18 Jul 2022 14:44:58 +0200 Subject: [PATCH] Move getAcceptedColors where it's used --- .../TypeFlowGraph.cpp | 171 +++++++++++++++++- .../TypeFlowNode.cpp | 167 ----------------- lib/ValueManipulationAnalysis/TypeFlowNode.h | 5 - 3 files changed, 170 insertions(+), 173 deletions(-) diff --git a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp index 0a9aa24bd..5840b72a7 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp +++ b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp @@ -22,6 +22,7 @@ #include "revng/Support/FunctionTags.h" #include "revng-c/Support/FunctionTags.h" +#include "revng-c/Support/ModelHelpers.h" #include "revng-c/ValueManipulationAnalysis/TypeColors.h" #include "TypeFlowGraph.h" @@ -33,7 +34,173 @@ using namespace llvm; static Logger<> TGLog("vma-tg"); -// --------------- TypeFlowGraph +/// Returns a ColorSet with the types that can be assigned to a given use or +/// value. +static ColorSet +getAcceptedColors(const UseOrValue &Content, const model::Binary *Model) { + // Arguments, constants, globals etc. + if (isValue(Content)) { + const Value *V = getValue(Content); + + if (isa(V)) + return ALL_COLORS; + + // Constants and globals should not be infected, since they don't belong to + // a single function + if (isa(V) or isa(V)) + return NO_COLOR; + + if (not isa(V)) + return NO_COLOR; + } + + // Instructions and operand uses should be the only thing remaining + bool IsContentInst = isInst(Content); + revng_assert(IsContentInst or isUse(Content)); + + // If the content of the node is an Instruction's Value, assign colors + // based on the instruction's opcode. Otherwise, if we are creating a node for + // one of the operands, find which the user of the operand and check its + // opcode. + const Instruction *I = IsContentInst ? + cast(getValue(Content)) : + cast(getUse(Content)->getUser()); + + // Do we have strong model information about this node? If so, use that + if (Model) { + // Deduce type for the use or for the value, depending on which type of node + // we are looking at + auto DeducedTypes = IsContentInst ? + getStrongModelInfo(I, *Model) : + getExpectedModelType(getUse(Content), *Model); + + if (DeducedTypes.size() == 1) + return QTToColor(DeducedTypes.back()); + + if (DeducedTypes.size() > 1) { + // There are cases in which we can associate to an LLVM value (typically + // an aggregate) more than one model type, e.g. for values returned by + // RawFunctionTypes or for calls to StructInitializer. + // In these cases, the aggregate itself has no color. Not that the value + // extracted from that will instead have a color, which is inferred by + // `getStrongModelInfo()`. + } + } + + // Fallback to manually matching LLVM instructions that provides us with rich + // type information + switch (I->getOpcode()) { + case Instruction::FNeg: + case Instruction::FAdd: + case Instruction::FMul: + case Instruction::FSub: + case Instruction::FDiv: + case Instruction::FRem: + case Instruction::FPExt: + return FLOATNESS; + break; + + case Instruction::FCmp: + if (IsContentInst) + return BOOLNESS; + else + return FLOATNESS; + break; + + case Instruction::ICmp: + if (IsContentInst) + return BOOLNESS; + if (cast(I)->isSigned()) + return SIGNEDNESS; + if (cast(I)->isUnsigned()) + return UNSIGNEDNESS | POINTERNESS; + break; + + case Instruction::SDiv: + case Instruction::SRem: + return SIGNEDNESS | NUMBERNESS; + break; + + case Instruction::UDiv: + case Instruction::URem: + return UNSIGNEDNESS | NUMBERNESS; + break; + + case Instruction::Alloca: + if (IsContentInst) + return POINTERNESS; + if (getUse(Content)->get() == cast(I)->getArraySize()) + return UNSIGNEDNESS; + break; + + case Instruction::Load: + if (isUse(Content) + && getOpNo(Content) == cast(I)->getPointerOperandIndex()) + return POINTERNESS; + break; + + case Instruction::Store: + if (isUse(Content) + && getOpNo(Content) == cast(I)->getPointerOperandIndex()) + return POINTERNESS; + break; + + case Instruction::AShr: + if (IsContentInst or getOpNo(Content) == 0) + return SIGNEDNESS; + if (getOpNo(Content) == 1) + return ~(FLOATNESS | POINTERNESS); + break; + + case Instruction::LShr: + if (IsContentInst or getOpNo(Content) == 0) + // TODO: rule on first operand too strict? + return UNSIGNEDNESS; + if (getOpNo(Content) == 1) + return ~(FLOATNESS | POINTERNESS); + break; + + case Instruction::Shl: + if (IsContentInst) + return ~(FLOATNESS | POINTERNESS); + if (getOpNo(Content) == 0) + // TODO: rule on first operand too strict? + return (SIGNEDNESS | UNSIGNEDNESS | BOOLNESS); + if (getOpNo(Content) == 1) + return ~(FLOATNESS | POINTERNESS); + break; + + case Instruction::Mul: + return ~(FLOATNESS | POINTERNESS); + break; + + case Instruction::Br: + if (isUse(Content) && cast(I)->isConditional() + && getUse(Content)->get() == cast(I)->getCondition()) + return BOOLNESS; + break; + + case Instruction::Select: + if (isUse(Content) + && getUse(Content)->get() == cast(I)->getCondition()) + return BOOLNESS; + break; + + case Instruction::Trunc: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + // TODO: Restrict more what can be accepted by bitwise operations? + return ~NUMBERNESS; + break; + + case Instruction::GetElementPtr: + revng_abort("Didn't expect to find a GEP here"); + break; + } + + return ~NUMBERNESS; +} TypeFlowNode *TypeFlowGraph::addNodeContaining(const UseOrValue &NC) { revng_assert(not ContentToNodeMap.count(NC)); @@ -45,6 +212,8 @@ TypeFlowNode *TypeFlowGraph::addNodeContaining(const UseOrValue &NC) { return N; } +// --------------- TypeFlowGraph + TypeFlowNode * TypeFlowGraph::getNodeContaining(const UseOrValue &Content) const { const auto &It = ContentToNodeMap.find(Content); diff --git a/lib/ValueManipulationAnalysis/TypeFlowNode.cpp b/lib/ValueManipulationAnalysis/TypeFlowNode.cpp index e83f843ab..07adc4a1b 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowNode.cpp +++ b/lib/ValueManipulationAnalysis/TypeFlowNode.cpp @@ -19,7 +19,6 @@ #include "revng/Support/Assert.h" #include "revng/Support/IRHelpers.h" -#include "revng-c/Support/ModelHelpers.h" #include "revng-c/ValueManipulationAnalysis/TypeColors.h" #include "TypeFlowNode.h" @@ -81,172 +80,6 @@ RecursiveCoroutine vma::QTToColor(const model::QualifiedType &QT) { rc_return NO_COLOR; } -ColorSet -vma::getAcceptedColors(const UseOrValue &Content, const model::Binary *Model) { - // Arguments, constants, globals etc. - if (isValue(Content)) { - const Value *V = getValue(Content); - - if (isa(V)) - return ALL_COLORS; - - // Constants and globals should not be infected, since they don't belong to - // a single function - if (isa(V) or isa(V)) - return NO_COLOR; - - if (not isa(V)) - return NO_COLOR; - } - - // Instructions and operand uses should be the only thing remaining - bool IsContentInst = isInst(Content); - revng_assert(IsContentInst or isUse(Content)); - - // If the content of the node is an Instruction's Value, assign colors - // based on the instruction's opcode. Otherwise, if we are creating a node for - // one of the operands, find which the user of the operand and check its - // opcode. - const Instruction *I = IsContentInst ? - cast(getValue(Content)) : - cast(getUse(Content)->getUser()); - - // Do we have strong model information about this node? If so, use that - if (Model) { - // Deduce type for the use or for the value, depending on which type of node - // we are looking at - auto DeducedTypes = IsContentInst ? - getStrongModelInfo(I, *Model) : - getExpectedModelType(getUse(Content), *Model); - - if (DeducedTypes.size() == 1) - return QTToColor(DeducedTypes.back()); - - if (DeducedTypes.size() > 1) { - // There are cases in which we can associate to an LLVM value (typically - // an aggregate) more than one model type, e.g. for values returned by - // RawFunctionTypes or for calls to StructInitializer. - // In these cases, the aggregate itself has no color. Not that the value - // extracted from that will instead have a color, which is inferred by - // `getStrongModelInfo()`. - } - } - - // Fallback to manually matching LLVM instructions that provides us with rich - // type information - switch (I->getOpcode()) { - case Instruction::FNeg: - case Instruction::FAdd: - case Instruction::FMul: - case Instruction::FSub: - case Instruction::FDiv: - case Instruction::FRem: - case Instruction::FPExt: - return FLOATNESS; - break; - - case Instruction::FCmp: - if (IsContentInst) - return BOOLNESS; - else - return FLOATNESS; - break; - - case Instruction::ICmp: - if (IsContentInst) - return BOOLNESS; - if (cast(I)->isSigned()) - return SIGNEDNESS; - if (cast(I)->isUnsigned()) - return UNSIGNEDNESS | POINTERNESS; - break; - - case Instruction::SDiv: - case Instruction::SRem: - return SIGNEDNESS | NUMBERNESS; - break; - - case Instruction::UDiv: - case Instruction::URem: - return UNSIGNEDNESS | NUMBERNESS; - break; - - case Instruction::Alloca: - if (IsContentInst) - return POINTERNESS; - if (getUse(Content)->get() == cast(I)->getArraySize()) - return UNSIGNEDNESS; - break; - - case Instruction::Load: - if (isUse(Content) - && getOpNo(Content) == cast(I)->getPointerOperandIndex()) - return POINTERNESS; - break; - - case Instruction::Store: - if (isUse(Content) - && getOpNo(Content) == cast(I)->getPointerOperandIndex()) - return POINTERNESS; - break; - - case Instruction::AShr: - if (IsContentInst or getOpNo(Content) == 0) - return SIGNEDNESS; - if (getOpNo(Content) == 1) - return ~(FLOATNESS | POINTERNESS); - break; - - case Instruction::LShr: - if (IsContentInst or getOpNo(Content) == 0) - // TODO: rule on first operand too strict? - return UNSIGNEDNESS; - if (getOpNo(Content) == 1) - return ~(FLOATNESS | POINTERNESS); - break; - - case Instruction::Shl: - if (IsContentInst) - return ~(FLOATNESS | POINTERNESS); - if (getOpNo(Content) == 0) - // TODO: rule on first operand too strict? - return (SIGNEDNESS | UNSIGNEDNESS | BOOLNESS); - if (getOpNo(Content) == 1) - return ~(FLOATNESS | POINTERNESS); - break; - - case Instruction::Mul: - return ~(FLOATNESS | POINTERNESS); - break; - - case Instruction::Br: - if (isUse(Content) && cast(I)->isConditional() - && getUse(Content)->get() == cast(I)->getCondition()) - return BOOLNESS; - break; - - case Instruction::Select: - if (isUse(Content) - && getUse(Content)->get() == cast(I)->getCondition()) - return BOOLNESS; - break; - - case Instruction::Trunc: - case Instruction::And: - case Instruction::Or: - case Instruction::Xor: - // TODO: Restrict more what can be accepted by bitwise operations? - return ~NUMBERNESS; - break; - - case Instruction::GetElementPtr: - revng_abort("Didn't expect to find a GEP here"); - break; - } - - return ~NUMBERNESS; -} - void TypeFlowNodeData::print(llvm::raw_ostream &Out) const { if (this->isValue()) { Out << "value "; diff --git a/lib/ValueManipulationAnalysis/TypeFlowNode.h b/lib/ValueManipulationAnalysis/TypeFlowNode.h index 39253a4a9..057d4905b 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowNode.h +++ b/lib/ValueManipulationAnalysis/TypeFlowNode.h @@ -68,11 +68,6 @@ struct NodeColorProperty { /// are none). RecursiveCoroutine QTToColor(const model::QualifiedType &QT); -/// Returns a ColorSet with the types that can be assigned to a given use or -/// value. -ColorSet -getAcceptedColors(const UseOrValue &NC, const model::Binary *Model = nullptr); - // --------------- TypeFlowGraph Node /// Label of a TypeFlowGraph edge