C++: Operands as IPA types

@rdmarsh2 has been working on various queries and libraries on top of the IR, and has pointed out that having to always refer to an operand of an instruction by the pair of (instruction, operandTag) makes using the IR a bit clunky. This PR adds a new `Operand` IPA type that represents an operand of an instruction. `OperandTag` still exists, but is now an internal type used only in the IR implementation.
This commit is contained in:
Dave Bartolomeo
2018-10-23 14:17:17 -07:00
parent 640de0c947
commit f278f4fa47
29 changed files with 1579 additions and 1347 deletions

View File

@@ -19,10 +19,10 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/FunctionIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/FunctionIR.qll"
],
"C++ IR OperandTag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll"
"C++ IR Operand": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll"
],
"C++ IR IRImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",

View File

@@ -16,7 +16,7 @@ class MemoryAccessKind extends TMemoryAccessKind {
/**
* The operand or result accesses memory at the address specified by the
* `LoadStoreAddressOperand` on the same instruction.
* `AddressOperand` on the same instruction.
*/
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
override string toString() {

View File

@@ -2,7 +2,7 @@ import FunctionIR
import Instruction
import IRBlock
import IRVariable
import OperandTag
import Operand
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind

View File

@@ -2,12 +2,13 @@ private import internal.IRInternal
import FunctionIR
import IRBlock
import IRVariable
import OperandTag
import Operand
import cpp
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
class InstructionTag = Construction::InstructionTagType;
@@ -22,21 +23,21 @@ module InstructionSanity {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
(
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperand or
tag instanceof RightOperand
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
) or
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
)
)
}
@@ -45,26 +46,34 @@ module InstructionSanity {
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, OperandTag tag) {
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
expectsOperand(instr, tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
strictcount(instr.getOperand(tag)) > 1 and
not tag instanceof UnmodeledUseOperand
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) > 1 and
not tag instanceof UnmodeledUseOperandTag
}
/**
@@ -74,7 +83,7 @@ module InstructionSanity {
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiOperand operand |
exists(instr.getOperand(operand)) and
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
@@ -98,14 +107,13 @@ module InstructionSanity {
}
/**
* Holds if instruction `op` consumes an operand `operand` that was defined in
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(
Instruction op, Instruction operand, OperandTag tag
) {
operand = op.getOperand(tag) and
operand.getFunctionIR() != op.getFunctionIR()
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getInstruction() = instr and
operand.getDefinitionInstruction() = defInstr and
instr.getFunctionIR() != defInstr.getFunctionIR()
}
/**
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
result = concat(Operand operand |
operand = getAnOperand() |
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
)
}
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
}
/**
* Gets the instruction that produced the value of the specified source
* operand.
* Gets all direct uses of the result of this instruction.
*/
final Instruction getOperand(OperandTag tag) {
result = Construction::getInstructionOperand(this, tag)
final Operand getAUse() {
result.getDefinitionInstruction() = this
}
/**
* Gets all instructions consumed by this instruction's operands.
* Gets all of this instruction's operands.
*/
final Instruction getAnOperand() {
result = getOperand(_)
final Operand getAnOperand() {
result.getInstruction() = this
}
/**
* Holds if this instruction has a memory operand with the specified tag.
*/
final predicate isMemoryOperand(OperandTag tag) {
exists(getOperandMemoryAccess(tag))
}
/**
* Gets the kind of memory access performed by the specified operand. Holds
* only for memory operands.
*/
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
none()
}
/**
* Holds if this instruction produces a memory result.
*/
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
this = useInstr.getOperand(useTag)
)
not (getAUse() instanceof UnmodeledUseOperand)
}
/**
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
final Instruction getObjectAddress() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
}
final Instruction getReturnValue() {
result = getOperand(returnValueOperand())
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ReturnValueOperand))) and
result instanceof IndirectMemoryAccess
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
}
}
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
}
final Instruction getSourceValue() {
result = getOperand(copySourceOperand())
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
}
}
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
opcode instanceof Opcode::Load
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(CopySourceOperand))) and
result instanceof IndirectMemoryAccess
}
final Instruction getSourceAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
}
final Instruction getDestinationAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
}
final Instruction getCondition() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getTrueSuccessor() {
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
}
final Instruction getLeftOperand() {
result = getOperand(leftOperand())
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
}
final Instruction getRightOperand() {
result = getOperand(rightOperand())
result = getAnOperand().(RightOperand).getDefinitionInstruction()
}
}
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
}
final Instruction getOperand() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
RelationalInstruction() {
opcode instanceof RelationalOpcode
}
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational instruction, that is, the side that is larger
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
Instruction getLesserOperand() {
none()
}
/**
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
*/
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
}
final Instruction getExpression() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getACaseSuccessor() {
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
}
final Instruction getCallTarget() {
result = getOperand(callTargetOperand())
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
}
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
opcode instanceof Opcode::ThrowValue
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ExceptionOperand))) and
result instanceof IndirectMemoryAccess
}
/**
* Gets the address of the exception thrown by this instruction.
*/
final Instruction getExceptionAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
/**
* Gets the exception thrown by this instruction.
*/
final Instruction getException() {
result = getOperand(exceptionOperand())
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
}
}
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
result instanceof UnmodeledMemoryAccess
}
}
class PhiInstruction extends Instruction {
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
opcode instanceof Opcode::Phi
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(PhiOperand))) and
result instanceof PhiMemoryAccess
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}

View File

