зеркало из https://github.com/github/codeql.git
C++: Sync identical files
This commit is contained in:
Родитель
9f59e385d1
Коммит
75eb7f92a2
|
@ -1,12 +1,13 @@
|
|||
private import internal.EdgeKindInternal
|
||||
|
||||
private newtype TEdgeKind =
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge(string minValue, string maxValue) { // Case label of switch
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge(string minValue, string maxValue) {
|
||||
// Case label of switch
|
||||
Language::hasCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
|
@ -24,70 +25,50 @@ abstract class EdgeKind extends TEdgeKind {
|
|||
* or `IRBlock`.
|
||||
*/
|
||||
class GotoEdge extends EdgeKind, TGotoEdge {
|
||||
override final string toString() {
|
||||
result = "Goto"
|
||||
}
|
||||
final override string toString() { result = "Goto" }
|
||||
}
|
||||
|
||||
GotoEdge gotoEdge() {
|
||||
result = TGotoEdge()
|
||||
}
|
||||
GotoEdge gotoEdge() { result = TGotoEdge() }
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends EdgeKind, TTrueEdge {
|
||||
override final string toString() {
|
||||
result = "True"
|
||||
}
|
||||
final override string toString() { result = "True" }
|
||||
}
|
||||
|
||||
TrueEdge trueEdge() {
|
||||
result = TTrueEdge()
|
||||
}
|
||||
TrueEdge trueEdge() { result = TTrueEdge() }
|
||||
|
||||
/**
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends EdgeKind, TFalseEdge {
|
||||
override final string toString() {
|
||||
result = "False"
|
||||
}
|
||||
final override string toString() { result = "False" }
|
||||
}
|
||||
|
||||
FalseEdge falseEdge() {
|
||||
result = TFalseEdge()
|
||||
}
|
||||
FalseEdge falseEdge() { result = TFalseEdge() }
|
||||
|
||||
/**
|
||||
* An "exception" edge, representing the successor of an instruction when that
|
||||
* instruction's evaluation throws an exception.
|
||||
*/
|
||||
class ExceptionEdge extends EdgeKind, TExceptionEdge {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
final override string toString() { result = "Exception" }
|
||||
}
|
||||
|
||||
ExceptionEdge exceptionEdge() {
|
||||
result = TExceptionEdge()
|
||||
}
|
||||
ExceptionEdge exceptionEdge() { result = TExceptionEdge() }
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends EdgeKind, TDefaultEdge {
|
||||
override final string toString() {
|
||||
result = "Default"
|
||||
}
|
||||
final override string toString() { result = "Default" }
|
||||
}
|
||||
|
||||
DefaultEdge defaultEdge() {
|
||||
result = TDefaultEdge()
|
||||
}
|
||||
DefaultEdge defaultEdge() { result = TDefaultEdge() }
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
|
@ -95,28 +76,20 @@ DefaultEdge defaultEdge() {
|
|||
*/
|
||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
string minValue;
|
||||
|
||||
string maxValue;
|
||||
|
||||
CaseEdge() {
|
||||
this = TCaseEdge(minValue, maxValue)
|
||||
CaseEdge() { this = TCaseEdge(minValue, maxValue) }
|
||||
|
||||
final override string toString() {
|
||||
if minValue = maxValue
|
||||
then result = "Case[" + minValue + "]"
|
||||
else result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
if minValue = maxValue then
|
||||
result = "Case[" + minValue + "]"
|
||||
else
|
||||
result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
string getMinValue() { result = minValue }
|
||||
|
||||
string getMinValue() {
|
||||
result = minValue
|
||||
}
|
||||
|
||||
string getMaxValue() {
|
||||
result = maxValue
|
||||
}
|
||||
string getMaxValue() { result = maxValue }
|
||||
}
|
||||
|
||||
CaseEdge caseEdge(string minValue, string maxValue) {
|
||||
result = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) }
|
||||
|
|
|
@ -15,17 +15,13 @@ private newtype TMemoryAccessKind =
|
|||
* memory result.
|
||||
*/
|
||||
class MemoryAccessKind extends TMemoryAccessKind {
|
||||
string toString() {
|
||||
none()
|
||||
}
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the operand or result accesses memory pointed to by the `AddressOperand` on the
|
||||
* same instruction.
|
||||
*/
|
||||
predicate usesAddressOperand() {
|
||||
none()
|
||||
}
|
||||
predicate usesAddressOperand() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,13 +29,9 @@ class MemoryAccessKind extends TMemoryAccessKind {
|
|||
* same instruction.
|
||||
*/
|
||||
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
override string toString() {
|
||||
result = "indirect"
|
||||
}
|
||||
|
||||
override final predicate usesAddressOperand() {
|
||||
any()
|
||||
}
|
||||
override string toString() { result = "indirect" }
|
||||
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,13 +39,9 @@ class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
|||
* `AddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess {
|
||||
override string toString() {
|
||||
result = "indirect(may)"
|
||||
}
|
||||
override string toString() { result = "indirect(may)" }
|
||||
|
||||
override final predicate usesAddressOperand() {
|
||||
any()
|
||||
}
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,13 +50,9 @@ class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess
|
|||
* `BufferSizeOperand`.
|
||||
*/
|
||||
class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
|
||||
override string toString() {
|
||||
result = "buffer"
|
||||
}
|
||||
override string toString() { result = "buffer" }
|
||||
|
||||
override final predicate usesAddressOperand() {
|
||||
any()
|
||||
}
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,31 +61,23 @@ class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
|
|||
* elements given by the `BufferSizeOperand`.
|
||||
*/
|
||||
class BufferMayMemoryAccess extends MemoryAccessKind, TBufferMayMemoryAccess {
|
||||
override string toString() {
|
||||
result = "buffer(may)"
|
||||
}
|
||||
override string toString() { result = "buffer(may)" }
|
||||
|
||||
override final predicate usesAddressOperand() {
|
||||
any()
|
||||
}
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses all memory whose address has escaped.
|
||||
*/
|
||||
class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess {
|
||||
override string toString() {
|
||||
result = "escaped"
|
||||
}
|
||||
override string toString() { result = "escaped" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access all memory whose address has escaped.
|
||||
*/
|
||||
class EscapedMayMemoryAccess extends MemoryAccessKind, TEscapedMayMemoryAccess {
|
||||
override string toString() {
|
||||
result = "escaped(may)"
|
||||
}
|
||||
override string toString() { result = "escaped(may)" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,9 +85,7 @@ class EscapedMayMemoryAccess extends MemoryAccessKind, TEscapedMayMemoryAccess {
|
|||
* definition.
|
||||
*/
|
||||
class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess {
|
||||
override string toString() {
|
||||
result = "phi"
|
||||
}
|
||||
override string toString() { result = "phi" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,9 +93,7 @@ class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess {
|
|||
* definition.
|
||||
*/
|
||||
class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
|
||||
override string toString() {
|
||||
result = "chi(total)"
|
||||
}
|
||||
override string toString() { result = "chi(total)" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,9 +101,7 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
|
|||
* definition.
|
||||
*/
|
||||
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
|
||||
override string toString() {
|
||||
result = "chi(partial)"
|
||||
}
|
||||
override string toString() { result = "chi(partial)" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,7 +109,5 @@ class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
|
|||
* `UnmodeledDefinition` and on the operands of `UnmodeledUse`.
|
||||
*/
|
||||
class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess {
|
||||
override string toString() {
|
||||
result = "unmodeled"
|
||||
}
|
||||
override string toString() { result = "unmodeled" }
|
||||
}
|
||||
|
|
|
@ -77,152 +77,382 @@ private newtype TOpcode =
|
|||
TNewObj()
|
||||
|
||||
class Opcode extends TOpcode {
|
||||
string toString() {
|
||||
result = "UnknownOpcode"
|
||||
}
|
||||
string toString() { result = "UnknownOpcode" }
|
||||
}
|
||||
|
||||
abstract class UnaryOpcode extends Opcode {}
|
||||
abstract class UnaryOpcode extends Opcode { }
|
||||
|
||||
abstract class BinaryOpcode extends Opcode {}
|
||||
abstract class BinaryOpcode extends Opcode { }
|
||||
|
||||
abstract class PointerArithmeticOpcode extends BinaryOpcode {}
|
||||
abstract class PointerArithmeticOpcode extends BinaryOpcode { }
|
||||
|
||||
abstract class PointerOffsetOpcode extends PointerArithmeticOpcode {}
|
||||
abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { }
|
||||
|
||||
abstract class ArithmeticOpcode extends Opcode {}
|
||||
abstract class ArithmeticOpcode extends Opcode { }
|
||||
|
||||
abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode {}
|
||||
abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { }
|
||||
|
||||
abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode {}
|
||||
abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { }
|
||||
|
||||
abstract class BitwiseOpcode extends Opcode {}
|
||||
abstract class BitwiseOpcode extends Opcode { }
|
||||
|
||||
abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode {}
|
||||
abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { }
|
||||
|
||||
abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode {}
|
||||
abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { }
|
||||
|
||||
abstract class CompareOpcode extends BinaryOpcode {}
|
||||
abstract class CompareOpcode extends BinaryOpcode { }
|
||||
|
||||
abstract class RelationalOpcode extends CompareOpcode {}
|
||||
abstract class RelationalOpcode extends CompareOpcode { }
|
||||
|
||||
abstract class CopyOpcode extends Opcode {}
|
||||
abstract class CopyOpcode extends Opcode { }
|
||||
|
||||
abstract class MemoryAccessOpcode extends Opcode {}
|
||||
abstract class MemoryAccessOpcode extends Opcode { }
|
||||
|
||||
abstract class ReturnOpcode extends Opcode {}
|
||||
abstract class ReturnOpcode extends Opcode { }
|
||||
|
||||
abstract class ThrowOpcode extends Opcode {}
|
||||
abstract class ThrowOpcode extends Opcode { }
|
||||
|
||||
abstract class CatchOpcode extends Opcode {}
|
||||
abstract class CatchOpcode extends Opcode { }
|
||||
|
||||
abstract class OpcodeWithCondition extends Opcode {}
|
||||
abstract class OpcodeWithCondition extends Opcode { }
|
||||
|
||||
abstract class BuiltInOperationOpcode extends Opcode {}
|
||||
abstract class BuiltInOperationOpcode extends Opcode { }
|
||||
|
||||
abstract class SideEffectOpcode extends Opcode {}
|
||||
abstract class SideEffectOpcode extends Opcode { }
|
||||
|
||||
/**
|
||||
* An opcode that reads a value from memory.
|
||||
*/
|
||||
abstract class OpcodeWithLoad extends MemoryAccessOpcode {}
|
||||
abstract class OpcodeWithLoad extends MemoryAccessOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that reads from a set of memory locations as a side effect.
|
||||
*/
|
||||
abstract class ReadSideEffectOpcode extends SideEffectOpcode {}
|
||||
abstract class ReadSideEffectOpcode extends SideEffectOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that writes to a set of memory locations as a side effect.
|
||||
*/
|
||||
abstract class WriteSideEffectOpcode extends SideEffectOpcode {}
|
||||
abstract class WriteSideEffectOpcode extends SideEffectOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled
|
||||
* as a read of the original contents, plus a "may" write of the new contents.
|
||||
*/
|
||||
abstract class MayWriteSideEffectOpcode extends SideEffectOpcode {}
|
||||
abstract class MayWriteSideEffectOpcode extends SideEffectOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`.
|
||||
*/
|
||||
abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
|
||||
abstract class BufferAccessOpcode extends MemoryAccessOpcode { }
|
||||
|
||||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
class Error extends Opcode, TError { override final string toString() { result = "Error" } }
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
||||
class ExitFunction extends Opcode, TExitFunction { override final string toString() { result = "ExitFunction" } }
|
||||
class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { override final string toString() { result = "ReturnValue" } }
|
||||
class ReturnVoid extends ReturnOpcode, TReturnVoid { override final string toString() { result = "ReturnVoid" } }
|
||||
class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { override final string toString() { result = "CopyValue" } }
|
||||
class Load extends CopyOpcode, OpcodeWithLoad, TLoad { override final string toString() { result = "Load" } }
|
||||
class Store extends CopyOpcode, MemoryAccessOpcode, TStore { override final string toString() { result = "Store" } }
|
||||
class Add extends BinaryArithmeticOpcode, TAdd { override final string toString() { result = "Add" } }
|
||||
class Sub extends BinaryArithmeticOpcode, TSub { override final string toString() { result = "Sub" } }
|
||||
class Mul extends BinaryArithmeticOpcode, TMul { override final string toString() { result = "Mul" } }
|
||||
class Div extends BinaryArithmeticOpcode, TDiv { override final string toString() { result = "Div" } }
|
||||
class Rem extends BinaryArithmeticOpcode, TRem { override final string toString() { result = "Rem" } }
|
||||
class Negate extends UnaryArithmeticOpcode, TNegate { override final string toString() { result = "Negate" } }
|
||||
class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { override final string toString() { result = "ShiftLeft" } }
|
||||
class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { override final string toString() { result = "ShiftRight" } }
|
||||
class BitAnd extends BinaryBitwiseOpcode, TBitAnd { override final string toString() { result = "BitAnd" } }
|
||||
class BitOr extends BinaryBitwiseOpcode, TBitOr { override final string toString() { result = "BitOr" } }
|
||||
class BitXor extends BinaryBitwiseOpcode, TBitXor { override final string toString() { result = "BitXor" } }
|
||||
class BitComplement extends UnaryBitwiseOpcode, TBitComplement { override final string toString() { result = "BitComplement" } }
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot { override final string toString() { result = "LogicalNot" } }
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ { override final string toString() { result = "CompareEQ" } }
|
||||
class CompareNE extends CompareOpcode, TCompareNE { override final string toString() { result = "CompareNE" } }
|
||||
class CompareLT extends RelationalOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends RelationalOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends RelationalOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends RelationalOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd { override final string toString() { result = "PointerAdd" } }
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
class Convert extends UnaryOpcode, TConvert { override final string toString() { result = "Convert" } }
|
||||
class ConvertToBase extends UnaryOpcode, TConvertToBase { override final string toString() { result = "ConvertToBase" } }
|
||||
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase { override final string toString() { result = "ConvertToVirtualBase" } }
|
||||
class ConvertToDerived extends UnaryOpcode, TConvertToDerived { override final string toString() { result = "ConvertToDerived" } }
|
||||
class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { override final string toString() { result = "CheckedConvertOrNull" } }
|
||||
class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { override final string toString() { result = "CheckedConvertOrThrow" } }
|
||||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { override final string toString() { result = "DynamicCastToVoid" } }
|
||||
class VariableAddress extends Opcode, TVariableAddress { override final string toString() { result = "VariableAddress" } }
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress { override final string toString() { result = "FieldAddress" } }
|
||||
class ElementsAddress extends UnaryOpcode, TElementsAddress { override final string toString() { result = "ElementsAddress" } }
|
||||
class FunctionAddress extends Opcode, TFunctionAddress { override final string toString() { result = "FunctionAddress" } }
|
||||
class Constant extends Opcode, TConstant { override final string toString() { result = "Constant" } }
|
||||
class StringConstant extends Opcode, TStringConstant { override final string toString() { result = "StringConstant" } }
|
||||
class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { override final string toString() { result = "ConditionalBranch" } }
|
||||
class Switch extends OpcodeWithCondition, TSwitch { override final string toString() { result = "Switch" } }
|
||||
class Call extends Opcode, TCall { override final string toString() { result = "Call" } }
|
||||
class CatchByType extends CatchOpcode, TCatchByType { override final string toString() { result = "CatchByType" } }
|
||||
class CatchAny extends CatchOpcode, TCatchAny { override final string toString() { result = "CatchAny" } }
|
||||
class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { override final string toString() { result = "ThrowValue" } }
|
||||
class ReThrow extends ThrowOpcode, TReThrow { override final string toString() { result = "ReThrow" } }
|
||||
class Unwind extends Opcode, TUnwind { override final string toString() { result = "Unwind" } }
|
||||
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { override final string toString() { result = "UnmodeledDefinition" } }
|
||||
class UnmodeledUse extends Opcode, TUnmodeledUse { override final string toString() { result = "UnmodeledUse" } }
|
||||
class AliasedDefinition extends Opcode, TAliasedDefinition { override final string toString() { result = "AliasedDefinition" } }
|
||||
class Phi extends Opcode, TPhi { override final string toString() { result = "Phi" } }
|
||||
class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { override final string toString() { result = "BuiltIn" } }
|
||||
class VarArgsStart extends BuiltInOperationOpcode, TVarArgsStart { override final string toString() { result = "VarArgsStart" } }
|
||||
class VarArgsEnd extends BuiltInOperationOpcode, TVarArgsEnd { override final string toString() { result = "VarArgsEnd" } }
|
||||
class VarArg extends BuiltInOperationOpcode, TVarArg { override final string toString() { result = "VarArg" } }
|
||||
class VarArgCopy extends BuiltInOperationOpcode, TVarArgCopy { override final string toString() { result = "VarArgCopy" } }
|
||||
class CallSideEffect extends MayWriteSideEffectOpcode, TCallSideEffect { override final string toString() { result = "CallSideEffect" } }
|
||||
class CallReadSideEffect extends ReadSideEffectOpcode, TCallReadSideEffect { override final string toString() { result = "CallReadSideEffect" } }
|
||||
class IndirectReadSideEffect extends ReadSideEffectOpcode, MemoryAccessOpcode, TIndirectReadSideEffect { override final string toString() { result = "IndirectReadSideEffect" } }
|
||||
class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode, TIndirectWriteSideEffect { override final string toString() { result = "IndirectWriteSideEffect" } }
|
||||
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode, TIndirectMayWriteSideEffect { override final string toString() { result = "IndirectMayWriteSideEffect" } }
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect { override final string toString() { result = "BufferReadSideEffect" } }
|
||||
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
|
||||
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
|
||||
class Chi extends Opcode, TChi { override final string toString() { result = "Chi" } }
|
||||
class InlineAsm extends Opcode, TInlineAsm { override final string toString() { result = "InlineAsm" } }
|
||||
class Unreached extends Opcode, TUnreached { override final string toString() { result = "Unreached" } }
|
||||
class NewObj extends Opcode, TNewObj { override final string toString() { result = "NewObj" } }
|
||||
class NoOp extends Opcode, TNoOp {
|
||||
final override string toString() { result = "NoOp" }
|
||||
}
|
||||
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized {
|
||||
final override string toString() { result = "Uninitialized" }
|
||||
}
|
||||
|
||||
class Error extends Opcode, TError {
|
||||
final override string toString() { result = "Error" }
|
||||
}
|
||||
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter {
|
||||
final override string toString() { result = "InitializeParameter" }
|
||||
}
|
||||
|
||||
class InitializeThis extends Opcode, TInitializeThis {
|
||||
final override string toString() { result = "InitializeThis" }
|
||||
}
|
||||
|
||||
class EnterFunction extends Opcode, TEnterFunction {
|
||||
final override string toString() { result = "EnterFunction" }
|
||||
}
|
||||
|
||||
class ExitFunction extends Opcode, TExitFunction {
|
||||
final override string toString() { result = "ExitFunction" }
|
||||
}
|
||||
|
||||
class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue {
|
||||
final override string toString() { result = "ReturnValue" }
|
||||
}
|
||||
|
||||
class ReturnVoid extends ReturnOpcode, TReturnVoid {
|
||||
final override string toString() { result = "ReturnVoid" }
|
||||
}
|
||||
|
||||
class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue {
|
||||
final override string toString() { result = "CopyValue" }
|
||||
}
|
||||
|
||||
class Load extends CopyOpcode, OpcodeWithLoad, TLoad {
|
||||
final override string toString() { result = "Load" }
|
||||
}
|
||||
|
||||
class Store extends CopyOpcode, MemoryAccessOpcode, TStore {
|
||||
final override string toString() { result = "Store" }
|
||||
}
|
||||
|
||||
class Add extends BinaryArithmeticOpcode, TAdd {
|
||||
final override string toString() { result = "Add" }
|
||||
}
|
||||
|
||||
class Sub extends BinaryArithmeticOpcode, TSub {
|
||||
final override string toString() { result = "Sub" }
|
||||
}
|
||||
|
||||
class Mul extends BinaryArithmeticOpcode, TMul {
|
||||
final override string toString() { result = "Mul" }
|
||||
}
|
||||
|
||||
class Div extends BinaryArithmeticOpcode, TDiv {
|
||||
final override string toString() { result = "Div" }
|
||||
}
|
||||
|
||||
class Rem extends BinaryArithmeticOpcode, TRem {
|
||||
final override string toString() { result = "Rem" }
|
||||
}
|
||||
|
||||
class Negate extends UnaryArithmeticOpcode, TNegate {
|
||||
final override string toString() { result = "Negate" }
|
||||
}
|
||||
|
||||
class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft {
|
||||
final override string toString() { result = "ShiftLeft" }
|
||||
}
|
||||
|
||||
class ShiftRight extends BinaryBitwiseOpcode, TShiftRight {
|
||||
final override string toString() { result = "ShiftRight" }
|
||||
}
|
||||
|
||||
class BitAnd extends BinaryBitwiseOpcode, TBitAnd {
|
||||
final override string toString() { result = "BitAnd" }
|
||||
}
|
||||
|
||||
class BitOr extends BinaryBitwiseOpcode, TBitOr {
|
||||
final override string toString() { result = "BitOr" }
|
||||
}
|
||||
|
||||
class BitXor extends BinaryBitwiseOpcode, TBitXor {
|
||||
final override string toString() { result = "BitXor" }
|
||||
}
|
||||
|
||||
class BitComplement extends UnaryBitwiseOpcode, TBitComplement {
|
||||
final override string toString() { result = "BitComplement" }
|
||||
}
|
||||
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot {
|
||||
final override string toString() { result = "LogicalNot" }
|
||||
}
|
||||
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ {
|
||||
final override string toString() { result = "CompareEQ" }
|
||||
}
|
||||
|
||||
class CompareNE extends CompareOpcode, TCompareNE {
|
||||
final override string toString() { result = "CompareNE" }
|
||||
}
|
||||
|
||||
class CompareLT extends RelationalOpcode, TCompareLT {
|
||||
final override string toString() { result = "CompareLT" }
|
||||
}
|
||||
|
||||
class CompareGT extends RelationalOpcode, TCompareGT {
|
||||
final override string toString() { result = "CompareGT" }
|
||||
}
|
||||
|
||||
class CompareLE extends RelationalOpcode, TCompareLE {
|
||||
final override string toString() { result = "CompareLE" }
|
||||
}
|
||||
|
||||
class CompareGE extends RelationalOpcode, TCompareGE {
|
||||
final override string toString() { result = "CompareGE" }
|
||||
}
|
||||
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd {
|
||||
final override string toString() { result = "PointerAdd" }
|
||||
}
|
||||
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub {
|
||||
final override string toString() { result = "PointerSub" }
|
||||
}
|
||||
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff {
|
||||
final override string toString() { result = "PointerDiff" }
|
||||
}
|
||||
|
||||
class Convert extends UnaryOpcode, TConvert {
|
||||
final override string toString() { result = "Convert" }
|
||||
}
|
||||
|
||||
class ConvertToBase extends UnaryOpcode, TConvertToBase {
|
||||
final override string toString() { result = "ConvertToBase" }
|
||||
}
|
||||
|
||||
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase {
|
||||
final override string toString() { result = "ConvertToVirtualBase" }
|
||||
}
|
||||
|
||||
class ConvertToDerived extends UnaryOpcode, TConvertToDerived {
|
||||
final override string toString() { result = "ConvertToDerived" }
|
||||
}
|
||||
|
||||
class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull {
|
||||
final override string toString() { result = "CheckedConvertOrNull" }
|
||||
}
|
||||
|
||||
class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow {
|
||||
final override string toString() { result = "CheckedConvertOrThrow" }
|
||||
}
|
||||
|
||||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid {
|
||||
final override string toString() { result = "DynamicCastToVoid" }
|
||||
}
|
||||
|
||||
class VariableAddress extends Opcode, TVariableAddress {
|
||||
final override string toString() { result = "VariableAddress" }
|
||||
}
|
||||
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress {
|
||||
final override string toString() { result = "FieldAddress" }
|
||||
}
|
||||
|
||||
class ElementsAddress extends UnaryOpcode, TElementsAddress {
|
||||
final override string toString() { result = "ElementsAddress" }
|
||||
}
|
||||
|
||||
class FunctionAddress extends Opcode, TFunctionAddress {
|
||||
final override string toString() { result = "FunctionAddress" }
|
||||
}
|
||||
|
||||
class Constant extends Opcode, TConstant {
|
||||
final override string toString() { result = "Constant" }
|
||||
}
|
||||
|
||||
class StringConstant extends Opcode, TStringConstant {
|
||||
final override string toString() { result = "StringConstant" }
|
||||
}
|
||||
|
||||
class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch {
|
||||
final override string toString() { result = "ConditionalBranch" }
|
||||
}
|
||||
|
||||
class Switch extends OpcodeWithCondition, TSwitch {
|
||||
final override string toString() { result = "Switch" }
|
||||
}
|
||||
|
||||
class Call extends Opcode, TCall {
|
||||
final override string toString() { result = "Call" }
|
||||
}
|
||||
|
||||
class CatchByType extends CatchOpcode, TCatchByType {
|
||||
final override string toString() { result = "CatchByType" }
|
||||
}
|
||||
|
||||
class CatchAny extends CatchOpcode, TCatchAny {
|
||||
final override string toString() { result = "CatchAny" }
|
||||
}
|
||||
|
||||
class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue {
|
||||
final override string toString() { result = "ThrowValue" }
|
||||
}
|
||||
|
||||
class ReThrow extends ThrowOpcode, TReThrow {
|
||||
final override string toString() { result = "ReThrow" }
|
||||
}
|
||||
|
||||
class Unwind extends Opcode, TUnwind {
|
||||
final override string toString() { result = "Unwind" }
|
||||
}
|
||||
|
||||
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition {
|
||||
final override string toString() { result = "UnmodeledDefinition" }
|
||||
}
|
||||
|
||||
class UnmodeledUse extends Opcode, TUnmodeledUse {
|
||||
final override string toString() { result = "UnmodeledUse" }
|
||||
}
|
||||
|
||||
class AliasedDefinition extends Opcode, TAliasedDefinition {
|
||||
final override string toString() { result = "AliasedDefinition" }
|
||||
}
|
||||
|
||||
class Phi extends Opcode, TPhi {
|
||||
final override string toString() { result = "Phi" }
|
||||
}
|
||||
|
||||
class BuiltIn extends BuiltInOperationOpcode, TBuiltIn {
|
||||
final override string toString() { result = "BuiltIn" }
|
||||
}
|
||||
|
||||
class VarArgsStart extends BuiltInOperationOpcode, TVarArgsStart {
|
||||
final override string toString() { result = "VarArgsStart" }
|
||||
}
|
||||
|
||||
class VarArgsEnd extends BuiltInOperationOpcode, TVarArgsEnd {
|
||||
final override string toString() { result = "VarArgsEnd" }
|
||||
}
|
||||
|
||||
class VarArg extends BuiltInOperationOpcode, TVarArg {
|
||||
final override string toString() { result = "VarArg" }
|
||||
}
|
||||
|
||||
class VarArgCopy extends BuiltInOperationOpcode, TVarArgCopy {
|
||||
final override string toString() { result = "VarArgCopy" }
|
||||
}
|
||||
|
||||
class CallSideEffect extends MayWriteSideEffectOpcode, TCallSideEffect {
|
||||
final override string toString() { result = "CallSideEffect" }
|
||||
}
|
||||
|
||||
class CallReadSideEffect extends ReadSideEffectOpcode, TCallReadSideEffect {
|
||||
final override string toString() { result = "CallReadSideEffect" }
|
||||
}
|
||||
|
||||
class IndirectReadSideEffect extends ReadSideEffectOpcode, MemoryAccessOpcode,
|
||||
TIndirectReadSideEffect {
|
||||
final override string toString() { result = "IndirectReadSideEffect" }
|
||||
}
|
||||
|
||||
class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode,
|
||||
TIndirectWriteSideEffect {
|
||||
final override string toString() { result = "IndirectWriteSideEffect" }
|
||||
}
|
||||
|
||||
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode,
|
||||
TIndirectMayWriteSideEffect {
|
||||
final override string toString() { result = "IndirectMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect {
|
||||
final override string toString() { result = "BufferReadSideEffect" }
|
||||
}
|
||||
|
||||
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode,
|
||||
TBufferWriteSideEffect {
|
||||
final override string toString() { result = "BufferWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode,
|
||||
TBufferMayWriteSideEffect {
|
||||
final override string toString() { result = "BufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class Chi extends Opcode, TChi {
|
||||
final override string toString() { result = "Chi" }
|
||||
}
|
||||
|
||||
class InlineAsm extends Opcode, TInlineAsm {
|
||||
final override string toString() { result = "InlineAsm" }
|
||||
}
|
||||
|
||||
class Unreached extends Opcode, TUnreached {
|
||||
final override string toString() { result = "Unreached" }
|
||||
}
|
||||
|
||||
class NewObj extends Opcode, TNewObj {
|
||||
final override string toString() { result = "NewObj" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,5 @@ private import internal.TempVariableTagInternal
|
|||
private import Imports::TempVariableTag
|
||||
|
||||
class TempVariableTag extends TTempVariableTag {
|
||||
string toString() {
|
||||
result = getTempVariableTagId(this)
|
||||
}
|
||||
string toString() { result = getTempVariableTagId(this) }
|
||||
}
|
||||
|
|
|
@ -15,21 +15,15 @@ private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
|||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
string toString() { result = "IRPropertyProvider" }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
string getInstructionProperty(Instruction instruction, string key) { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
string getBlockProperty(IRBlock block, string key) { none() }
|
||||
}
|
||||
|
|
|
@ -16,32 +16,25 @@ private import Cached
|
|||
* Most consumers should use the class `IRBlock`.
|
||||
*/
|
||||
class IRBlockBase extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
final string toString() { result = getFirstInstruction(this).toString() }
|
||||
|
||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
||||
|
||||
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction()
|
||||
|
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
|
@ -52,17 +45,11 @@ class IRBlockBase extends TIRBlock {
|
|||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = getInstructionCount(this)
|
||||
}
|
||||
final int getInstructionCount() { result = getInstructionCount(this) }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getFirstInstruction(this).getEnclosingIRFunction()
|
||||
|
@ -79,40 +66,26 @@ class IRBlockBase extends TIRBlock {
|
|||
* instruction of another block.
|
||||
*/
|
||||
class IRBlock extends IRBlockBase {
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
final IRBlock getASuccessor() { blockSuccessor(this, result) }
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
|
@ -125,22 +98,21 @@ class IRBlock extends IRBlockBase {
|
|||
private predicate startsBasicBlock(Instruction instr) {
|
||||
not instr instanceof PhiInstruction and
|
||||
(
|
||||
count(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor()
|
||||
) != 1 or // Multiple predecessors or no predecessor
|
||||
count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor() and
|
||||
strictcount(Instruction other |
|
||||
other = predecessor.getASuccessor()
|
||||
) > 1
|
||||
) or // Predecessor has multiple successors
|
||||
strictcount(Instruction other | other = predecessor.getASuccessor()) > 1
|
||||
) // Predecessor has multiple successors
|
||||
or
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -148,11 +120,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
|||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
cached newtype TIRBlock =
|
||||
MkIRBlock(Instruction firstInstr) {
|
||||
startsBasicBlock(firstInstr)
|
||||
}
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) }
|
||||
|
||||
/** Holds if `i2` follows `i1` in a `IRBlock`. */
|
||||
private predicate adjacentInBlock(Instruction i1, Instruction i2) {
|
||||
|
@ -165,15 +136,16 @@ private cached module Cached {
|
|||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
cached
|
||||
Instruction getInstruction(TIRBlock block, int index) {
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
cached int getInstructionCount(TIRBlock block) {
|
||||
result = strictcount(getInstruction(block, _))
|
||||
}
|
||||
cached
|
||||
int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) }
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = predLast.getSuccessor(kind) and
|
||||
|
@ -185,7 +157,8 @@ private cached module Cached {
|
|||
private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 }
|
||||
|
||||
pragma[noopt]
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
// See the QLDoc on `backEdgeSuccessorRaw`.
|
||||
|
@ -226,14 +199,12 @@ private cached module Cached {
|
|||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) }
|
||||
|
||||
cached predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
cached
|
||||
predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
|
||||
}
|
||||
|
||||
Instruction getFirstInstruction(TIRBlock block) {
|
||||
block = MkIRBlock(result)
|
||||
}
|
||||
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
|
||||
|
|
|
@ -2,9 +2,7 @@ private import internal.IRInternal
|
|||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
|
@ -12,27 +10,19 @@ private newtype TIRFunction =
|
|||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() {
|
||||
this = MkIRFunction(func)
|
||||
}
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
|
@ -64,38 +54,28 @@ class IRFunction extends TIRFunction {
|
|||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
|
||||
final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
final IRBlock getEntryBlock() { result.getFirstInstruction() = getEnterFunctionInstruction() }
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
private import IR
|
||||
import InstructionSanity
|
||||
|
||||
|
|
|
@ -37,27 +37,21 @@ abstract class IRVariable extends TIRVariable {
|
|||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getAST().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result.getFunction() = func
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,34 +59,25 @@ abstract class IRVariable extends TIRVariable {
|
|||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRUserVariable() {
|
||||
this = TIRUserVariable(var, type, func)
|
||||
}
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
override final string toString() {
|
||||
result = getVariable().toString()
|
||||
}
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
Language::Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
Language::Variable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,31 +85,22 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
|||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
IRStaticUserVariable() {
|
||||
not Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRStaticUserVariable() { not Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::StaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
@ -134,55 +110,39 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
|||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
|
||||
TempVariableTag tag;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = ast
|
||||
}
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
final TempVariableTag getTag() { result = tag }
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,11 +12,15 @@ private newtype TOperand =
|
|||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
|
@ -46,24 +50,16 @@ private predicate isInCycle(Instruction instr) {
|
|||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getUse().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getUse().getEnclosingIRFunction()
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getUse() {
|
||||
none()
|
||||
}
|
||||
Instruction getUse() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -71,9 +67,7 @@ class Operand extends TOperand {
|
|||
* means that the resulting instruction may only _partially_ or _potentially_
|
||||
* be the value of this operand.
|
||||
*/
|
||||
Instruction getAnyDef() {
|
||||
none()
|
||||
}
|
||||
Instruction getAnyDef() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -91,10 +85,7 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getUseInstruction() {
|
||||
result = getUse()
|
||||
}
|
||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
|
@ -103,31 +94,22 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getDefinitionInstruction() {
|
||||
result = getAnyDef()
|
||||
}
|
||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
Overlap getDefinitionOverlap() {
|
||||
none()
|
||||
}
|
||||
Overlap getDefinitionOverlap() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||
*/
|
||||
final predicate isDefinitionInexact() {
|
||||
not getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
string getDumpLabel() { result = "" }
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
|
@ -146,18 +128,13 @@ class Operand extends TOperand {
|
|||
* the empty string.
|
||||
*/
|
||||
private string getInexactSpecifier() {
|
||||
if isDefinitionInexact() then
|
||||
result = "~"
|
||||
else
|
||||
result = ""
|
||||
if isDefinitionInexact() then result = "~" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
int getDumpSortOrder() { result = -1 }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
|
@ -166,9 +143,7 @@ class Operand extends TOperand {
|
|||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() {
|
||||
result = getAnyDef().getResultType()
|
||||
}
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
|
@ -177,17 +152,13 @@ class Operand extends TOperand {
|
|||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
*/
|
||||
predicate isGLValue() {
|
||||
getAnyDef().isGLValue()
|
||||
}
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,9 +178,7 @@ class MemoryOperand extends Operand {
|
|||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
MemoryAccessKind getMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
|
@ -227,7 +196,9 @@ class MemoryOperand extends Operand {
|
|||
*/
|
||||
class NonPhiOperand extends Operand {
|
||||
Instruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
|
@ -235,25 +206,15 @@ class NonPhiOperand extends Operand {
|
|||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
|
||||
}
|
||||
|
||||
override final Instruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
final override string getDumpLabel() { result = tag.getLabel() }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = tag.getSortOrder() }
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
final OperandTag getOperandTag() { result = tag }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -262,7 +223,7 @@ class NonPhiOperand extends Operand {
|
|||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
final override Overlap getDefinitionOverlap() {
|
||||
// All register results overlap exactly with their uses.
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
@ -270,21 +231,18 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
|||
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
NonPhiMemoryOperand() {
|
||||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap)
|
||||
}
|
||||
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
}
|
||||
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
override final Language::Type getType() {
|
||||
final override Language::Type getType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
@ -296,9 +254,7 @@ class TypedOperand extends NonPhiMemoryOperand {
|
|||
class AddressOperand extends RegisterOperand {
|
||||
override AddressOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
override string toString() { result = "Address" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,13 +264,9 @@ class AddressOperand extends RegisterOperand {
|
|||
class LoadOperand extends TypedOperand {
|
||||
override LoadOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Load"
|
||||
}
|
||||
override string toString() { result = "Load" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,9 +275,7 @@ class LoadOperand extends TypedOperand {
|
|||
class StoreValueOperand extends RegisterOperand {
|
||||
override StoreValueOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "StoreValue"
|
||||
}
|
||||
override string toString() { result = "StoreValue" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,9 +284,7 @@ class StoreValueOperand extends RegisterOperand {
|
|||
class UnaryOperand extends RegisterOperand {
|
||||
override UnaryOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
override string toString() { result = "Unary" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,9 +293,7 @@ class UnaryOperand extends RegisterOperand {
|
|||
class LeftOperand extends RegisterOperand {
|
||||
override LeftOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
override string toString() { result = "Left" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,9 +302,7 @@ class LeftOperand extends RegisterOperand {
|
|||
class RightOperand extends RegisterOperand {
|
||||
override RightOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
override string toString() { result = "Right" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,9 +311,7 @@ class RightOperand extends RegisterOperand {
|
|||
class ConditionOperand extends RegisterOperand {
|
||||
override ConditionOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
override string toString() { result = "Condition" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,13 +321,9 @@ class ConditionOperand extends RegisterOperand {
|
|||
class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
||||
override UnmodeledUseOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
override string toString() { result = "UnmodeledUse" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,9 +332,7 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
|||
class CallTargetOperand extends RegisterOperand {
|
||||
override CallTargetOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
override string toString() { result = "CallTarget" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,9 +351,7 @@ class ArgumentOperand extends RegisterOperand {
|
|||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
override ThisArgumentOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
override string toString() { result = "ThisArgument" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,32 +359,26 @@ class ThisArgumentOperand extends ArgumentOperand {
|
|||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
override PositionalArgumentOperandTag tag;
|
||||
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
argIndex = tag.getArgIndex()
|
||||
}
|
||||
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
override string toString() { result = "Arg(" + argIndex + ")" }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the argument.
|
||||
*/
|
||||
final int getIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
final int getIndex() { result = argIndex }
|
||||
}
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override final int getSize() {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = Language::getTypeSize(getType())
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
@ -485,48 +413,35 @@ class SideEffectOperand extends TypedOperand {
|
|||
*/
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
PhiInputOperand() {
|
||||
this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
override final PhiInstruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override PhiInstruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
final override string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
final IRBlock getPredecessorBlock() { result = predecessorBlock }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,27 +450,18 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||
class ChiTotalOperand extends NonPhiMemoryOperand {
|
||||
override ChiTotalOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiTotal"
|
||||
}
|
||||
override string toString() { result = "ChiTotal" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiTotalMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The partial operand of a Chi node, representing the value being written to part of the memory.
|
||||
*/
|
||||
class ChiPartialOperand extends NonPhiMemoryOperand {
|
||||
override ChiPartialOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiPartial"
|
||||
}
|
||||
override string toString() { result = "ChiPartial" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiPartialMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess }
|
||||
}
|
||||
|
|
|
@ -9,23 +9,17 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
|||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
string toString() {
|
||||
result = "PrintIRConfiguration"
|
||||
}
|
||||
string toString() { result = "PrintIRConfiguration" }
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Function func) {
|
||||
any()
|
||||
}
|
||||
predicate shouldPrintFunction(Language::Function func) { any() }
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Function func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,27 +32,17 @@ private class FilteredIRConfiguration extends IRConfiguration {
|
|||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key))
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) {
|
||||
shouldPrintFunction(irFunc.getFunction())
|
||||
} or
|
||||
TPrintableIRBlock(IRBlock block) {
|
||||
shouldPrintFunction(block.getEnclosingFunction())
|
||||
} or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
|
@ -85,29 +69,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
string getGraphKind() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
predicate forceText() { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.label" and result = getLabel()
|
||||
or
|
||||
key = "semmle.order" and result = getOrder().toString()
|
||||
or
|
||||
key = "semmle.graphKind" and result = getGraphKind()
|
||||
or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
@ -118,37 +101,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
||||
IRFunction irFunc;
|
||||
|
||||
PrintableIRFunction() {
|
||||
this = TPrintableIRFunction(irFunc)
|
||||
}
|
||||
PrintableIRFunction() { this = TPrintableIRFunction(irFunc) }
|
||||
|
||||
override string toString() {
|
||||
result = irFunc.toString()
|
||||
}
|
||||
override string toString() { result = irFunc.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = irFunc.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = irFunc.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = Language::getIdentityString(irFunc.getFunction())
|
||||
}
|
||||
override string getLabel() { result = Language::getIdentityString(irFunc.getFunction()) }
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location |
|
||||
location = orderedFunc.getIRFunction().getLocation() |
|
||||
orderedFunc order by location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
location = orderedFunc.getIRFunction().getLocation()
|
||||
|
|
||||
orderedFunc
|
||||
order by
|
||||
location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(),
|
||||
orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
final override PrintableIRNode getParent() { none() }
|
||||
|
||||
final IRFunction getIRFunction() {
|
||||
result = irFunc
|
||||
}
|
||||
final IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,35 +131,21 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
|||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
PrintableIRBlock() { this = TPrintableIRBlock(block) }
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
override string toString() { result = getLabel() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = block.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
override string getLabel() { result = "Block " + block.getDisplayIndex().toString() }
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
override int getOrder() { result = block.getDisplayIndex() }
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
final override string getGraphKind() { result = "tree" }
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
final override predicate forceText() { any() }
|
||||
|
||||
override final PrintableIRFunction getParent() {
|
||||
final override PrintableIRFunction getParent() {
|
||||
result.getIRFunction() = block.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
|
@ -194,9 +154,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
final IRBlock getBlock() { result = block }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,45 +163,35 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
PrintableInstruction() { this = TPrintableInstruction(instr) }
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
override string toString() { result = instr.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
exists(
|
||||
string resultString, string operationString, string operandsString, int resultWidth,
|
||||
int operationWidth
|
||||
|
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " +
|
||||
operationString + getPaddingString(operationWidth - operationString.length()) + " : " +
|
||||
operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
override int getOrder() { result = instr.getDisplayIndexInBlock() }
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() }
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
final Instruction getInstruction() { result = instr }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
|
@ -253,19 +201,26 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
|||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
operationWidth = max(Instruction instr |
|
||||
instr.getBlock() = block
|
||||
|
|
||||
instr.getOperationString().length()
|
||||
)
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length()
|
||||
|
|
||||
width
|
||||
)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
|
@ -275,9 +230,10 @@ query predicate nodes(PrintableIRNode node, string key, string value) {
|
|||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
aSucc = pred.getSuccessor(kind)
|
||||
|
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
|
@ -291,11 +247,10 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
or
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,14 +13,10 @@ private newtype TOperandTag =
|
|||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
Language::hasPositionalArgIndex(argIndex)
|
||||
} or
|
||||
TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or
|
||||
TChiTotalOperand() or
|
||||
TChiPartialOperand() or
|
||||
TAsmOperand(int index) {
|
||||
Language::hasAsmOperandIndex(index)
|
||||
}
|
||||
TAsmOperand(int index) { Language::hasAsmOperandIndex(index) }
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
|
@ -28,291 +24,195 @@ private newtype TOperandTag =
|
|||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
string getLabel() { result = "" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
abstract class MemoryOperandTag extends OperandTag {
|
||||
}
|
||||
abstract class MemoryOperandTag extends OperandTag { }
|
||||
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
abstract class RegisterOperandTag extends OperandTag {
|
||||
}
|
||||
abstract class RegisterOperandTag extends OperandTag { }
|
||||
|
||||
/**
|
||||
* A memory operand whose type may be different from the result type of its definition instruction.
|
||||
*/
|
||||
abstract class TypedOperandTag extends MemoryOperandTag {
|
||||
}
|
||||
abstract class TypedOperandTag extends MemoryOperandTag { }
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
|
||||
*/
|
||||
class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||
override final string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
final override string toString() { result = "Address" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "&:"
|
||||
}
|
||||
final override int getSortOrder() { result = 0 }
|
||||
|
||||
final override string getLabel() { result = "&:" }
|
||||
}
|
||||
|
||||
AddressOperandTag addressOperand() {
|
||||
result = TAddressOperand()
|
||||
}
|
||||
AddressOperandTag addressOperand() { result = TAddressOperand() }
|
||||
|
||||
/**
|
||||
* The buffer size operand of an instruction that represents a read or write of
|
||||
* a buffer.
|
||||
*/
|
||||
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
|
||||
override final string toString() {
|
||||
result = "BufferSize"
|
||||
}
|
||||
final override string toString() { result = "BufferSize" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
final override int getSortOrder() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the read side effect of a `SideEffectInstruction`.
|
||||
*/
|
||||
class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||
override final string toString() {
|
||||
result = "SideEffect"
|
||||
}
|
||||
final override string toString() { result = "SideEffect" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
final override int getSortOrder() { result = 2 }
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() {
|
||||
result = TSideEffectOperand()
|
||||
}
|
||||
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
|
||||
* `ReturnValue`, `ThrowValue`).
|
||||
*/
|
||||
class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||
override final string toString() {
|
||||
result = "Load"
|
||||
}
|
||||
final override string toString() { result = "Load" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
final override int getSortOrder() { result = 3 }
|
||||
}
|
||||
|
||||
LoadOperandTag loadOperand() {
|
||||
result = TLoadOperand()
|
||||
}
|
||||
LoadOperandTag loadOperand() { result = TLoadOperand() }
|
||||
|
||||
/**
|
||||
* The source value operand of a `Store` instruction.
|
||||
*/
|
||||
class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||
override final string toString() {
|
||||
result = "StoreValue"
|
||||
}
|
||||
final override string toString() { result = "StoreValue" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
final override int getSortOrder() { result = 4 }
|
||||
}
|
||||
|
||||
StoreValueOperandTag storeValueOperand() {
|
||||
result = TStoreValueOperand()
|
||||
}
|
||||
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
|
||||
*/
|
||||
class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
final override string toString() { result = "Unary" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
final override int getSortOrder() { result = 5 }
|
||||
}
|
||||
|
||||
UnaryOperandTag unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
final override string toString() { result = "Left" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
final override int getSortOrder() { result = 6 }
|
||||
}
|
||||
|
||||
LeftOperandTag leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
LeftOperandTag leftOperand() { result = TLeftOperand() }
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
final override string toString() { result = "Right" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
final override int getSortOrder() { result = 7 }
|
||||
}
|
||||
|
||||
RightOperandTag rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
RightOperandTag rightOperand() { result = TRightOperand() }
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
final override string toString() { result = "Condition" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
final override int getSortOrder() { result = 8 }
|
||||
}
|
||||
|
||||
ConditionOperandTag conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
final override string toString() { result = "UnmodeledUse" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
final override int getSortOrder() { result = 9 }
|
||||
}
|
||||
|
||||
UnmodeledUseOperandTag unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() }
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
final override string toString() { result = "CallTarget" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
final override int getSortOrder() { result = 10 }
|
||||
|
||||
override final string getLabel() {
|
||||
result = "func:"
|
||||
}
|
||||
final override string getLabel() { result = "func:" }
|
||||
}
|
||||
|
||||
CallTargetOperandTag callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperandTag extends RegisterOperandTag {
|
||||
}
|
||||
abstract class ArgumentOperandTag extends RegisterOperandTag { }
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
ThisArgumentOperandTag() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
ThisArgumentOperandTag() { this = TThisArgumentOperand() }
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
final override string toString() { result = "Arg(this)" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11
|
||||
}
|
||||
final override int getSortOrder() { result = 11 }
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
final override string getLabel() { result = "this:" }
|
||||
}
|
||||
|
||||
ThisArgumentOperandTag thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperandTag extends ArgumentOperandTag,
|
||||
TPositionalArgumentOperand {
|
||||
class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperandTag() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
PositionalArgumentOperandTag() { this = TPositionalArgumentOperand(argIndex) }
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
final override string toString() { result = "Arg(" + argIndex + ")" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 12 + argIndex
|
||||
}
|
||||
final override int getSortOrder() { result = 12 + argIndex }
|
||||
|
||||
override final string getLabel() {
|
||||
result = argIndex.toString() + ":"
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
final override string getLabel() { result = argIndex.toString() + ":" }
|
||||
|
||||
final int getArgIndex() { result = argIndex }
|
||||
}
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
|
@ -320,61 +220,35 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
|||
}
|
||||
|
||||
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
|
||||
override final string toString() {
|
||||
result = "ChiTotal"
|
||||
}
|
||||
final override string toString() { result = "ChiTotal" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 13
|
||||
}
|
||||
final override int getSortOrder() { result = 13 }
|
||||
|
||||
override final string getLabel() {
|
||||
result = "total:"
|
||||
}
|
||||
final override string getLabel() { result = "total:" }
|
||||
}
|
||||
|
||||
ChiTotalOperandTag chiTotalOperand() {
|
||||
result = TChiTotalOperand()
|
||||
}
|
||||
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
|
||||
|
||||
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||
override final string toString() {
|
||||
result = "ChiPartial"
|
||||
}
|
||||
final override string toString() { result = "ChiPartial" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 14
|
||||
}
|
||||
final override int getSortOrder() { result = 14 }
|
||||
|
||||
override final string getLabel() {
|
||||
result = "partial:"
|
||||
}
|
||||
final override string getLabel() { result = "partial:" }
|
||||
}
|
||||
|
||||
ChiPartialOperandTag chiPartialOperand() {
|
||||
result = TChiPartialOperand()
|
||||
}
|
||||
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }
|
||||
|
||||
class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
|
||||
int index;
|
||||
|
||||
AsmOperandTag() {
|
||||
this = TAsmOperand(index)
|
||||
}
|
||||
AsmOperandTag() { this = TAsmOperand(index) }
|
||||
|
||||
override final string toString() {
|
||||
result = "AsmOperand(" + index + ")"
|
||||
}
|
||||
final override string toString() { result = "AsmOperand(" + index + ")" }
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 15 + index
|
||||
}
|
||||
final override int getSortOrder() { result = 15 + index }
|
||||
|
||||
override final string getLabel() {
|
||||
result = index.toString() + ":"
|
||||
}
|
||||
final override string getLabel() { result = index.toString() + ":" }
|
||||
}
|
||||
|
||||
AsmOperandTag asmOperand(int index) {
|
||||
result = TAsmOperand(index)
|
||||
}
|
||||
AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) }
|
||||
|
|
|
@ -2,11 +2,11 @@ private import TIRVariableInternal
|
|||
private import Imports::TempVariableTag
|
||||
|
||||
newtype TIRVariable =
|
||||
TIRUserVariable(Language::Variable var, Language::Type type,
|
||||
Language::Function func) {
|
||||
TIRUserVariable(Language::Variable var, Language::Type type, Language::Function func) {
|
||||
Construction::hasUserVariable(func, var, type)
|
||||
} or
|
||||
TIRTempVariable(Language::Function func, Language::AST ast, TempVariableTag tag,
|
||||
Language::Type type) {
|
||||
TIRTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type
|
||||
) {
|
||||
Construction::hasTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
|
|
@ -15,21 +15,15 @@ private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
|||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
string toString() { result = "IRPropertyProvider" }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
string getInstructionProperty(Instruction instruction, string key) { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
string getBlockProperty(IRBlock block, string key) { none() }
|
||||
}
|
||||
|
|
|
@ -16,32 +16,25 @@ private import Cached
|
|||
* Most consumers should use the class `IRBlock`.
|
||||
*/
|
||||
class IRBlockBase extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
final string toString() { result = getFirstInstruction(this).toString() }
|
||||
|
||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
||||
|
||||
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction()
|
||||
|
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
|
@ -52,17 +45,11 @@ class IRBlockBase extends TIRBlock {
|
|||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = getInstructionCount(this)
|
||||
}
|
||||
final int getInstructionCount() { result = getInstructionCount(this) }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getFirstInstruction(this).getEnclosingIRFunction()
|
||||
|
@ -79,40 +66,26 @@ class IRBlockBase extends TIRBlock {
|
|||
* instruction of another block.
|
||||
*/
|
||||
class IRBlock extends IRBlockBase {
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
final IRBlock getASuccessor() { blockSuccessor(this, result) }
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
|
@ -125,22 +98,21 @@ class IRBlock extends IRBlockBase {
|
|||
private predicate startsBasicBlock(Instruction instr) {
|
||||
not instr instanceof PhiInstruction and
|
||||
(
|
||||
count(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor()
|
||||
) != 1 or // Multiple predecessors or no predecessor
|
||||
count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor() and
|
||||
strictcount(Instruction other |
|
||||
other = predecessor.getASuccessor()
|
||||
) > 1
|
||||
) or // Predecessor has multiple successors
|
||||
strictcount(Instruction other | other = predecessor.getASuccessor()) > 1
|
||||
) // Predecessor has multiple successors
|
||||
or
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -148,11 +120,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
|||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
cached newtype TIRBlock =
|
||||
MkIRBlock(Instruction firstInstr) {
|
||||
startsBasicBlock(firstInstr)
|
||||
}
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) }
|
||||
|
||||
/** Holds if `i2` follows `i1` in a `IRBlock`. */
|
||||
private predicate adjacentInBlock(Instruction i1, Instruction i2) {
|
||||
|
@ -165,15 +136,16 @@ private cached module Cached {
|
|||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
cached
|
||||
Instruction getInstruction(TIRBlock block, int index) {
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
cached int getInstructionCount(TIRBlock block) {
|
||||
result = strictcount(getInstruction(block, _))
|
||||
}
|
||||
cached
|
||||
int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) }
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = predLast.getSuccessor(kind) and
|
||||
|
@ -185,7 +157,8 @@ private cached module Cached {
|
|||
private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 }
|
||||
|
||||
pragma[noopt]
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
// See the QLDoc on `backEdgeSuccessorRaw`.
|
||||
|
@ -226,14 +199,12 @@ private cached module Cached {
|
|||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) }
|
||||
|
||||
cached predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
cached
|
||||
predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
|
||||
}
|
||||
|
||||
Instruction getFirstInstruction(TIRBlock block) {
|
||||
block = MkIRBlock(result)
|
||||
}
|
||||
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
|
||||
|
|
|
@ -2,9 +2,7 @@ private import internal.IRInternal
|
|||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
|
@ -12,27 +10,19 @@ private newtype TIRFunction =
|
|||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() {
|
||||
this = MkIRFunction(func)
|
||||
}
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
|
@ -64,38 +54,28 @@ class IRFunction extends TIRFunction {
|
|||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
|
||||
final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
final IRBlock getEntryBlock() { result.getFirstInstruction() = getEnterFunctionInstruction() }
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
private import IR
|
||||
import InstructionSanity
|
||||
|
||||
|
|
|
@ -37,27 +37,21 @@ abstract class IRVariable extends TIRVariable {
|
|||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getAST().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result.getFunction() = func
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,34 +59,25 @@ abstract class IRVariable extends TIRVariable {
|
|||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRUserVariable() {
|
||||
this = TIRUserVariable(var, type, func)
|
||||
}
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
override final string toString() {
|
||||
result = getVariable().toString()
|
||||
}
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
Language::Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
Language::Variable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,31 +85,22 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
|||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
IRStaticUserVariable() {
|
||||
not Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRStaticUserVariable() { not Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::StaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
@ -134,55 +110,39 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
|||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
|
||||
TempVariableTag tag;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = ast
|
||||
}
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
final TempVariableTag getTag() { result = tag }
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,11 +12,15 @@ private newtype TOperand =
|
|||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
|
@ -46,24 +50,16 @@ private predicate isInCycle(Instruction instr) {
|
|||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getUse().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getUse().getEnclosingIRFunction()
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getUse() {
|
||||
none()
|
||||
}
|
||||
Instruction getUse() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -71,9 +67,7 @@ class Operand extends TOperand {
|
|||
* means that the resulting instruction may only _partially_ or _potentially_
|
||||
* be the value of this operand.
|
||||
*/
|
||||
Instruction getAnyDef() {
|
||||
none()
|
||||
}
|
||||
Instruction getAnyDef() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -91,10 +85,7 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getUseInstruction() {
|
||||
result = getUse()
|
||||
}
|
||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
|
@ -103,31 +94,22 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getDefinitionInstruction() {
|
||||
result = getAnyDef()
|
||||
}
|
||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
Overlap getDefinitionOverlap() {
|
||||
none()
|
||||
}
|
||||
Overlap getDefinitionOverlap() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||
*/
|
||||
final predicate isDefinitionInexact() {
|
||||
not getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
string getDumpLabel() { result = "" }
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
|
@ -146,18 +128,13 @@ class Operand extends TOperand {
|
|||
* the empty string.
|
||||
*/
|
||||
private string getInexactSpecifier() {
|
||||
if isDefinitionInexact() then
|
||||
result = "~"
|
||||
else
|
||||
result = ""
|
||||
if isDefinitionInexact() then result = "~" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
int getDumpSortOrder() { result = -1 }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
|
@ -166,9 +143,7 @@ class Operand extends TOperand {
|
|||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() {
|
||||
result = getAnyDef().getResultType()
|
||||
}
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
|
@ -177,17 +152,13 @@ class Operand extends TOperand {
|
|||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
*/
|
||||
predicate isGLValue() {
|
||||
getAnyDef().isGLValue()
|
||||
}
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,9 +178,7 @@ class MemoryOperand extends Operand {
|
|||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
MemoryAccessKind getMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
|
@ -227,7 +196,9 @@ class MemoryOperand extends Operand {
|
|||
*/
|
||||
class NonPhiOperand extends Operand {
|
||||
Instruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
|
@ -235,25 +206,15 @@ class NonPhiOperand extends Operand {
|
|||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
|
||||
}
|
||||
|
||||
override final Instruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
final override string getDumpLabel() { result = tag.getLabel() }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = tag.getSortOrder() }
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
final OperandTag getOperandTag() { result = tag }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -262,7 +223,7 @@ class NonPhiOperand extends Operand {
|
|||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
final override Overlap getDefinitionOverlap() {
|
||||
// All register results overlap exactly with their uses.
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
@ -270,21 +231,18 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
|||
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
NonPhiMemoryOperand() {
|
||||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap)
|
||||
}
|
||||
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
}
|
||||
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
override final Language::Type getType() {
|
||||
final override Language::Type getType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
@ -296,9 +254,7 @@ class TypedOperand extends NonPhiMemoryOperand {
|
|||
class AddressOperand extends RegisterOperand {
|
||||
override AddressOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
override string toString() { result = "Address" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,13 +264,9 @@ class AddressOperand extends RegisterOperand {
|
|||
class LoadOperand extends TypedOperand {
|
||||
override LoadOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Load"
|
||||
}
|
||||
override string toString() { result = "Load" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,9 +275,7 @@ class LoadOperand extends TypedOperand {
|
|||
class StoreValueOperand extends RegisterOperand {
|
||||
override StoreValueOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "StoreValue"
|
||||
}
|
||||
override string toString() { result = "StoreValue" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,9 +284,7 @@ class StoreValueOperand extends RegisterOperand {
|
|||
class UnaryOperand extends RegisterOperand {
|
||||
override UnaryOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
override string toString() { result = "Unary" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,9 +293,7 @@ class UnaryOperand extends RegisterOperand {
|
|||
class LeftOperand extends RegisterOperand {
|
||||
override LeftOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
override string toString() { result = "Left" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,9 +302,7 @@ class LeftOperand extends RegisterOperand {
|
|||
class RightOperand extends RegisterOperand {
|
||||
override RightOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
override string toString() { result = "Right" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,9 +311,7 @@ class RightOperand extends RegisterOperand {
|
|||
class ConditionOperand extends RegisterOperand {
|
||||
override ConditionOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
override string toString() { result = "Condition" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,13 +321,9 @@ class ConditionOperand extends RegisterOperand {
|
|||
class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
||||
override UnmodeledUseOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
override string toString() { result = "UnmodeledUse" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,9 +332,7 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
|||
class CallTargetOperand extends RegisterOperand {
|
||||
override CallTargetOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
override string toString() { result = "CallTarget" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,9 +351,7 @@ class ArgumentOperand extends RegisterOperand {
|
|||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
override ThisArgumentOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
override string toString() { result = "ThisArgument" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,32 +359,26 @@ class ThisArgumentOperand extends ArgumentOperand {
|
|||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
override PositionalArgumentOperandTag tag;
|
||||
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
argIndex = tag.getArgIndex()
|
||||
}
|
||||
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
override string toString() { result = "Arg(" + argIndex + ")" }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the argument.
|
||||
*/
|
||||
final int getIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
final int getIndex() { result = argIndex }
|
||||
}
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override final int getSize() {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = Language::getTypeSize(getType())
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
@ -485,48 +413,35 @@ class SideEffectOperand extends TypedOperand {
|
|||
*/
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
PhiInputOperand() {
|
||||
this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
override final PhiInstruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override PhiInstruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
final override string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
final IRBlock getPredecessorBlock() { result = predecessorBlock }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,27 +450,18 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||
class ChiTotalOperand extends NonPhiMemoryOperand {
|
||||
override ChiTotalOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiTotal"
|
||||
}
|
||||
override string toString() { result = "ChiTotal" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiTotalMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The partial operand of a Chi node, representing the value being written to part of the memory.
|
||||
*/
|
||||
class ChiPartialOperand extends NonPhiMemoryOperand {
|
||||
override ChiPartialOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiPartial"
|
||||
}
|
||||
override string toString() { result = "ChiPartial" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiPartialMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess }
|
||||
}
|
||||
|
|
|
@ -9,23 +9,17 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
|||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
string toString() {
|
||||
result = "PrintIRConfiguration"
|
||||
}
|
||||
string toString() { result = "PrintIRConfiguration" }
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Function func) {
|
||||
any()
|
||||
}
|
||||
predicate shouldPrintFunction(Language::Function func) { any() }
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Function func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,27 +32,17 @@ private class FilteredIRConfiguration extends IRConfiguration {
|
|||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key))
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) {
|
||||
shouldPrintFunction(irFunc.getFunction())
|
||||
} or
|
||||
TPrintableIRBlock(IRBlock block) {
|
||||
shouldPrintFunction(block.getEnclosingFunction())
|
||||
} or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
|
@ -85,29 +69,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
string getGraphKind() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
predicate forceText() { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.label" and result = getLabel()
|
||||
or
|
||||
key = "semmle.order" and result = getOrder().toString()
|
||||
or
|
||||
key = "semmle.graphKind" and result = getGraphKind()
|
||||
or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
@ -118,37 +101,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
||||
IRFunction irFunc;
|
||||
|
||||
PrintableIRFunction() {
|
||||
this = TPrintableIRFunction(irFunc)
|
||||
}
|
||||
PrintableIRFunction() { this = TPrintableIRFunction(irFunc) }
|
||||
|
||||
override string toString() {
|
||||
result = irFunc.toString()
|
||||
}
|
||||
override string toString() { result = irFunc.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = irFunc.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = irFunc.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = Language::getIdentityString(irFunc.getFunction())
|
||||
}
|
||||
override string getLabel() { result = Language::getIdentityString(irFunc.getFunction()) }
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location |
|
||||
location = orderedFunc.getIRFunction().getLocation() |
|
||||
orderedFunc order by location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
location = orderedFunc.getIRFunction().getLocation()
|
||||
|
|
||||
orderedFunc
|
||||
order by
|
||||
location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(),
|
||||
orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
final override PrintableIRNode getParent() { none() }
|
||||
|
||||
final IRFunction getIRFunction() {
|
||||
result = irFunc
|
||||
}
|
||||
final IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,35 +131,21 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
|||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
PrintableIRBlock() { this = TPrintableIRBlock(block) }
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
override string toString() { result = getLabel() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = block.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
override string getLabel() { result = "Block " + block.getDisplayIndex().toString() }
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
override int getOrder() { result = block.getDisplayIndex() }
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
final override string getGraphKind() { result = "tree" }
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
final override predicate forceText() { any() }
|
||||
|
||||
override final PrintableIRFunction getParent() {
|
||||
final override PrintableIRFunction getParent() {
|
||||
result.getIRFunction() = block.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
|
@ -194,9 +154,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
final IRBlock getBlock() { result = block }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,45 +163,35 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
PrintableInstruction() { this = TPrintableInstruction(instr) }
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
override string toString() { result = instr.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
exists(
|
||||
string resultString, string operationString, string operandsString, int resultWidth,
|
||||
int operationWidth
|
||||
|
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " +
|
||||
operationString + getPaddingString(operationWidth - operationString.length()) + " : " +
|
||||
operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
override int getOrder() { result = instr.getDisplayIndexInBlock() }
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() }
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
final Instruction getInstruction() { result = instr }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
|
@ -253,19 +201,26 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
|||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
operationWidth = max(Instruction instr |
|
||||
instr.getBlock() = block
|
||||
|
|
||||
instr.getOperationString().length()
|
||||
)
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length()
|
||||
|
|
||||
width
|
||||
)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
|
@ -275,9 +230,10 @@ query predicate nodes(PrintableIRNode node, string key, string value) {
|
|||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
aSucc = pred.getSuccessor(kind)
|
||||
|
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
|
@ -291,11 +247,10 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
or
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,21 +15,15 @@ private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
|||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
string toString() { result = "IRPropertyProvider" }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
string getInstructionProperty(Instruction instruction, string key) { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
string getBlockProperty(IRBlock block, string key) { none() }
|
||||
}
|
||||
|
|
|
@ -16,32 +16,25 @@ private import Cached
|
|||
* Most consumers should use the class `IRBlock`.
|
||||
*/
|
||||
class IRBlockBase extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
final string toString() { result = getFirstInstruction(this).toString() }
|
||||
|
||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
||||
|
||||
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
funcBlock.getEnclosingFunction() = getEnclosingFunction()
|
||||
|
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
|
@ -52,17 +45,11 @@ class IRBlockBase extends TIRBlock {
|
|||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = getInstructionCount(this)
|
||||
}
|
||||
final int getInstructionCount() { result = getInstructionCount(this) }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getFirstInstruction(this).getEnclosingIRFunction()
|
||||
|
@ -79,40 +66,26 @@ class IRBlockBase extends TIRBlock {
|
|||
* instruction of another block.
|
||||
*/
|
||||
class IRBlock extends IRBlockBase {
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
final IRBlock getASuccessor() { blockSuccessor(this, result) }
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
|
@ -125,22 +98,21 @@ class IRBlock extends IRBlockBase {
|
|||
private predicate startsBasicBlock(Instruction instr) {
|
||||
not instr instanceof PhiInstruction and
|
||||
(
|
||||
count(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor()
|
||||
) != 1 or // Multiple predecessors or no predecessor
|
||||
count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = predecessor.getASuccessor() and
|
||||
strictcount(Instruction other |
|
||||
other = predecessor.getASuccessor()
|
||||
) > 1
|
||||
) or // Predecessor has multiple successors
|
||||
strictcount(Instruction other | other = predecessor.getASuccessor()) > 1
|
||||
) // Predecessor has multiple successors
|
||||
or
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
or
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -148,11 +120,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
|||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
cached newtype TIRBlock =
|
||||
MkIRBlock(Instruction firstInstr) {
|
||||
startsBasicBlock(firstInstr)
|
||||
}
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) }
|
||||
|
||||
/** Holds if `i2` follows `i1` in a `IRBlock`. */
|
||||
private predicate adjacentInBlock(Instruction i1, Instruction i2) {
|
||||
|
@ -165,15 +136,16 @@ private cached module Cached {
|
|||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
cached
|
||||
Instruction getInstruction(TIRBlock block, int index) {
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
cached int getInstructionCount(TIRBlock block) {
|
||||
result = strictcount(getInstruction(block, _))
|
||||
}
|
||||
cached
|
||||
int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) }
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = predLast.getSuccessor(kind) and
|
||||
|
@ -185,7 +157,8 @@ private cached module Cached {
|
|||
private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 }
|
||||
|
||||
pragma[noopt]
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
cached
|
||||
predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
// See the QLDoc on `backEdgeSuccessorRaw`.
|
||||
|
@ -226,14 +199,12 @@ private cached module Cached {
|
|||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
cached
|
||||
predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) }
|
||||
|
||||
cached predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
cached
|
||||
predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
|
||||
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
|
||||
}
|
||||
|
||||
Instruction getFirstInstruction(TIRBlock block) {
|
||||
block = MkIRBlock(result)
|
||||
}
|
||||
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
|
||||
|
|
|
@ -2,9 +2,7 @@ private import internal.IRInternal
|
|||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
|
@ -12,27 +10,19 @@ private newtype TIRFunction =
|
|||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() {
|
||||
this = MkIRFunction(func)
|
||||
}
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
|
@ -64,38 +54,28 @@ class IRFunction extends TIRFunction {
|
|||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
|
||||
final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
final IRBlock getEntryBlock() { result.getFirstInstruction() = getEnterFunctionInstruction() }
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getEnclosingIRFunction() = this
|
||||
}
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
private import IR
|
||||
import InstructionSanity
|
||||
|
||||
|
|
|
@ -37,27 +37,21 @@ abstract class IRVariable extends TIRVariable {
|
|||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Language::Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getAST().getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result.getFunction() = func
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = func
|
||||
}
|
||||
final Language::Function getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,34 +59,25 @@ abstract class IRVariable extends TIRVariable {
|
|||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRUserVariable() {
|
||||
this = TIRUserVariable(var, type, func)
|
||||
}
|
||||
IRUserVariable() { this = TIRUserVariable(var, type, func) }
|
||||
|
||||
override final string toString() {
|
||||
result = getVariable().toString()
|
||||
}
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
Language::Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
Language::Variable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,31 +85,22 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
|||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
abstract class IRAutomaticVariable extends IRVariable { }
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRAutomaticUserVariable() { Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::AutomaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
IRStaticUserVariable() {
|
||||
not Language::isVariableAutomatic(var)
|
||||
}
|
||||
IRStaticUserVariable() { not Language::isVariableAutomatic(var) }
|
||||
|
||||
final override Language::StaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
final override Language::StaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
@ -134,55 +110,39 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
|||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Language::AST ast;
|
||||
|
||||
TempVariableTag tag;
|
||||
|
||||
Language::Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
final override Language::Type getType() { result = type }
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = ast
|
||||
}
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override final string getUniqueId() {
|
||||
final override string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
final TempVariableTag getTag() { result = tag }
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
string getBaseString() { result = "#temp" }
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
IRReturnVariable() { tag = ReturnValueTempVar() }
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
final override string toString() { result = "#return" }
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
IRThrowVariable() { tag = ThrowTempVar() }
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
override string getBaseString() { result = "#throw" }
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,11 +12,15 @@ private newtype TOperand =
|
|||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
|
@ -46,24 +50,16 @@ private predicate isInCycle(Instruction instr) {
|
|||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
result = getUse().getLocation()
|
||||
}
|
||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getUse().getEnclosingIRFunction()
|
||||
}
|
||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getUse() {
|
||||
none()
|
||||
}
|
||||
Instruction getUse() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -71,9 +67,7 @@ class Operand extends TOperand {
|
|||
* means that the resulting instruction may only _partially_ or _potentially_
|
||||
* be the value of this operand.
|
||||
*/
|
||||
Instruction getAnyDef() {
|
||||
none()
|
||||
}
|
||||
Instruction getAnyDef() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
|
@ -91,10 +85,7 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getUseInstruction() {
|
||||
result = getUse()
|
||||
}
|
||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
|
@ -103,31 +94,22 @@ class Operand extends TOperand {
|
|||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getDefinitionInstruction() {
|
||||
result = getAnyDef()
|
||||
}
|
||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
Overlap getDefinitionOverlap() {
|
||||
none()
|
||||
}
|
||||
Overlap getDefinitionOverlap() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||
*/
|
||||
final predicate isDefinitionInexact() {
|
||||
not getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
string getDumpLabel() { result = "" }
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
|
@ -146,18 +128,13 @@ class Operand extends TOperand {
|
|||
* the empty string.
|
||||
*/
|
||||
private string getInexactSpecifier() {
|
||||
if isDefinitionInexact() then
|
||||
result = "~"
|
||||
else
|
||||
result = ""
|
||||
if isDefinitionInexact() then result = "~" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
int getDumpSortOrder() { result = -1 }
|
||||
|
||||
/**
|
||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||
|
@ -166,9 +143,7 @@ class Operand extends TOperand {
|
|||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Language::Type getType() {
|
||||
result = getAnyDef().getResultType()
|
||||
}
|
||||
Language::Type getType() { result = getAnyDef().getResultType() }
|
||||
|
||||
/**
|
||||
* Holds if the value consumed by this operand is a glvalue. If this
|
||||
|
@ -177,17 +152,13 @@ class Operand extends TOperand {
|
|||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
*/
|
||||
predicate isGLValue() {
|
||||
getAnyDef().isGLValue()
|
||||
}
|
||||
predicate isGLValue() { getAnyDef().isGLValue() }
|
||||
|
||||
/**
|
||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
int getSize() { result = Language::getTypeSize(getType()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,9 +178,7 @@ class MemoryOperand extends Operand {
|
|||
/**
|
||||
* Gets the kind of memory access performed by the operand.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
MemoryAccessKind getMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
|
@ -227,7 +196,9 @@ class MemoryOperand extends Operand {
|
|||
*/
|
||||
class NonPhiOperand extends Operand {
|
||||
Instruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
|
@ -235,25 +206,15 @@ class NonPhiOperand extends Operand {
|
|||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
|
||||
}
|
||||
|
||||
override final Instruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
final override string getDumpLabel() { result = tag.getLabel() }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = tag.getSortOrder() }
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
final OperandTag getOperandTag() { result = tag }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -262,7 +223,7 @@ class NonPhiOperand extends Operand {
|
|||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
final override Overlap getDefinitionOverlap() {
|
||||
// All register results overlap exactly with their uses.
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
@ -270,21 +231,18 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
|||
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
NonPhiMemoryOperand() {
|
||||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap)
|
||||
}
|
||||
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
}
|
||||
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
override final Language::Type getType() {
|
||||
final override Language::Type getType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
@ -296,9 +254,7 @@ class TypedOperand extends NonPhiMemoryOperand {
|
|||
class AddressOperand extends RegisterOperand {
|
||||
override AddressOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
override string toString() { result = "Address" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,13 +264,9 @@ class AddressOperand extends RegisterOperand {
|
|||
class LoadOperand extends TypedOperand {
|
||||
override LoadOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Load"
|
||||
}
|
||||
override string toString() { result = "Load" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,9 +275,7 @@ class LoadOperand extends TypedOperand {
|
|||
class StoreValueOperand extends RegisterOperand {
|
||||
override StoreValueOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "StoreValue"
|
||||
}
|
||||
override string toString() { result = "StoreValue" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,9 +284,7 @@ class StoreValueOperand extends RegisterOperand {
|
|||
class UnaryOperand extends RegisterOperand {
|
||||
override UnaryOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
override string toString() { result = "Unary" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,9 +293,7 @@ class UnaryOperand extends RegisterOperand {
|
|||
class LeftOperand extends RegisterOperand {
|
||||
override LeftOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
override string toString() { result = "Left" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,9 +302,7 @@ class LeftOperand extends RegisterOperand {
|
|||
class RightOperand extends RegisterOperand {
|
||||
override RightOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
override string toString() { result = "Right" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,9 +311,7 @@ class RightOperand extends RegisterOperand {
|
|||
class ConditionOperand extends RegisterOperand {
|
||||
override ConditionOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
override string toString() { result = "Condition" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,13 +321,9 @@ class ConditionOperand extends RegisterOperand {
|
|||
class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
||||
override UnmodeledUseOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
override string toString() { result = "UnmodeledUse" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,9 +332,7 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
|
|||
class CallTargetOperand extends RegisterOperand {
|
||||
override CallTargetOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
override string toString() { result = "CallTarget" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,9 +351,7 @@ class ArgumentOperand extends RegisterOperand {
|
|||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
override ThisArgumentOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
override string toString() { result = "ThisArgument" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,32 +359,26 @@ class ThisArgumentOperand extends ArgumentOperand {
|
|||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
override PositionalArgumentOperandTag tag;
|
||||
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
argIndex = tag.getArgIndex()
|
||||
}
|
||||
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
override string toString() { result = "Arg(" + argIndex + ")" }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the argument.
|
||||
*/
|
||||
final int getIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
final int getIndex() { result = argIndex }
|
||||
}
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override final int getSize() {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = Language::getTypeSize(getType())
|
||||
final override int getSize() {
|
||||
if getType() instanceof Language::UnknownType
|
||||
then result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
@ -485,48 +413,35 @@ class SideEffectOperand extends TypedOperand {
|
|||
*/
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
|
||||
Instruction defInstr;
|
||||
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
Overlap overlap;
|
||||
|
||||
PhiInputOperand() {
|
||||
this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
override final PhiInstruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
final override PhiInstruction getUse() { result = useInstr }
|
||||
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
final override Instruction getAnyDef() { result = defInstr }
|
||||
|
||||
override final Overlap getDefinitionOverlap() {
|
||||
result = overlap
|
||||
}
|
||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
||||
|
||||
override final string getDumpLabel() {
|
||||
final override string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
final IRBlock getPredecessorBlock() { result = predecessorBlock }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,27 +450,18 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||
class ChiTotalOperand extends NonPhiMemoryOperand {
|
||||
override ChiTotalOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiTotal"
|
||||
}
|
||||
override string toString() { result = "ChiTotal" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiTotalMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The partial operand of a Chi node, representing the value being written to part of the memory.
|
||||
*/
|
||||
class ChiPartialOperand extends NonPhiMemoryOperand {
|
||||
override ChiPartialOperandTag tag;
|
||||
|
||||
override string toString() {
|
||||
result = "ChiPartial"
|
||||
}
|
||||
override string toString() { result = "ChiPartial" }
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof ChiPartialMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess }
|
||||
}
|
||||
|
|
|
@ -9,23 +9,17 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
|||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
string toString() {
|
||||
result = "PrintIRConfiguration"
|
||||
}
|
||||
string toString() { result = "PrintIRConfiguration" }
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Function func) {
|
||||
any()
|
||||
}
|
||||
predicate shouldPrintFunction(Language::Function func) { any() }
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Function func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,27 +32,17 @@ private class FilteredIRConfiguration extends IRConfiguration {
|
|||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key))
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) {
|
||||
shouldPrintFunction(irFunc.getFunction())
|
||||
} or
|
||||
TPrintableIRBlock(IRBlock block) {
|
||||
shouldPrintFunction(block.getEnclosingFunction())
|
||||
} or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
|
@ -85,29 +69,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
string getGraphKind() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
predicate forceText() { none() }
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.label" and result = getLabel()
|
||||
or
|
||||
key = "semmle.order" and result = getOrder().toString()
|
||||
or
|
||||
key = "semmle.graphKind" and result = getGraphKind()
|
||||
or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
@ -118,37 +101,28 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
|||
class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
||||
IRFunction irFunc;
|
||||
|
||||
PrintableIRFunction() {
|
||||
this = TPrintableIRFunction(irFunc)
|
||||
}
|
||||
PrintableIRFunction() { this = TPrintableIRFunction(irFunc) }
|
||||
|
||||
override string toString() {
|
||||
result = irFunc.toString()
|
||||
}
|
||||
override string toString() { result = irFunc.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = irFunc.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = irFunc.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = Language::getIdentityString(irFunc.getFunction())
|
||||
}
|
||||
override string getLabel() { result = Language::getIdentityString(irFunc.getFunction()) }
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location |
|
||||
location = orderedFunc.getIRFunction().getLocation() |
|
||||
orderedFunc order by location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
location = orderedFunc.getIRFunction().getLocation()
|
||||
|
|
||||
orderedFunc
|
||||
order by
|
||||
location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(),
|
||||
orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
final override PrintableIRNode getParent() { none() }
|
||||
|
||||
final IRFunction getIRFunction() {
|
||||
result = irFunc
|
||||
}
|
||||
final IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,35 +131,21 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
|||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
PrintableIRBlock() { this = TPrintableIRBlock(block) }
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
override string toString() { result = getLabel() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = block.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
override string getLabel() { result = "Block " + block.getDisplayIndex().toString() }
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
override int getOrder() { result = block.getDisplayIndex() }
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
final override string getGraphKind() { result = "tree" }
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
final override predicate forceText() { any() }
|
||||
|
||||
override final PrintableIRFunction getParent() {
|
||||
final override PrintableIRFunction getParent() {
|
||||
result.getIRFunction() = block.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
|
@ -194,9 +154,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
final IRBlock getBlock() { result = block }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,45 +163,35 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
|||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
PrintableInstruction() { this = TPrintableInstruction(instr) }
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
override string toString() { result = instr.toString() }
|
||||
|
||||
override Language::Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
override Language::Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
exists(
|
||||
string resultString, string operationString, string operandsString, int resultWidth,
|
||||
int operationWidth
|
||||
|
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " +
|
||||
operationString + getPaddingString(operationWidth - operationString.length()) + " : " +
|
||||
operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
override int getOrder() { result = instr.getDisplayIndexInBlock() }
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() }
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
final Instruction getInstruction() { result = instr }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
|
@ -253,19 +201,26 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
|||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
operationWidth = max(Instruction instr |
|
||||
instr.getBlock() = block
|
||||
|
|
||||
instr.getOperationString().length()
|
||||
)
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length()
|
||||
|
|
||||
width
|
||||
)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
|
@ -275,9 +230,10 @@ query predicate nodes(PrintableIRNode node, string key, string value) {
|
|||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
aSucc = pred.getSuccessor(kind)
|
||||
|
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
|
@ -291,11 +247,10 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
or
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,56 +3,42 @@ class IntValue = int;
|
|||
/**
|
||||
* Returns the value of the maximum representable integer.
|
||||
*/
|
||||
int maxValue() {
|
||||
result = 2147483647
|
||||
}
|
||||
int maxValue() { result = 2147483647 }
|
||||
|
||||
/**
|
||||
* Returns the value of the minimum representable integer.
|
||||
*/
|
||||
int minValue() {
|
||||
result = -2147483647
|
||||
}
|
||||
int minValue() { result = -2147483647 }
|
||||
|
||||
/**
|
||||
* Returns a value representing an unknown integer.
|
||||
*/
|
||||
IntValue unknown() {
|
||||
result = -2147483648
|
||||
}
|
||||
IntValue unknown() { result = -2147483648 }
|
||||
|
||||
/**
|
||||
* Holds if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
predicate hasValue(IntValue n) {
|
||||
n != unknown()
|
||||
}
|
||||
predicate hasValue(IntValue n) { n != unknown() }
|
||||
|
||||
/**
|
||||
* Returns a string representation of `n`. If `n` does not have a known value, the result is "??".
|
||||
*/
|
||||
bindingset[n]
|
||||
string intValueToString(IntValue n) {
|
||||
if hasValue(n) then result = n.toString() else result = "??"
|
||||
}
|
||||
string intValueToString(IntValue n) { if hasValue(n) then result = n.toString() else result = "??" }
|
||||
|
||||
/**
|
||||
* Holds if the value `f` is within the range of representable integers.
|
||||
*/
|
||||
pragma[inline]
|
||||
bindingset[f]
|
||||
private predicate isRepresentable(float f) {
|
||||
(f >= minValue()) and (f <= maxValue())
|
||||
}
|
||||
pragma[inline]
|
||||
private predicate isRepresentable(float f) { f >= minValue() and f <= maxValue() }
|
||||
|
||||
/**
|
||||
* Gets the value of `n`. Holds only if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
int getValue(IntValue n) {
|
||||
hasValue(n) and result = n
|
||||
}
|
||||
int getValue(IntValue n) { hasValue(n) and result = n }
|
||||
|
||||
/**
|
||||
* Returns `a + b`. If either input is unknown, or if the addition overflows,
|
||||
|
@ -60,10 +46,9 @@ int getValue(IntValue n) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue add(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a + (float)b) then
|
||||
result = a + b
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b) and isRepresentable(a.(float) + b.(float))
|
||||
then result = a + b
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,10 +57,9 @@ IntValue add(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue sub(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a - (float)b) then
|
||||
result = a - b
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b) and isRepresentable(a.(float) - b.(float))
|
||||
then result = a - b
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,12 +69,12 @@ IntValue sub(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue mul(IntValue a, IntValue b) {
|
||||
if (a = 0) or (b = 0) then
|
||||
result = 0
|
||||
else if hasValue(a) and hasValue(b) and isRepresentable((float)a * (float)b) then
|
||||
result = a * b
|
||||
if a = 0 or b = 0
|
||||
then result = 0
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b) and isRepresentable(a.(float) * b.(float))
|
||||
then result = a * b
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,10 +86,7 @@ IntValue div(IntValue a, IntValue b) {
|
|||
// Normally, integer division has to worry about overflow for INT_MIN/-1.
|
||||
// However, since we use INT_MIN to represent an unknown value anyway, we only
|
||||
// have to worry about division by zero.
|
||||
if hasValue(a) and hasValue(b) and (b != 0) then
|
||||
result = a / b
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b) and b != 0 then result = a / b else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,14 +94,9 @@ IntValue div(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareEQ(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a = b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a = b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,14 +104,9 @@ IntValue compareEQ(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareNE(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a != b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a != b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,14 +114,9 @@ IntValue compareNE(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareLT(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a < b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a < b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,14 +124,9 @@ IntValue compareLT(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareGT(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a > b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a > b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,14 +134,9 @@ IntValue compareGT(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareLE(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a <= b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a <= b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,14 +144,9 @@ IntValue compareLE(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
IntValue compareGE(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) then (
|
||||
if a >= b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
)
|
||||
else
|
||||
result = unknown()
|
||||
if hasValue(a) and hasValue(b)
|
||||
then if a >= b then result = 1 else result = 0
|
||||
else result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,53 +154,41 @@ IntValue compareGE(IntValue a, IntValue b) {
|
|||
*/
|
||||
bindingset[a]
|
||||
IntValue neg(IntValue a) {
|
||||
result = -a // -INT_MIN = INT_MIN, so this preserves unknown
|
||||
result = -a // -INT_MIN = INT_MIN, so this preserves unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `a` is equal to `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isEQ(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a = b
|
||||
}
|
||||
predicate isEQ(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a = b }
|
||||
|
||||
/**
|
||||
* Holds if `a` is not equal to `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isNE(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a != b
|
||||
}
|
||||
predicate isNE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a != b }
|
||||
|
||||
/**
|
||||
* Holds if `a` is less than `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isLT(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a < b
|
||||
}
|
||||
predicate isLT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a < b }
|
||||
|
||||
/**
|
||||
* Holds if `a` is less than or equal to `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isLE(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a <= b
|
||||
}
|
||||
predicate isLE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a <= b }
|
||||
|
||||
/**
|
||||
* Holds if `a` is greater than `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isGT(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a > b
|
||||
}
|
||||
predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b }
|
||||
|
||||
/**
|
||||
* Holds if `a` is greater than or equal to `b`. Does not hold if either `a` or `b` is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
predicate isGE(IntValue a, IntValue b) {
|
||||
hasValue(a) and hasValue(b) and a >= b
|
||||
}
|
||||
predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b }
|
||||
|
|
|
@ -13,14 +13,15 @@ private import IntegerConstant
|
|||
*/
|
||||
bindingset[defStart, defEnd, useStart, useEnd]
|
||||
Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntValue useEnd) {
|
||||
if isEQ(defStart, useStart) and isEQ(defEnd, useEnd) then
|
||||
result instanceof MustExactlyOverlap
|
||||
else if isLE(defStart, useStart) and isGE(defEnd, useEnd) then
|
||||
result instanceof MustTotallyOverlap
|
||||
else if isLE(defEnd, useStart) or isGE(defStart, useEnd) then
|
||||
none()
|
||||
if isEQ(defStart, useStart) and isEQ(defEnd, useEnd)
|
||||
then result instanceof MustExactlyOverlap
|
||||
else
|
||||
result instanceof MayPartiallyOverlap
|
||||
if isLE(defStart, useStart) and isGE(defEnd, useEnd)
|
||||
then result instanceof MustTotallyOverlap
|
||||
else
|
||||
if isLE(defEnd, useStart) or isGE(defStart, useEnd)
|
||||
then none()
|
||||
else result instanceof MayPartiallyOverlap
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,32 +6,26 @@
|
|||
/**
|
||||
* Gets the value of the maximum representable integer.
|
||||
*/
|
||||
int maxValue() {
|
||||
result = 2147483647
|
||||
}
|
||||
int maxValue() { result = 2147483647 }
|
||||
|
||||
/**
|
||||
* Gets the value of the minimum representable integer.
|
||||
*/
|
||||
int minValue() {
|
||||
result = -2147483648
|
||||
}
|
||||
int minValue() { result = -2147483648 }
|
||||
|
||||
/**
|
||||
* Holds if the value `f` is within the range of representable integers.
|
||||
*/
|
||||
pragma[inline]
|
||||
bindingset[f]
|
||||
private predicate isRepresentable(float f) {
|
||||
(f >= minValue()) and (f <= maxValue())
|
||||
}
|
||||
pragma[inline]
|
||||
private predicate isRepresentable(float f) { f >= minValue() and f <= maxValue() }
|
||||
|
||||
/**
|
||||
* Returns `a + b`. If the addition overflows, there is no result.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
int add(int a, int b) {
|
||||
isRepresentable((float)a + (float)b) and
|
||||
isRepresentable(a.(float) + b.(float)) and
|
||||
result = a + b
|
||||
}
|
||||
|
||||
|
@ -40,7 +34,7 @@ int add(int a, int b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
int sub(int a, int b) {
|
||||
isRepresentable((float)a - (float)b) and
|
||||
isRepresentable(a.(float) - b.(float)) and
|
||||
result = a - b
|
||||
}
|
||||
|
||||
|
@ -57,7 +51,7 @@ int mul(int a, int b) {
|
|||
b = 0 and
|
||||
result = 0
|
||||
or
|
||||
isRepresentable((float)a * (float)b) and
|
||||
isRepresentable(a.(float) * b.(float)) and
|
||||
result = a * b
|
||||
}
|
||||
|
||||
|
@ -66,63 +60,34 @@ int mul(int a, int b) {
|
|||
*/
|
||||
bindingset[a, b]
|
||||
int div(int a, int b) {
|
||||
b != 0 and (a != minValue() or b != -1) and
|
||||
b != 0 and
|
||||
(a != minValue() or b != -1) and
|
||||
result = a / b
|
||||
}
|
||||
|
||||
/** Returns `a == b`. */
|
||||
bindingset[a, b]
|
||||
int compareEQ(int a, int b) {
|
||||
if a = b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareEQ(int a, int b) { if a = b then result = 1 else result = 0 }
|
||||
|
||||
/** Returns `a != b`. */
|
||||
bindingset[a, b]
|
||||
int compareNE(int a, int b) {
|
||||
if a != b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareNE(int a, int b) { if a != b then result = 1 else result = 0 }
|
||||
|
||||
/** Returns `a < b`. */
|
||||
bindingset[a, b]
|
||||
int compareLT(int a, int b) {
|
||||
if a < b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareLT(int a, int b) { if a < b then result = 1 else result = 0 }
|
||||
|
||||
/** Returns `a > b`. */
|
||||
bindingset[a, b]
|
||||
int compareGT(int a, int b) {
|
||||
if a > b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareGT(int a, int b) { if a > b then result = 1 else result = 0 }
|
||||
|
||||
/** Returns `a <= b`. */
|
||||
bindingset[a, b]
|
||||
int compareLE(int a, int b) {
|
||||
if a <= b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareLE(int a, int b) { if a <= b then result = 1 else result = 0 }
|
||||
|
||||
/** Returns `a >= b`. */
|
||||
bindingset[a, b]
|
||||
int compareGE(int a, int b) {
|
||||
if a >= b then
|
||||
result = 1
|
||||
else
|
||||
result = 0
|
||||
}
|
||||
int compareGE(int a, int b) { if a >= b then result = 1 else result = 0 }
|
||||
|
||||
/**
|
||||
* Returns `-a`. If the negation would overflow, there is no result.
|
||||
|
|
|
@ -8,19 +8,13 @@ abstract class Overlap extends TOverlap {
|
|||
}
|
||||
|
||||
class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MayPartiallyOverlap"
|
||||
}
|
||||
final override string toString() { result = "MayPartiallyOverlap" }
|
||||
}
|
||||
|
||||
class MustTotallyOverlap extends Overlap, TMustTotallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustTotallyOverlap"
|
||||
}
|
||||
final override string toString() { result = "MustTotallyOverlap" }
|
||||
}
|
||||
|
||||
class MustExactlyOverlap extends Overlap, TMustExactlyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustExactlyOverlap"
|
||||
}
|
||||
final override string toString() { result = "MustExactlyOverlap" }
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче