In this lab, we implement an interprocedural sign analysis in both context sensitive and insensitive manner. The source code refer to tutorialpass/pass/InterSignAnalysis
Dynamic cast
The dyn_cast<> operator is a “checking cast” operation. It checks to see if the operand is of the specified type, and if so, returns a pointer to it (this operator does not work with references). If the operand is not of the correct type, a null pointer is returned.
It is defined in include/llvm/Support/Casting.h
template <class X, class Y>
LLVM_NODISCARD inline std::enable_if_t<
!is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>
dyn_cast(const Y &Val) {
return isa<X>(Val) ? cast<X>(Val) : nullptr;
}
Typically, the dyn_cast<> operator is used in an if statement or some other flow control statement like this. Attention: Val should be the reference type, not pointer type.
if (auto *AI = dyn_cast<AllocationInst>(Val)) {
// ...
}
The related operators include:
- The isa<> operator works exactly like the Java “instanceof” operator. It returns true or false depending on whether a reference or pointer points to an instance of the specified class. This can be very useful for constraint checking of various sorts.
- The cast<> operator is a “checked cast” operation. It converts a pointer or reference from a base class to a derived class, causing an assertion failure if it is not really an instance of the right type. This should be used in cases where you have some information that makes you believe that something is of the right type.
- dyn_cast is a combination of isa and cast
Summary of lab
- The approaches of interprocedural analysis
- The context-insensitive analysis can be regarded as a variant of fixed point algorithm over super flow graph.
- As for context sensitive analysis, the function cloned based approach can be designed on demands, which means that the callee functions are analyzed only if it is called by some functions.
- Reflection of implementation
- The design of module should be clear. It would be better if more time is spent on designing the module.
- In this lab, a more sophisticated design can be
- Lattice operators: operations on sign lattice, which takes sign symbols as inputs and return the result of operation.
- Instruction handler: For each type of instructions, extract its operands and its result(if any). Retrieve the sign value of lattice operands and update the sign symbol of the result.
- Basic block handler: Update the basic block state
- Function handler: It is a core engine used for scheduling under different configuration of analysis, such as context sensitive/insensitive
- Some generic functions
- The join function of lattice elements
- The meet function of states for basic block(In path insensitive, it might be defined by invoking the join function of lattice elements)
Reference
- LLVM documentation casting type [ link ]