@@ -0,0 +1,360 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private import semmle.code.cpp.ir.internal.OperandTag
private newtype TOperand =
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
defInstr = Construction::getInstructionOperand(instr, tag)
} or
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
}
/**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/
class Operand extends TOperand {
string toString() {
result = "Operand"
}
/**
* Gets the `Instruction` that consumes this operand.
*/
Instruction getInstruction() {
none()
}
/**
* Gets the `Instruction` whose result is the value of the operand.
*/
Instruction getDefinitionInstruction() {
none()
}
/**
* Gets a prefix to use when dumping the operand in an operand list.
*/
string getDumpLabel() {
result = ""
}
/**
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
* result ID of the instruction consumed by the operand, plus a label identifying the operand
* kind.
*
* For example: `this:r3_5`
*/
final string getDumpString() {
result = getDumpLabel() + getDefinitionInstruction().getResultId()
}
/**
* Get the order in which the operand should be sorted in the operand list.
*/
int getDumpSortOrder() {
result = -1
}
/**
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
*/
MemoryAccessKind getMemoryAccess() {
none()
}
/**
* Returns the operand that holds the memory address from which the current operand loads its
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
* is `r1`.
*/
final AddressOperand getAddressOperand() {
getMemoryAccess() instanceof IndirectMemoryAccess and
result.getInstruction() = getInstruction()
}
}
/**
* An operand that is not an operand of a `PhiInstruction`.
*/
class NonPhiOperand extends Operand, TNonPhiOperand {
Instruction instr;
Instruction defInstr;
OperandTag tag;
NonPhiOperand() {
this = TNonPhiOperand(instr, tag, defInstr)
}
override final Instruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final string getDumpLabel() {
result = tag.getLabel()
}
override final int getDumpSortOrder() {
result = tag.getSortOrder()
}
final OperandTag getOperandTag() {
result = tag
}
}
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class AddressOperand extends NonPhiOperand {
AddressOperand() {
this = TNonPhiOperand(_, addressOperand(), _)
}
override string toString() {
result = "Address"
}
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends NonPhiOperand {
CopySourceOperand() {
this = TNonPhiOperand(_, copySourceOperand(), _)
}
override string toString() {
result = "CopySource"
}
override final MemoryAccessKind getMemoryAccess() {
instr.getOpcode() instanceof Opcode::Load and
result instanceof IndirectMemoryAccess
}
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends NonPhiOperand {
UnaryOperand() {
this = TNonPhiOperand(_, unaryOperand(), _)
}
override string toString() {
result = "Unary"
}
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends NonPhiOperand {
LeftOperand() {
this = TNonPhiOperand(_, leftOperand(), _)
}
override string toString() {
result = "Left"
}
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends NonPhiOperand {
RightOperand() {
this = TNonPhiOperand(_, rightOperand(), _)
}
override string toString() {
result = "Right"
}
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends NonPhiOperand {
ReturnValueOperand() {
this = TNonPhiOperand(_, returnValueOperand(), _)
}
override string toString() {
result = "ReturnValue"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends NonPhiOperand {
ExceptionOperand() {
this = TNonPhiOperand(_, exceptionOperand(), _)
}
override string toString() {
result = "Exception"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends NonPhiOperand {
ConditionOperand() {
this = TNonPhiOperand(_, conditionOperand(), _)
}
override string toString() {
result = "Condition"
}
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends NonPhiOperand {
UnmodeledUseOperand() {
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
}
override string toString() {
result = "UnmodeledUse"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends NonPhiOperand {
CallTargetOperand() {
this = TNonPhiOperand(_, callTargetOperand(), _)
}
override string toString() {
result = "CallTarget"
}
}
/**
* 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`).
*/
class ArgumentOperand extends NonPhiOperand {
ArgumentOperand() {
exists(ArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _)
)
}
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
ThisArgumentOperand() {
this = TNonPhiOperand(_, thisArgumentOperand(), _)
}
override string toString() {
result = "ThisArgument"
}
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
exists(PositionalArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _) and
argIndex = argTag.getArgIndex()
)
}
override string toString() {
result = "Arg(" + argIndex + ")"
}
}
/**
* An operand of a `PhiInstruction`.
*/
class PhiOperand extends Operand, TPhiOperand {
PhiInstruction instr;
Instruction defInstr;
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(instr, defInstr, predecessorBlock)
}
override string toString() {
result = "Phi"
}
override final PhiInstruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final int getDumpSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getDumpLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
/**
* Gets the predecessor block from which this value comes.
*/
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof PhiMemoryAccess
}
}
/**
* An operand that reads a value from memory.
*/
class MemoryOperand extends Operand {
MemoryOperand() {
exists(getMemoryAccess())
}
}

View File

@@ -46,18 +46,20 @@ private IntValue getFieldBitOffset(Field field) {
* not result in any address held in that operand from escaping beyond the
* instruction.
*/
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
(
// The source/destination address of a Load/Store does not escape (but the
// loaded/stored value could).
tag instanceof LoadStoreAddressOperand or
// Neither operand of a Compare escapes.
instr instanceof CompareInstruction or
// Neither operand of a PointerDiff escapes.
instr instanceof PointerDiffInstruction or
// Converting an address to a `bool` does not escape the address.
instr.(ConvertInstruction).getResultType() instanceof BoolType
predicate operandIsConsumedWithoutEscaping(Operand operand) {
// The source/destination address of a Load/Store does not escape (but the
// loaded/stored value could).
operand instanceof AddressOperand or
exists (Instruction instr |
instr = operand.getInstruction() and
(
// Neither operand of a Compare escapes.
instr instanceof CompareInstruction or
// Neither operand of a PointerDiff escapes.
instr instanceof PointerDiffInstruction or
// Converting an address to a `bool` does not escape the address.
instr.(ConvertInstruction).getResultType() instanceof BoolType
)
)
}
@@ -96,43 +98,44 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
* `bitOffset`. If the address is propagated, but the offset is not known to be
* a constant, then `bitOffset` is unknown.
*/
predicate operandIsPropagated(Instruction instr, OperandTag tag,
IntValue bitOffset) {
exists(instr.getOperand(tag)) and
(
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
) or
// Converting to a virtual base class adds an unknown offset.
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
exists(Instruction instr |
instr = operand.getInstruction() and
(
instr instanceof ConvertToVirtualBaseInstruction and
bitOffset = Ints::unknown()
) or
// Conversion to another pointer type propagates the source address.
exists(ConvertInstruction convert, Type resultType |
convert = instr and
resultType = convert.getResultType() and
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
) or
// Converting to a virtual base class adds an unknown offset.
(
resultType instanceof PointerType or
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
) and
bitOffset = 0
) or
// Adding an integer to or subtracting an integer from a pointer propagates
// the address with an offset.
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
// Computing a field address from a pointer propagates the address plus the
// offset of the field.
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
// A copy propagates the source value.
tag instanceof CopySourceOperand and bitOffset = 0
instr instanceof ConvertToVirtualBaseInstruction and
bitOffset = Ints::unknown()
) or
// Conversion to another pointer type propagates the source address.
exists(ConvertInstruction convert, Type resultType |
convert = instr and
resultType = convert.getResultType() and
(
resultType instanceof PointerType or
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
) and
bitOffset = 0
) or
// Adding an integer to or subtracting an integer from a pointer propagates
// the address with an offset.
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
// Computing a field address from a pointer propagates the address plus the
// offset of the field.
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
// A copy propagates the source value.
operand instanceof CopySourceOperand and bitOffset = 0
)
)
}
@@ -140,16 +143,15 @@ predicate operandIsPropagated(Instruction instr, OperandTag tag,
* Holds if any address held in operand number `tag` of instruction `instr`
* escapes outside the domain of the analysis.
*/
predicate operandEscapes(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
predicate operandEscapes(Operand operand) {
// Conservatively assume that the address escapes unless one of the following
// holds:
not (
// The operand is used in a way that does not escape the instruction
operandIsConsumedWithoutEscaping(instr, tag) or
operandIsConsumedWithoutEscaping(operand) or
// The address is propagated to the result of the instruction, but that
// result does not itself escape.
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
operandIsPropagated(operand, _) and not resultEscapes(operand.getInstruction())
)
}
@@ -159,10 +161,7 @@ predicate operandEscapes(Instruction instr, OperandTag tag) {
*/
predicate resultEscapes(Instruction instr) {
// The result escapes if it has at least one use that escapes.
exists(Instruction useInstr, OperandTag useOperandTag |
useInstr.getOperand(useOperandTag) = instr and
operandEscapes(useInstr, useOperandTag)
)
operandEscapes(instr.getAUse())
}
/**
@@ -203,12 +202,12 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getVariable() = var and
bitOffset = 0
) or
exists(OperandTag operandTag, IntValue originalBitOffset,
IntValue propagatedBitOffset |
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,
// offset by the bit offset from the propagation.
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
operandIsPropagated(operand, propagatedBitOffset) and
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
)
}

View File

@@ -1,30 +1,13 @@
import SSAConstructionInternal
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
import NewIR
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
import IRBlockConstruction as BlockConstruction
import Cached
cached private module Cached {
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
exists(PositionalArgumentOperand newArg |
newArg = newTag and
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
)
}
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
@@ -49,14 +32,6 @@ cached private module Cached {
)
}
cached int getMaxCallArgIndex() {
result = max(int argIndex |
exists(OldIR::PositionalArgumentOperand oldOperand |
argIndex = oldOperand.getArgIndex()
)
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
@@ -136,17 +111,18 @@ cached private module Cached {
}
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
oldUse = getOldInstruction(instruction) and
oldTag = getOldOperandTag(tag) and
if oldUse.isMemoryOperand(oldTag) then (
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
if defIndex >= 0 then
result = getNewInstruction(defBlock.getInstruction(defIndex))
@@ -162,25 +138,24 @@ cached private module Cached {
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperand and
oldDefinition = oldUse.getOperand(oldTag) and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
result = getNewInstruction(oldDefinition)
)
)
else
result = getNewInstruction(oldUse.getOperand(oldTag))
) or
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
result = getNewInstruction(oldOperand.getDefinitionInstruction())
)
}
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
tag.getPredecessorBlock() = getNewBlock(predBlock) and
newPredecessorBlock = getNewBlock(predBlock) and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
if defIndex >= 0 then
@@ -277,7 +252,7 @@ cached private module Cached {
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
exists(Alias::MemoryAccess access |
access = Alias::getOperandMemoryAccess(use, _) and
access = Alias::getOperandMemoryAccess(use.getAnOperand()) and
block.getInstruction(index) = use and
vvar = access.getVirtualVariable()
)

View File

@@ -2,7 +2,8 @@ import SimpleSSAInternal
import cpp
import Alias
private import InputIR
import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private newtype TVirtualVariable =
MkVirtualVariable(IRVariable var) {
@@ -69,15 +70,15 @@ Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
MemoryAccess getResultMemoryAccess(Instruction instr) {
exists(IRVariable var |
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(),
var, 0) and
result = getMemoryAccess(var)
)
}
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
MemoryAccess getOperandMemoryAccess(Operand operand) {
exists(IRVariable var |
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, 0) and
result = getMemoryAccess(var)
)
}

View File

@@ -2,7 +2,7 @@ import FunctionIR
import Instruction
import IRBlock
import IRVariable
import OperandTag
import Operand
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind

View File

@@ -2,12 +2,13 @@ private import internal.IRInternal
import FunctionIR
import IRBlock
import IRVariable
import OperandTag
import Operand
import cpp
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
class InstructionTag = Construction::InstructionTagType;
@@ -22,21 +23,21 @@ module InstructionSanity {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
(
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperand or
tag instanceof RightOperand
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
) or
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
)
)
}
@@ -45,26 +46,34 @@ module InstructionSanity {
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, OperandTag tag) {
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
expectsOperand(instr, tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
strictcount(instr.getOperand(tag)) > 1 and
not tag instanceof UnmodeledUseOperand
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) > 1 and
not tag instanceof UnmodeledUseOperandTag
}
/**
@@ -74,7 +83,7 @@ module InstructionSanity {
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiOperand operand |
exists(instr.getOperand(operand)) and
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
@@ -98,14 +107,13 @@ module InstructionSanity {
}
/**
* Holds if instruction `op` consumes an operand `operand` that was defined in
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(
Instruction op, Instruction operand, OperandTag tag
) {
operand = op.getOperand(tag) and
operand.getFunctionIR() != op.getFunctionIR()
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getInstruction() = instr and
operand.getDefinitionInstruction() = defInstr and
instr.getFunctionIR() != defInstr.getFunctionIR()
}
/**
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
result = concat(Operand operand |
operand = getAnOperand() |
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
)
}
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
}
/**
* Gets the instruction that produced the value of the specified source
* operand.
* Gets all direct uses of the result of this instruction.
*/
final Instruction getOperand(OperandTag tag) {
result = Construction::getInstructionOperand(this, tag)
final Operand getAUse() {
result.getDefinitionInstruction() = this
}
/**
* Gets all instructions consumed by this instruction's operands.
* Gets all of this instruction's operands.
*/
final Instruction getAnOperand() {
result = getOperand(_)
final Operand getAnOperand() {
result.getInstruction() = this
}
/**
* Holds if this instruction has a memory operand with the specified tag.
*/
final predicate isMemoryOperand(OperandTag tag) {
exists(getOperandMemoryAccess(tag))
}
/**
* Gets the kind of memory access performed by the specified operand. Holds
* only for memory operands.
*/
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
none()
}
/**
* Holds if this instruction produces a memory result.
*/
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
this = useInstr.getOperand(useTag)
)
not (getAUse() instanceof UnmodeledUseOperand)
}
/**
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
final Instruction getObjectAddress() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
}
final Instruction getReturnValue() {
result = getOperand(returnValueOperand())
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ReturnValueOperand))) and
result instanceof IndirectMemoryAccess
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
}
}
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
}
final Instruction getSourceValue() {
result = getOperand(copySourceOperand())
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
}
}
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
opcode instanceof Opcode::Load
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(CopySourceOperand))) and
result instanceof IndirectMemoryAccess
}
final Instruction getSourceAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
}
final Instruction getDestinationAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
}
final Instruction getCondition() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getTrueSuccessor() {
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
}
final Instruction getLeftOperand() {
result = getOperand(leftOperand())
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
}
final Instruction getRightOperand() {
result = getOperand(rightOperand())
result = getAnOperand().(RightOperand).getDefinitionInstruction()
}
}
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
}
final Instruction getOperand() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
RelationalInstruction() {
opcode instanceof RelationalOpcode
}
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational instruction, that is, the side that is larger
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
Instruction getLesserOperand() {
none()
}
/**
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
*/
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
}
final Instruction getExpression() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getACaseSuccessor() {
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
}
final Instruction getCallTarget() {
result = getOperand(callTargetOperand())
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
}
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
opcode instanceof Opcode::ThrowValue
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ExceptionOperand))) and
result instanceof IndirectMemoryAccess
}
/**
* Gets the address of the exception thrown by this instruction.
*/
final Instruction getExceptionAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
/**
* Gets the exception thrown by this instruction.
*/
final Instruction getException() {
result = getOperand(exceptionOperand())
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
}
}
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
result instanceof UnmodeledMemoryAccess
}
}
class PhiInstruction extends Instruction {
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
opcode instanceof Opcode::Phi
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(PhiOperand))) and
result instanceof PhiMemoryAccess
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}

View File

@@ -0,0 +1,360 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private import semmle.code.cpp.ir.internal.OperandTag
private newtype TOperand =
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
defInstr = Construction::getInstructionOperand(instr, tag)
} or
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
}
/**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/
class Operand extends TOperand {
string toString() {
result = "Operand"
}
/**
* Gets the `Instruction` that consumes this operand.
*/
Instruction getInstruction() {
none()
}
/**
* Gets the `Instruction` whose result is the value of the operand.
*/
Instruction getDefinitionInstruction() {
none()
}
/**
* Gets a prefix to use when dumping the operand in an operand list.
*/
string getDumpLabel() {
result = ""
}
/**
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
* result ID of the instruction consumed by the operand, plus a label identifying the operand
* kind.
*
* For example: `this:r3_5`
*/
final string getDumpString() {
result = getDumpLabel() + getDefinitionInstruction().getResultId()
}
/**
* Get the order in which the operand should be sorted in the operand list.
*/
int getDumpSortOrder() {
result = -1
}
/**
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
*/
MemoryAccessKind getMemoryAccess() {
none()
}
/**
* Returns the operand that holds the memory address from which the current operand loads its
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
* is `r1`.
*/
final AddressOperand getAddressOperand() {
getMemoryAccess() instanceof IndirectMemoryAccess and
result.getInstruction() = getInstruction()
}
}
/**
* An operand that is not an operand of a `PhiInstruction`.
*/
class NonPhiOperand extends Operand, TNonPhiOperand {
Instruction instr;
Instruction defInstr;
OperandTag tag;
NonPhiOperand() {
this = TNonPhiOperand(instr, tag, defInstr)
}
override final Instruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final string getDumpLabel() {
result = tag.getLabel()
}
override final int getDumpSortOrder() {
result = tag.getSortOrder()
}
final OperandTag getOperandTag() {
result = tag
}
}
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class AddressOperand extends NonPhiOperand {
AddressOperand() {
this = TNonPhiOperand(_, addressOperand(), _)
}
override string toString() {
result = "Address"
}
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends NonPhiOperand {
CopySourceOperand() {
this = TNonPhiOperand(_, copySourceOperand(), _)
}
override string toString() {
result = "CopySource"
}
override final MemoryAccessKind getMemoryAccess() {
instr.getOpcode() instanceof Opcode::Load and
result instanceof IndirectMemoryAccess
}
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends NonPhiOperand {
UnaryOperand() {
this = TNonPhiOperand(_, unaryOperand(), _)
}
override string toString() {
result = "Unary"
}
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends NonPhiOperand {
LeftOperand() {
this = TNonPhiOperand(_, leftOperand(), _)
}
override string toString() {
result = "Left"
}
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends NonPhiOperand {
RightOperand() {
this = TNonPhiOperand(_, rightOperand(), _)
}
override string toString() {
result = "Right"
}
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends NonPhiOperand {
ReturnValueOperand() {
this = TNonPhiOperand(_, returnValueOperand(), _)
}
override string toString() {
result = "ReturnValue"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends NonPhiOperand {
ExceptionOperand() {
this = TNonPhiOperand(_, exceptionOperand(), _)
}
override string toString() {
result = "Exception"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends NonPhiOperand {
ConditionOperand() {
this = TNonPhiOperand(_, conditionOperand(), _)
}
override string toString() {
result = "Condition"
}
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends NonPhiOperand {
UnmodeledUseOperand() {
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
}
override string toString() {
result = "UnmodeledUse"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends NonPhiOperand {
CallTargetOperand() {
this = TNonPhiOperand(_, callTargetOperand(), _)
}
override string toString() {
result = "CallTarget"
}
}
/**
* 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`).
*/
class ArgumentOperand extends NonPhiOperand {
ArgumentOperand() {
exists(ArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _)
)
}
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
ThisArgumentOperand() {
this = TNonPhiOperand(_, thisArgumentOperand(), _)
}
override string toString() {
result = "ThisArgument"
}
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
exists(PositionalArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _) and
argIndex = argTag.getArgIndex()
)
}
override string toString() {
result = "Arg(" + argIndex + ")"
}
}
/**
* An operand of a `PhiInstruction`.
*/
class PhiOperand extends Operand, TPhiOperand {
PhiInstruction instr;
Instruction defInstr;
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(instr, defInstr, predecessorBlock)
}
override string toString() {
result = "Phi"
}
override final PhiInstruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final int getDumpSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getDumpLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
/**
* Gets the predecessor block from which this value comes.
*/
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof PhiMemoryAccess
}
}
/**
* An operand that reads a value from memory.
*/
class MemoryOperand extends Operand {
MemoryOperand() {
exists(getMemoryAccess())
}
}

View File

@@ -1,312 +0,0 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
string getLabel() {
result = ""
}
}
// 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`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand 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 ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
override final string getLabel() {
result = "this:"
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -1,6 +1,7 @@
import cpp
import semmle.code.cpp.ir.implementation.raw.IR
import IRBlockConstruction as BlockConstruction
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedElement
@@ -37,14 +38,6 @@ cached private module Cached {
exists(getTranslatedFunction(func))
}
cached int getMaxCallArgIndex() {
result = max(int argIndex |
exists(FunctionCall call |
exists(call.getArgument(argIndex))
)
)
}
cached newtype TInstruction =
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
InstructionTag tag, Type resultType, boolean isGLValue) {
@@ -98,6 +91,10 @@ cached private module Cached {
instruction.getTag(), tag)
}
cached Instruction getPhiInstructionOperand(Instruction instruction, IRBlock predecessorBlock) {
none()
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
none()
}

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
@@ -209,7 +210,7 @@ class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
}
class TranslatedValueCondition extends TranslatedCondition,
TTranslatedValueCondition {
TTranslatedValueCondition {
TranslatedValueCondition() {
this = TTranslatedValueCondition(expr)
}
@@ -223,7 +224,7 @@ class TranslatedValueCondition extends TranslatedCondition,
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
Type resultType, boolean isGLValue) {
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and
@@ -236,7 +237,7 @@ class TranslatedValueCondition extends TranslatedCondition,
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
(
@@ -251,9 +252,9 @@ class TranslatedValueCondition extends TranslatedCondition,
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperand and
operandTag instanceof ConditionOperandTag and
result = getValueExpr().getResult()
}

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
@@ -157,7 +158,7 @@ class TranslatedUninitializedVariable extends
tag = InitializerStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(InitializerVariableAddressTag())
)
)

View File

@@ -1,6 +1,7 @@
import cpp
import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedCondition

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedCondition
@@ -209,16 +210,16 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
(
tag = ConditionValueTrueStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueTrueTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(ConditionValueTrueConstantTag())
)
)
@@ -227,11 +228,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
tag = ConditionValueFalseStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueFalseTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(ConditionValueFalseConstantTag())
)
)
@@ -240,11 +241,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
tag = ConditionValueResultLoadTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueResultTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -315,7 +316,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
Type resultType, boolean isGLValue) {
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = expr.getType().getUnspecifiedType() and
@@ -326,7 +327,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
EdgeKind kind) {
tag = LoadTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
@@ -345,11 +346,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
tag = LoadTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -404,7 +405,7 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
none()
}
@@ -478,16 +479,16 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
(
tag = CrementLoadTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -496,11 +497,11 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
tag = CrementOpTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getInstruction(CrementLoadTag())
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getInstruction(CrementConstantTag())
)
)
@@ -509,11 +510,11 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
tag = CrementStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(CrementOpTag())
)
)
@@ -670,11 +671,11 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
tag = OnlyInstructionTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getBaseOperand().getResult()
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getOffsetOperand().getResult()
)
)
@@ -722,7 +723,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
none()
}
@@ -804,7 +805,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInitializeThisInstruction()
}
@@ -857,7 +858,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
none()
}
@@ -891,7 +892,7 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getQualifier().getResult()
}
@@ -987,7 +988,7 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr {
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
none()
}
@@ -1100,13 +1101,13 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = OnlyInstructionTag() and
result = getOperand().getResult() and
if getOpcode() instanceof Opcode::CopyValue then
operandTag instanceof CopySourceOperand
operandTag instanceof CopySourceOperandTag
else
operandTag instanceof UnaryOperand
operandTag instanceof UnaryOperandTag
}
override final Opcode getOpcode() {
@@ -1172,9 +1173,9 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getOperand().getResult()
}
@@ -1313,11 +1314,11 @@ class TranslatedBoolConversion extends TranslatedConversion {
tag = BoolConversionCompareTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getOperand().getResult()
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getInstruction(BoolConversionConstantTag())
)
)
@@ -1381,21 +1382,21 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
tag = OnlyInstructionTag() and
if swapOperandsOnOp() then (
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getRightOperand().getResult()
)
)
else (
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getRightOperand().getResult()
)
)
@@ -1551,11 +1552,11 @@ class TranslatedAssignExpr extends TranslatedAssignment {
tag = AssignmentStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getRightOperand().getResult()
)
)
@@ -1714,11 +1715,11 @@ class TranslatedAssignOperation extends TranslatedAssignment {
tag = AssignOperationLoadTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -1726,21 +1727,21 @@ class TranslatedAssignOperation extends TranslatedAssignment {
(
leftOperandNeedsConversion() and
tag = AssignOperationConvertLeftTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getInstruction(AssignOperationLoadTag())
) or
(
tag = AssignOperationOpTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
if leftOperandNeedsConversion() then
result = getInstruction(AssignOperationConvertLeftTag())
else
result = getInstruction(AssignOperationLoadTag())
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getRightOperand().getResult()
)
)
@@ -1748,18 +1749,18 @@ class TranslatedAssignOperation extends TranslatedAssignment {
(
leftOperandNeedsConversion() and
tag = AssignOperationConvertResultTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getInstruction(AssignOperationOpTag())
) or
(
tag = AssignmentStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getStoredValue()
)
)
@@ -1828,14 +1829,14 @@ abstract class TranslatedCall extends TranslatedExpr {
tag = CallTag() and
(
(
operandTag instanceof CallTargetOperand and
operandTag instanceof CallTargetOperandTag and
result = getCallTargetResult()
) or
(
operandTag instanceof ThisArgumentOperand and
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
) or
exists(PositionalArgumentOperand argTag |
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
@@ -2071,13 +2072,13 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
(
tag = AllocationSizeTag() and
(
operandTag instanceof LeftOperand and result = getInstruction(AllocationExtentConvertTag()) or
operandTag instanceof RightOperand and result = getInstruction(AllocationElementSizeTag())
operandTag instanceof LeftOperandTag and result = getInstruction(AllocationExtentConvertTag()) or
operandTag instanceof RightOperandTag and result = getInstruction(AllocationElementSizeTag())
)
) or
(
tag = AllocationExtentConvertTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getExtent().getResult()
)
}
@@ -2322,7 +2323,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getTranslatedFunction(destruction.getEnclosingFunction()).getInitializeThisInstruction()
}
@@ -2433,7 +2434,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
not resultIsVoid() and
(
(
@@ -2441,11 +2442,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
tag = ConditionValueTrueStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueTrueTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getThen().getResult()
)
)
@@ -2455,11 +2456,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
tag = ConditionValueFalseStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueFalseTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getElse().getResult()
)
)
@@ -2468,11 +2469,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
tag = ConditionValueResultLoadTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ConditionValueResultTempAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -2648,11 +2649,11 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
tag = ThrowTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(InitializerVariableAddressTag())
) or
(
operandTag instanceof ExceptionOperand and
operandTag instanceof ExceptionOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -2864,7 +2865,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getAllocatorCall().getResult()
}

View File

@@ -1,6 +1,7 @@
import cpp
import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedElement
@@ -210,10 +211,10 @@ class TranslatedFunction extends TranslatedElement,
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
(
tag = UnmodeledUseTag() and
operandTag instanceof UnmodeledUseOperand and
operandTag instanceof UnmodeledUseOperandTag and
result.getFunction() = func and
result.hasMemoryResult()
) or
@@ -222,11 +223,11 @@ class TranslatedFunction extends TranslatedElement,
not getReturnType() instanceof VoidType and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ReturnValueAddressTag())
) or
(
operandTag instanceof ReturnValueOperand and
operandTag instanceof ReturnValueOperandTag and
result = getUnmodeledDefinitionInstruction()
)
)
@@ -374,11 +375,11 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = InitializerStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(InitializerVariableAddressTag())
)
)

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
@@ -205,15 +206,15 @@ class TranslatedSimpleDirectInitialization extends
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = InitializerStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getContext().getTargetAddress()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInitializer().getResult()
)
)
@@ -332,11 +333,11 @@ class TranslatedStringLiteralInitialization extends
tag = InitializerLoadStringTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInitializer().getResult()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
)
@@ -345,11 +346,11 @@ class TranslatedStringLiteralInitialization extends
tag = InitializerStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getContext().getTargetAddress()
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(InitializerLoadStringTag())
)
)
@@ -358,11 +359,11 @@ class TranslatedStringLiteralInitialization extends
tag = ZeroPadStringElementAddressTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getContext().getTargetAddress()
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getInstruction(ZeroPadStringElementIndexTag())
)
)
@@ -371,11 +372,11 @@ class TranslatedStringLiteralInitialization extends
tag = ZeroPadStringStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(ZeroPadStringElementAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(ZeroPadStringConstantTag())
)
)
@@ -450,7 +451,7 @@ class TranslatedConstructorInitialization extends
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
none()
}
@@ -514,9 +515,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = getFieldAddressTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
}
@@ -633,17 +634,17 @@ class TranslatedFieldValueInitialization extends
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
result = TranslatedFieldInitialization.super.getInstructionOperand(tag, operandTag) or
(
tag = getFieldDefaultValueStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(getFieldAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(getFieldDefaultValueTag())
)
)
@@ -723,15 +724,15 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = getElementAddressTag() and
(
(
operandTag instanceof LeftOperand and
operandTag instanceof LeftOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
) or
(
operandTag instanceof RightOperand and
operandTag instanceof RightOperandTag and
result = getInstruction(getElementIndexTag())
)
)
@@ -882,17 +883,17 @@ class TranslatedElementValueInitialization extends
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
result = TranslatedElementInitialization.super.getInstructionOperand(tag, operandTag) or
(
tag = getElementDefaultValueStoreTag() and
(
(
operandTag instanceof LoadStoreAddressOperand and
operandTag instanceof AddressOperandTag and
result = getInstruction(getElementAddressTag())
) or
(
operandTag instanceof CopySourceOperand and
operandTag instanceof CopySourceOperandTag and
result = getInstruction(getElementDefaultValueTag())
)
)
@@ -981,9 +982,9 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
operandTag instanceof UnaryOperandTag and
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
}

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.internal.TempVariableTag
private import semmle.code.cpp.ir.internal.OperandTag
private import InstructionTag
private import TranslatedCondition
private import TranslatedDeclarationEntry
@@ -732,7 +733,7 @@ class TranslatedSwitchStmt extends TranslatedStmt {
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = SwitchBranchTag() and
operandTag instanceof ConditionOperand and
operandTag instanceof ConditionOperandTag and
result = getExpr().getResult()
}

View File

@@ -2,7 +2,7 @@ import FunctionIR
import Instruction
import IRBlock
import IRVariable
import OperandTag
import Operand
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind

View File

@@ -2,12 +2,13 @@ private import internal.IRInternal
import FunctionIR
import IRBlock
import IRVariable
import OperandTag
import Operand
import cpp
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
class InstructionTag = Construction::InstructionTagType;
@@ -22,21 +23,21 @@ module InstructionSanity {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
(
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperand or
tag instanceof RightOperand
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
) or
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
)
)
}
@@ -45,26 +46,34 @@ module InstructionSanity {
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, OperandTag tag) {
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
expectsOperand(instr, tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
strictcount(instr.getOperand(tag)) > 1 and
not tag instanceof UnmodeledUseOperand
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) > 1 and
not tag instanceof UnmodeledUseOperandTag
}
/**
@@ -74,7 +83,7 @@ module InstructionSanity {
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiOperand operand |
exists(instr.getOperand(operand)) and
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
@@ -98,14 +107,13 @@ module InstructionSanity {
}
/**
* Holds if instruction `op` consumes an operand `operand` that was defined in
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(
Instruction op, Instruction operand, OperandTag tag
) {
operand = op.getOperand(tag) and
operand.getFunctionIR() != op.getFunctionIR()
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getInstruction() = instr and
operand.getDefinitionInstruction() = defInstr and
instr.getFunctionIR() != defInstr.getFunctionIR()
}
/**
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
result = concat(Operand operand |
operand = getAnOperand() |
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
)
}
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
}
/**
* Gets the instruction that produced the value of the specified source
* operand.
* Gets all direct uses of the result of this instruction.
*/
final Instruction getOperand(OperandTag tag) {
result = Construction::getInstructionOperand(this, tag)
final Operand getAUse() {
result.getDefinitionInstruction() = this
}
/**
* Gets all instructions consumed by this instruction's operands.
* Gets all of this instruction's operands.
*/
final Instruction getAnOperand() {
result = getOperand(_)
final Operand getAnOperand() {
result.getInstruction() = this
}
/**
* Holds if this instruction has a memory operand with the specified tag.
*/
final predicate isMemoryOperand(OperandTag tag) {
exists(getOperandMemoryAccess(tag))
}
/**
* Gets the kind of memory access performed by the specified operand. Holds
* only for memory operands.
*/
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
none()
}
/**
* Holds if this instruction produces a memory result.
*/
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
this = useInstr.getOperand(useTag)
)
not (getAUse() instanceof UnmodeledUseOperand)
}
/**
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
final Instruction getObjectAddress() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
}
final Instruction getReturnValue() {
result = getOperand(returnValueOperand())
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ReturnValueOperand))) and
result instanceof IndirectMemoryAccess
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
}
}
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
}
final Instruction getSourceValue() {
result = getOperand(copySourceOperand())
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
}
}
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
opcode instanceof Opcode::Load
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(CopySourceOperand))) and
result instanceof IndirectMemoryAccess
}
final Instruction getSourceAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
}
final Instruction getDestinationAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
}
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
}
final Instruction getCondition() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getTrueSuccessor() {
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
}
final Instruction getLeftOperand() {
result = getOperand(leftOperand())
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
}
final Instruction getRightOperand() {
result = getOperand(rightOperand())
result = getAnOperand().(RightOperand).getDefinitionInstruction()
}
}
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
}
final Instruction getOperand() {
result = getOperand(unaryOperand())
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
}
}
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
RelationalInstruction() {
opcode instanceof RelationalOpcode
}
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational instruction, that is, the side that is larger
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
Instruction getLesserOperand() {
none()
}
/**
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
*/
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
}
final Instruction getExpression() {
result = getOperand(conditionOperand())
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
}
final Instruction getACaseSuccessor() {
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
}
final Instruction getCallTarget() {
result = getOperand(callTargetOperand())
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
}
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
opcode instanceof Opcode::ThrowValue
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(ExceptionOperand))) and
result instanceof IndirectMemoryAccess
}
/**
* Gets the address of the exception thrown by this instruction.
*/
final Instruction getExceptionAddress() {
result = getOperand(loadStoreAddressOperand())
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
}
/**
* Gets the exception thrown by this instruction.
*/
final Instruction getException() {
result = getOperand(exceptionOperand())
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
}
}
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
result instanceof UnmodeledMemoryAccess
}
}
class PhiInstruction extends Instruction {
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
opcode instanceof Opcode::Phi
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
exists(this.getOperand(tag.(PhiOperand))) and
result instanceof PhiMemoryAccess
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}

View File

@@ -0,0 +1,360 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private import semmle.code.cpp.ir.internal.OperandTag
private newtype TOperand =
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
defInstr = Construction::getInstructionOperand(instr, tag)
} or
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
}
/**
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/
class Operand extends TOperand {
string toString() {
result = "Operand"
}
/**
* Gets the `Instruction` that consumes this operand.
*/
Instruction getInstruction() {
none()
}
/**
* Gets the `Instruction` whose result is the value of the operand.
*/
Instruction getDefinitionInstruction() {
none()
}
/**
* Gets a prefix to use when dumping the operand in an operand list.
*/
string getDumpLabel() {
result = ""
}
/**
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
* result ID of the instruction consumed by the operand, plus a label identifying the operand
* kind.
*
* For example: `this:r3_5`
*/
final string getDumpString() {
result = getDumpLabel() + getDefinitionInstruction().getResultId()
}
/**
* Get the order in which the operand should be sorted in the operand list.
*/
int getDumpSortOrder() {
result = -1
}
/**
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
*/
MemoryAccessKind getMemoryAccess() {
none()
}
/**
* Returns the operand that holds the memory address from which the current operand loads its
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
* is `r1`.
*/
final AddressOperand getAddressOperand() {
getMemoryAccess() instanceof IndirectMemoryAccess and
result.getInstruction() = getInstruction()
}
}
/**
* An operand that is not an operand of a `PhiInstruction`.
*/
class NonPhiOperand extends Operand, TNonPhiOperand {
Instruction instr;
Instruction defInstr;
OperandTag tag;
NonPhiOperand() {
this = TNonPhiOperand(instr, tag, defInstr)
}
override final Instruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final string getDumpLabel() {
result = tag.getLabel()
}
override final int getDumpSortOrder() {
result = tag.getSortOrder()
}
final OperandTag getOperandTag() {
result = tag
}
}
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class AddressOperand extends NonPhiOperand {
AddressOperand() {
this = TNonPhiOperand(_, addressOperand(), _)
}
override string toString() {
result = "Address"
}
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends NonPhiOperand {
CopySourceOperand() {
this = TNonPhiOperand(_, copySourceOperand(), _)
}
override string toString() {
result = "CopySource"
}
override final MemoryAccessKind getMemoryAccess() {
instr.getOpcode() instanceof Opcode::Load and
result instanceof IndirectMemoryAccess
}
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends NonPhiOperand {
UnaryOperand() {
this = TNonPhiOperand(_, unaryOperand(), _)
}
override string toString() {
result = "Unary"
}
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends NonPhiOperand {
LeftOperand() {
this = TNonPhiOperand(_, leftOperand(), _)
}
override string toString() {
result = "Left"
}
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends NonPhiOperand {
RightOperand() {
this = TNonPhiOperand(_, rightOperand(), _)
}
override string toString() {
result = "Right"
}
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends NonPhiOperand {
ReturnValueOperand() {
this = TNonPhiOperand(_, returnValueOperand(), _)
}
override string toString() {
result = "ReturnValue"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends NonPhiOperand {
ExceptionOperand() {
this = TNonPhiOperand(_, exceptionOperand(), _)
}
override string toString() {
result = "Exception"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof IndirectMemoryAccess
}
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends NonPhiOperand {
ConditionOperand() {
this = TNonPhiOperand(_, conditionOperand(), _)
}
override string toString() {
result = "Condition"
}
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends NonPhiOperand {
UnmodeledUseOperand() {
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
}
override string toString() {
result = "UnmodeledUse"
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends NonPhiOperand {
CallTargetOperand() {
this = TNonPhiOperand(_, callTargetOperand(), _)
}
override string toString() {
result = "CallTarget"
}
}
/**
* 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`).
*/
class ArgumentOperand extends NonPhiOperand {
ArgumentOperand() {
exists(ArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _)
)
}
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
ThisArgumentOperand() {
this = TNonPhiOperand(_, thisArgumentOperand(), _)
}
override string toString() {
result = "ThisArgument"
}
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
exists(PositionalArgumentOperandTag argTag |
this = TNonPhiOperand(_, argTag, _) and
argIndex = argTag.getArgIndex()
)
}
override string toString() {
result = "Arg(" + argIndex + ")"
}
}
/**
* An operand of a `PhiInstruction`.
*/
class PhiOperand extends Operand, TPhiOperand {
PhiInstruction instr;
Instruction defInstr;
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(instr, defInstr, predecessorBlock)
}
override string toString() {
result = "Phi"
}
override final PhiInstruction getInstruction() {
result = instr
}
override final Instruction getDefinitionInstruction() {
result = defInstr
}
override final int getDumpSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getDumpLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
/**
* Gets the predecessor block from which this value comes.
*/
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
override final MemoryAccessKind getMemoryAccess() {
result instanceof PhiMemoryAccess
}
}
/**
* An operand that reads a value from memory.
*/
class MemoryOperand extends Operand {
MemoryOperand() {
exists(getMemoryAccess())
}
}

View File

@@ -1,312 +0,0 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
string getLabel() {
result = ""
}
}
// 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`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand 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 ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
override final string getLabel() {
result = "this:"
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -46,18 +46,20 @@ private IntValue getFieldBitOffset(Field field) {
* not result in any address held in that operand from escaping beyond the
* instruction.
*/
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
(
// The source/destination address of a Load/Store does not escape (but the
// loaded/stored value could).
tag instanceof LoadStoreAddressOperand or
// Neither operand of a Compare escapes.
instr instanceof CompareInstruction or
// Neither operand of a PointerDiff escapes.
instr instanceof PointerDiffInstruction or
// Converting an address to a `bool` does not escape the address.
instr.(ConvertInstruction).getResultType() instanceof BoolType
predicate operandIsConsumedWithoutEscaping(Operand operand) {
// The source/destination address of a Load/Store does not escape (but the
// loaded/stored value could).
operand instanceof AddressOperand or
exists (Instruction instr |
instr = operand.getInstruction() and
(
// Neither operand of a Compare escapes.
instr instanceof CompareInstruction or
// Neither operand of a PointerDiff escapes.
instr instanceof PointerDiffInstruction or
// Converting an address to a `bool` does not escape the address.
instr.(ConvertInstruction).getResultType() instanceof BoolType
)
)
}
@@ -96,43 +98,44 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
* `bitOffset`. If the address is propagated, but the offset is not known to be
* a constant, then `bitOffset` is unknown.
*/
predicate operandIsPropagated(Instruction instr, OperandTag tag,
IntValue bitOffset) {
exists(instr.getOperand(tag)) and
(
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
) or
// Converting to a virtual base class adds an unknown offset.
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
exists(Instruction instr |
instr = operand.getInstruction() and
(
instr instanceof ConvertToVirtualBaseInstruction and
bitOffset = Ints::unknown()
) or
// Conversion to another pointer type propagates the source address.
exists(ConvertInstruction convert, Type resultType |
convert = instr and
resultType = convert.getResultType() and
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
) or
// Converting to a virtual base class adds an unknown offset.
(
resultType instanceof PointerType or
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
) and
bitOffset = 0
) or
// Adding an integer to or subtracting an integer from a pointer propagates
// the address with an offset.
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
// Computing a field address from a pointer propagates the address plus the
// offset of the field.
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
// A copy propagates the source value.
tag instanceof CopySourceOperand and bitOffset = 0
instr instanceof ConvertToVirtualBaseInstruction and
bitOffset = Ints::unknown()
) or
// Conversion to another pointer type propagates the source address.
exists(ConvertInstruction convert, Type resultType |
convert = instr and
resultType = convert.getResultType() and
(
resultType instanceof PointerType or
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
) and
bitOffset = 0
) or
// Adding an integer to or subtracting an integer from a pointer propagates
// the address with an offset.
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
// Computing a field address from a pointer propagates the address plus the
// offset of the field.
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
// A copy propagates the source value.
operand instanceof CopySourceOperand and bitOffset = 0
)
)
}
@@ -140,16 +143,15 @@ predicate operandIsPropagated(Instruction instr, OperandTag tag,
* Holds if any address held in operand number `tag` of instruction `instr`
* escapes outside the domain of the analysis.
*/
predicate operandEscapes(Instruction instr, OperandTag tag) {
exists(instr.getOperand(tag)) and
predicate operandEscapes(Operand operand) {
// Conservatively assume that the address escapes unless one of the following
// holds:
not (
// The operand is used in a way that does not escape the instruction
operandIsConsumedWithoutEscaping(instr, tag) or
operandIsConsumedWithoutEscaping(operand) or
// The address is propagated to the result of the instruction, but that
// result does not itself escape.
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
operandIsPropagated(operand, _) and not resultEscapes(operand.getInstruction())
)
}
@@ -159,10 +161,7 @@ predicate operandEscapes(Instruction instr, OperandTag tag) {
*/
predicate resultEscapes(Instruction instr) {
// The result escapes if it has at least one use that escapes.
exists(Instruction useInstr, OperandTag useOperandTag |
useInstr.getOperand(useOperandTag) = instr and
operandEscapes(useInstr, useOperandTag)
)
operandEscapes(instr.getAUse())
}
/**
@@ -203,12 +202,12 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getVariable() = var and
bitOffset = 0
) or
exists(OperandTag operandTag, IntValue originalBitOffset,
IntValue propagatedBitOffset |
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,
// offset by the bit offset from the propagation.
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
operandIsPropagated(operand, propagatedBitOffset) and
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
)
}

View File

@@ -1,30 +1,13 @@
import SSAConstructionInternal
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
import NewIR
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
import IRBlockConstruction as BlockConstruction
import Cached
cached private module Cached {
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
exists(PositionalArgumentOperand newArg |
newArg = newTag and
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
)
}
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
@@ -49,14 +32,6 @@ cached private module Cached {
)
}
cached int getMaxCallArgIndex() {
result = max(int argIndex |
exists(OldIR::PositionalArgumentOperand oldOperand |
argIndex = oldOperand.getArgIndex()
)
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
@@ -136,17 +111,18 @@ cached private module Cached {
}
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
oldUse = getOldInstruction(instruction) and
oldTag = getOldOperandTag(tag) and
if oldUse.isMemoryOperand(oldTag) then (
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
if defIndex >= 0 then
result = getNewInstruction(defBlock.getInstruction(defIndex))
@@ -162,25 +138,24 @@ cached private module Cached {
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperand and
oldDefinition = oldUse.getOperand(oldTag) and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
result = getNewInstruction(oldDefinition)
)
)
else
result = getNewInstruction(oldUse.getOperand(oldTag))
) or
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
result = getNewInstruction(oldOperand.getDefinitionInstruction())
)
}
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
tag.getPredecessorBlock() = getNewBlock(predBlock) and
newPredecessorBlock = getNewBlock(predBlock) and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
if defIndex >= 0 then
@@ -277,7 +252,7 @@ cached private module Cached {
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
exists(Alias::MemoryAccess access |
access = Alias::getOperandMemoryAccess(use, _) and
access = Alias::getOperandMemoryAccess(use.getAnOperand()) and
block.getInstruction(index) = use and
vvar = access.getVirtualVariable()
)

View File

@@ -2,7 +2,8 @@ import SimpleSSAInternal
import cpp
import Alias
private import InputIR
import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private newtype TVirtualVariable =
MkVirtualVariable(IRVariable var) {
@@ -69,15 +70,15 @@ Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
MemoryAccess getResultMemoryAccess(Instruction instr) {
exists(IRVariable var |
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(),
var, 0) and
result = getMemoryAccess(var)
)
}
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
MemoryAccess getOperandMemoryAccess(Operand operand) {
exists(IRVariable var |
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, 0) and
result = getMemoryAccess(var)
)
}

View File

@@ -1,10 +1,15 @@
private import internal.IRInternal
import Instruction
import IRBlock
import cpp
private int getMaxCallArgIndex() {
result = max(int argIndex |
exists(FunctionCall call |
exists(call.getArgument(argIndex))
)
)
}
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
@@ -16,15 +21,10 @@ private newtype TOperandTag =
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
argIndex in [0..getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
@@ -49,9 +49,9 @@ abstract class OperandTag extends TOperandTag {
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
class AddressOperandTag extends OperandTag, TAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
result = "Address"
}
override final int getSortOrder() {
@@ -59,15 +59,15 @@ class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
AddressOperandTag addressOperand() {
result = TAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
class CopySourceOperandTag extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
@@ -77,14 +77,14 @@ class CopySourceOperand extends OperandTag, TCopySourceOperand {
}
}
CopySourceOperand copySourceOperand() {
CopySourceOperandTag copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
class UnaryOperandTag extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
@@ -94,14 +94,14 @@ class UnaryOperand extends OperandTag, TUnaryOperand {
}
}
UnaryOperand unaryOperand() {
UnaryOperandTag unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
class LeftOperandTag extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
@@ -111,14 +111,14 @@ class LeftOperand extends OperandTag, TLeftOperand {
}
}
LeftOperand leftOperand() {
LeftOperandTag leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
class RightOperandTag extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
@@ -128,14 +128,14 @@ class RightOperand extends OperandTag, TRightOperand {
}
}
RightOperand rightOperand() {
RightOperandTag rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
class ReturnValueOperandTag extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
@@ -145,14 +145,14 @@ class ReturnValueOperand extends OperandTag, TReturnValueOperand {
}
}
ReturnValueOperand returnValueOperand() {
ReturnValueOperandTag returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
class ExceptionOperandTag extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
@@ -162,14 +162,14 @@ class ExceptionOperand extends OperandTag, TExceptionOperand {
}
}
ExceptionOperand exceptionOperand() {
ExceptionOperandTag exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
class ConditionOperandTag extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
@@ -179,7 +179,7 @@ class ConditionOperand extends OperandTag, TConditionOperand {
}
}
ConditionOperand conditionOperand() {
ConditionOperandTag conditionOperand() {
result = TConditionOperand()
}
@@ -187,7 +187,7 @@ ConditionOperand conditionOperand() {
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
class UnmodeledUseOperandTag extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
@@ -197,14 +197,14 @@ class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
}
}
UnmodeledUseOperand unmodeledUseOperand() {
UnmodeledUseOperandTag unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
class CallTargetOperandTag extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
@@ -214,7 +214,7 @@ class CallTargetOperand extends OperandTag, TCallTargetOperand {
}
}
CallTargetOperand callTargetOperand() {
CallTargetOperandTag callTargetOperand() {
result = TCallTargetOperand()
}
@@ -223,15 +223,15 @@ CallTargetOperand callTargetOperand() {
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
abstract class ArgumentOperandTag extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
ThisArgumentOperandTag() {
this = TThisArgumentOperand()
}
@@ -248,18 +248,18 @@ class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
}
}
ThisArgumentOperand thisArgumentOperand() {
ThisArgumentOperandTag thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
class PositionalArgumentOperandTag extends ArgumentOperandTag,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
PositionalArgumentOperandTag() {
this = TPositionalArgumentOperand(argIndex)
}
@@ -276,37 +276,6 @@ class PositionalArgumentOperand extends ArgumentOperand,
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -19,8 +19,8 @@ IntValue getConstantValue(Instruction instr) {
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) and
result = min(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand))
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}