mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge pull request #3796 from dbartol/codeql-c-analysis-team/40/2
C++: QLDoc for all of `Instruction.qll`
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes that represent the individual instructions in the IR for a function.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
import IRFunction
|
||||
import IRBlock
|
||||
@@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single operation in the IR.
|
||||
* A single instruction in the IR.
|
||||
*/
|
||||
class Instruction extends Construction::TStageInstruction {
|
||||
Instruction() {
|
||||
@@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
Construction::hasInstruction(this)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||
|
||||
/**
|
||||
@@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction {
|
||||
* given by `getResultType()`.
|
||||
*
|
||||
* For example, the statement `y = x;` generates the following IR:
|
||||
* ```
|
||||
* r1_0(glval: int) = VariableAddress[x]
|
||||
* r1_1(int) = Load r1_0, mu0_1
|
||||
* r1_2(glval: int) = VariableAddress[y]
|
||||
* mu1_3(int) = Store r1_2, r1_1
|
||||
* ```
|
||||
*
|
||||
* The result of each `VariableAddress` instruction is a glvalue of type
|
||||
* `int`, representing the address of the corresponding integer variable. The
|
||||
@@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction {
|
||||
final Instruction getAPredecessor() { result = getPredecessor(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a variable.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* variable. For example, it is used for `VariableAddress`, which returns the address of a specific
|
||||
* variable, and `InitializeParameter`, which returns the value that was passed to the specified
|
||||
* parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions
|
||||
* that happen to load from or store to a particular variable; in those cases, the memory location
|
||||
* being accessed is specified by the `AddressOperand` on the instruction, which may or may not be
|
||||
* defined by the result of a `VariableAddress` instruction.
|
||||
*/
|
||||
class VariableInstruction extends Instruction {
|
||||
IRVariable var;
|
||||
|
||||
@@ -406,6 +424,9 @@ class VariableInstruction extends Instruction {
|
||||
|
||||
override string getImmediateString() { result = var.toString() }
|
||||
|
||||
/**
|
||||
* Gets the variable that this instruction references.
|
||||
*/
|
||||
final IRVariable getIRVariable() { result = var }
|
||||
|
||||
/**
|
||||
@@ -414,6 +435,16 @@ class VariableInstruction extends Instruction {
|
||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a field of a class, struct, or union.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* field. For example, it is used for `FieldAddress`, which computes the address of a specific
|
||||
* field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen
|
||||
* to load from or store to a particular field; in those cases, the memory location being accessed
|
||||
* is specified by the `AddressOperand` on the instruction, which may or may not be defined by the
|
||||
* result of a `FieldAddress` instruction.
|
||||
*/
|
||||
class FieldInstruction extends Instruction {
|
||||
Language::Field field;
|
||||
|
||||
@@ -421,9 +452,22 @@ class FieldInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = field.toString() }
|
||||
|
||||
/**
|
||||
* Gets the field that this instruction references.
|
||||
*/
|
||||
final Language::Field getField() { result = field }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a function.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* function. For example, it is used for `FunctionAddress`, which returns the address of a specific
|
||||
* function. `FunctionInstruction` is not used for `Call` instructions that happen to call a
|
||||
* particular function; in that case, the function being called is specified by the
|
||||
* `CallTargetOperand` on the instruction, which may or may not be defined by the result of a
|
||||
* `FunctionAddress` instruction.
|
||||
*/
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
|
||||
@@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = funcSymbol.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function that this instruction references.
|
||||
*/
|
||||
final Language::Function getFunctionSymbol() { result = funcSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a compile-time constant value.
|
||||
*/
|
||||
class ConstantValueInstruction extends Instruction {
|
||||
string value;
|
||||
|
||||
@@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = value }
|
||||
|
||||
/**
|
||||
* Gets the constant value of this instruction's result.
|
||||
*/
|
||||
final string getValue() { result = value }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to an argument of a `Call` instruction.
|
||||
*
|
||||
* This instruction is used for side effects of a `Call` instruction that read or write memory
|
||||
* pointed to by one of the arguments of the call.
|
||||
*/
|
||||
class IndexedInstruction extends Instruction {
|
||||
int index;
|
||||
|
||||
@@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = index.toString() }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the argument that this instruction references.
|
||||
*/
|
||||
final int getIndex() { result = index }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the entry point to a function.
|
||||
*
|
||||
* Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins
|
||||
* at this instruction. This instruction has no predecessors.
|
||||
*/
|
||||
class EnterFunctionInstruction extends Instruction {
|
||||
EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns the address of a variable.
|
||||
*
|
||||
* This instruction returns the address of a local variable, parameter, static field,
|
||||
* namespace-scope variable, or global variable. For the address of a non-static field of a class,
|
||||
* struct, or union, see `FieldAddressInstruction`.
|
||||
*/
|
||||
class VariableAddressInstruction extends VariableInstruction {
|
||||
VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a parameter of the enclosing function with the value of the
|
||||
* corresponding argument passed by the caller.
|
||||
*
|
||||
* Each parameter of a function will have exactly one `InitializeParameter` instruction that
|
||||
* initializes that parameter.
|
||||
*/
|
||||
class InitializeParameterInstruction extends VariableInstruction {
|
||||
InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter }
|
||||
|
||||
/**
|
||||
* Gets the parameter initialized by this instruction.
|
||||
*/
|
||||
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes the memory pointed to by a parameter of the enclosing function
|
||||
* with the value of that memory on entry to the function.
|
||||
*/
|
||||
class InitializeIndirectionInstruction extends VariableInstruction {
|
||||
InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection }
|
||||
|
||||
/**
|
||||
* Gets the parameter initialized by this instruction.
|
||||
*/
|
||||
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
@@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the address of a non-static field of an object.
|
||||
*/
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the object containing the field.
|
||||
*/
|
||||
final UnaryOperand getObjectAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the object containing the field.
|
||||
*/
|
||||
final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
@@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() { getOpcode() instanceof Opcode::Error }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns an uninitialized value.
|
||||
*
|
||||
* This instruction is used to provide an initial definition for a stack variable that does not have
|
||||
* an initializer, or whose initializer only partially initializes the variable.
|
||||
*/
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized }
|
||||
|
||||
@@ -512,35 +619,94 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has no effect.
|
||||
*
|
||||
* This instruction is typically inserted to ensure that a particular AST is associated with at
|
||||
* least one instruction, even when the AST has no semantic effect.
|
||||
*/
|
||||
class NoOpInstruction extends Instruction {
|
||||
NoOpInstruction() { getOpcode() instanceof Opcode::NoOp }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function.
|
||||
*
|
||||
* This instruction represents the normal (non-exception) return from a function, either from an
|
||||
* explicit `return` statement or from control flow reaching the end of the function's body.
|
||||
*
|
||||
* Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is
|
||||
* represented as an initialization of the temporary variable that holds the return value, with
|
||||
* control then flowing to the common `ReturnInstruction` for that function. Exception: A function
|
||||
* that never returns will not have a `ReturnInstruction`.
|
||||
*
|
||||
* The `ReturnInstruction` for a function will have a control-flow successor edge to a block
|
||||
* containing the `ExitFunction` instruction for that function.
|
||||
*
|
||||
* There are two differet return instructions: `ReturnValueInstruction`, for returning a value from
|
||||
* a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a
|
||||
* `void`-returning function.
|
||||
*/
|
||||
class ReturnInstruction extends Instruction {
|
||||
ReturnInstruction() { getOpcode() instanceof ReturnOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function, without returning a value.
|
||||
*/
|
||||
class ReturnVoidInstruction extends ReturnInstruction {
|
||||
ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function, including a return value.
|
||||
*/
|
||||
class ReturnValueInstruction extends ReturnInstruction {
|
||||
ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the value being returned by the function.
|
||||
*/
|
||||
final LoadOperand getReturnValueOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value being returned by the function, if an
|
||||
* exact definition is available.
|
||||
*/
|
||||
final Instruction getReturnValue() { result = getReturnValueOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that represents the use of the value pointed to by a parameter of the function
|
||||
* after the function returns control to its caller.
|
||||
*
|
||||
* This instruction does not itself return control to the caller. It merely represents the potential
|
||||
* for a caller to use the memory pointed to by the parameter sometime after the call returns. This
|
||||
* is the counterpart to the `InitializeIndirection` instruction, which represents the possibility
|
||||
* that the caller initialized the memory pointed to by the parameter before the call.
|
||||
*/
|
||||
class ReturnIndirectionInstruction extends VariableInstruction {
|
||||
ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the value of the pointed-to memory.
|
||||
*/
|
||||
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the pointed-to memory, if an exact
|
||||
* definition is available.
|
||||
*/
|
||||
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the pointed-to memory.
|
||||
*/
|
||||
final AddressOperand getSourceAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the pointed-to memory.
|
||||
*/
|
||||
final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
|
||||
|
||||
/**
|
||||
@@ -555,60 +721,128 @@ class ReturnIndirectionInstruction extends VariableInstruction {
|
||||
final predicate isThisIndirection() { var instanceof IRThisVariable }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a copy of its operand.
|
||||
*
|
||||
* There are several different copy instructions, depending on the source and destination of the
|
||||
* copy operation:
|
||||
* - `CopyInstruction` - Copies a register operand to a register result.
|
||||
* - `LoadInstruction` - Copies a memory operand to a register result.
|
||||
* - `StoreInstruction` - Copies a register operand to a memory result.
|
||||
*/
|
||||
class CopyInstruction extends Instruction {
|
||||
CopyInstruction() { getOpcode() instanceof CopyOpcode }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the input value of the copy.
|
||||
*/
|
||||
Operand getSourceValueOperand() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the input value of the copy, if an exact definition
|
||||
* is available.
|
||||
*/
|
||||
final Instruction getSourceValue() { result = getSourceValueOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a register result containing a copy of its register operand.
|
||||
*/
|
||||
class CopyValueInstruction extends CopyInstruction, UnaryInstruction {
|
||||
CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue }
|
||||
|
||||
final override UnaryOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a register result containing a copy of its memory operand.
|
||||
*/
|
||||
class LoadInstruction extends CopyInstruction {
|
||||
LoadInstruction() { getOpcode() instanceof Opcode::Load }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the value being loaded.
|
||||
*/
|
||||
final AddressOperand getSourceAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the value being loaded.
|
||||
*/
|
||||
final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
|
||||
|
||||
final override LoadOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a memory result containing a copy of its register operand.
|
||||
*/
|
||||
class StoreInstruction extends CopyInstruction {
|
||||
StoreInstruction() { getOpcode() instanceof Opcode::Store }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the location to which the value will be stored.
|
||||
*/
|
||||
final AddressOperand getDestinationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the location to which the value will
|
||||
* be stored, if an exact definition is available.
|
||||
*/
|
||||
final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() }
|
||||
|
||||
final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that branches to one of two successor instructions based on the value of a Boolean
|
||||
* operand.
|
||||
*/
|
||||
class ConditionalBranchInstruction extends Instruction {
|
||||
ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the Boolean condition controlling the branch.
|
||||
*/
|
||||
final ConditionOperand getConditionOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the Boolean condition controlling the branch.
|
||||
*/
|
||||
final Instruction getCondition() { result = getConditionOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the instruction to which control will flow if the condition is true.
|
||||
*/
|
||||
final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) }
|
||||
|
||||
/**
|
||||
* Gets the instruction to which control will flow if the condition is false.
|
||||
*/
|
||||
final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the exit point of a function.
|
||||
*
|
||||
* Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns
|
||||
* nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns
|
||||
* (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no
|
||||
* successors.
|
||||
*/
|
||||
class ExitFunctionInstruction extends Instruction {
|
||||
ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value.
|
||||
*/
|
||||
class ConstantInstruction extends ConstantValueInstruction {
|
||||
ConstantInstruction() { getOpcode() instanceof Opcode::Constant }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of integer or Boolean type.
|
||||
*/
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
@@ -618,27 +852,53 @@ class IntegerConstantInstruction extends ConstantInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of floating-point type.
|
||||
*/
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is the address of a string literal.
|
||||
*/
|
||||
class StringConstantInstruction extends VariableInstruction {
|
||||
override IRStringLiteral var;
|
||||
|
||||
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
|
||||
|
||||
/**
|
||||
* Gets the string literal whose address is returned by this instruction.
|
||||
*/
|
||||
final Language::StringLiteral getValue() { result = var.getLiteral() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed from two operands.
|
||||
*/
|
||||
class BinaryInstruction extends Instruction {
|
||||
BinaryInstruction() { getOpcode() instanceof BinaryOpcode }
|
||||
|
||||
/**
|
||||
* Gets the left operand of this binary instruction.
|
||||
*/
|
||||
final LeftOperand getLeftOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the right operand of this binary instruction.
|
||||
*/
|
||||
final RightOperand getRightOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left operand of this binary
|
||||
* instruction.
|
||||
*/
|
||||
final Instruction getLeft() { result = getLeftOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the right operand of this binary
|
||||
* instruction.
|
||||
*/
|
||||
final Instruction getRight() { result = getRightOperand().getDef() }
|
||||
|
||||
/**
|
||||
@@ -651,66 +911,161 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the result of an arithmetic operation.
|
||||
*/
|
||||
class ArithmeticInstruction extends Instruction {
|
||||
ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs an arithmetic operation on two numeric operands.
|
||||
*/
|
||||
class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed by performing an arithmetic operation on a single
|
||||
* numeric operand.
|
||||
*/
|
||||
class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that computes the sum of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is
|
||||
* performed according to IEEE-754.
|
||||
*/
|
||||
class AddInstruction extends BinaryArithmeticInstruction {
|
||||
AddInstruction() { getOpcode() instanceof Opcode::Add }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the difference of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed
|
||||
* according to IEEE-754.
|
||||
*/
|
||||
class SubInstruction extends BinaryArithmeticInstruction {
|
||||
SubInstruction() { getOpcode() instanceof Opcode::Sub }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the product of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is
|
||||
* performed according to IEEE-754.
|
||||
*/
|
||||
class MulInstruction extends BinaryArithmeticInstruction {
|
||||
MulInstruction() { getOpcode() instanceof Opcode::Mul }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the quotient of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* division by zero or integer overflow is undefined. Floating-point division is performed according
|
||||
* to IEEE-754.
|
||||
*/
|
||||
class DivInstruction extends BinaryArithmeticInstruction {
|
||||
DivInstruction() { getOpcode() instanceof Opcode::Div }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the remainder of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type. The result of
|
||||
* division by zero or integer overflow is undefined.
|
||||
*/
|
||||
class RemInstruction extends BinaryArithmeticInstruction {
|
||||
RemInstruction() { getOpcode() instanceof Opcode::Rem }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that negates a single numeric operand.
|
||||
*
|
||||
* The operand must have a numeric type, which will also be the result type. The result of integer
|
||||
* negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation
|
||||
* is performed according to IEEE-754.
|
||||
*/
|
||||
class NegateInstruction extends UnaryArithmeticInstruction {
|
||||
NegateInstruction() { getOpcode() instanceof Opcode::Negate }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the result of a bitwise operation.
|
||||
*/
|
||||
class BitwiseInstruction extends Instruction {
|
||||
BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs a bitwise operation on two integer operands.
|
||||
*/
|
||||
class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that performs a bitwise operation on a single integer operand.
|
||||
*/
|
||||
class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "and" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitAndInstruction extends BinaryBitwiseInstruction {
|
||||
BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "or" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitOrInstruction extends BinaryBitwiseInstruction {
|
||||
BitOrInstruction() { getOpcode() instanceof Opcode::BitOr }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "xor" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitXorInstruction extends BinaryBitwiseInstruction {
|
||||
BitXorInstruction() { getOpcode() instanceof Opcode::BitXor }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that shifts its left operand to the left by the number of bits specified by its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have an integer type. The result has the same type as the left operand. The
|
||||
* rightmost bits are zero-filled.
|
||||
*/
|
||||
class ShiftLeftInstruction extends BinaryBitwiseInstruction {
|
||||
ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that shifts its left operand to the right by the number of bits specified by its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have an integer type. The result has the same type as the left operand. If the
|
||||
* left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand
|
||||
* has a signed integer type, the leftmost bits are filled by duplicating the most significant bit
|
||||
* of the left operand.
|
||||
*/
|
||||
class ShiftRightInstruction extends BinaryBitwiseInstruction {
|
||||
ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs a binary arithmetic operation involving at least one pointer
|
||||
* operand.
|
||||
*/
|
||||
class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
int elementSize;
|
||||
|
||||
@@ -721,25 +1076,64 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
final override string getImmediateString() { result = elementSize.toString() }
|
||||
|
||||
/**
|
||||
* Gets the size of the elements pointed to by the pointer operands, in bytes.
|
||||
*
|
||||
* When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer
|
||||
* offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the
|
||||
* element size to compute the actual number of bytes added to or subtracted from the pointer
|
||||
* address. When computing the integer difference between two pointers (`PointerDiffInstruction`),
|
||||
* the result is computed by computing the difference between the two pointer byte addresses, then
|
||||
* dividing that byte count by the element size.
|
||||
*/
|
||||
final int getElementSize() { result = elementSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that adds or subtracts an integer offset from a pointer.
|
||||
*/
|
||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||
PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that adds an integer offset to a pointer.
|
||||
*
|
||||
* The result is the byte address computed by adding the value of the right (integer) operand,
|
||||
* multiplied by the element size, to the value of the left (pointer) operand. The result of pointer
|
||||
* overflow is undefined.
|
||||
*/
|
||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||
PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that subtracts an integer offset from a pointer.
|
||||
*
|
||||
* The result is the byte address computed by subtracting the value of the right (integer) operand,
|
||||
* multiplied by the element size, from the value of the left (pointer) operand. The result of
|
||||
* pointer underflow is undefined.
|
||||
*/
|
||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||
PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the difference between two pointers.
|
||||
*
|
||||
* Both operands must have the same pointer type. The result must have an integer type whose size is
|
||||
* the same as that of the pointer operands. The result is computed by subtracting the byte address
|
||||
* in the right operand from the byte address in the left operand, and dividing by the element size.
|
||||
* If the difference in byte addresses is not divisible by the element size, the result is
|
||||
* undefined.
|
||||
*/
|
||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||
PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed from a single operand.
|
||||
*/
|
||||
class UnaryInstruction extends Instruction {
|
||||
UnaryInstruction() { getOpcode() instanceof UnaryOpcode }
|
||||
|
||||
@@ -748,17 +1142,44 @@ class UnaryInstruction extends Instruction {
|
||||
final Instruction getUnary() { result = getUnaryOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the value of its operand to a value of a different type.
|
||||
*/
|
||||
class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the address of a polymorphic object to the address of a different
|
||||
* subobject of the same polymorphic object, returning a null address if the dynamic type of the
|
||||
* object is not compatible with the result type.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*
|
||||
* This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or
|
||||
* `as` expression.
|
||||
*/
|
||||
class CheckedConvertOrNullInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts between two addresses
|
||||
* related by inheritance.
|
||||
* An instruction that converts the address of a polymorphic object to the address of a different
|
||||
* subobject of the same polymorphic object, throwing an exception if the dynamic type of the object
|
||||
* is not compatible with the result type.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*
|
||||
* This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast
|
||||
* expression.
|
||||
*/
|
||||
class CheckedConvertOrThrowInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the address of an object to the address of a different subobject of
|
||||
* the same object, without any type checking at runtime.
|
||||
*/
|
||||
class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Language::Class baseClass;
|
||||
@@ -795,59 +1216,91 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a base class.
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a direct non-virtual base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a direct
|
||||
* non-virtual base class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction {
|
||||
ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a virtual base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a virtual base
|
||||
* class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction {
|
||||
ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a base class
|
||||
* to the address of a direct non-virtual derived class.
|
||||
* An instruction that converts from the address of a base class to the address of a direct
|
||||
* non-virtual derived class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise complement of its operand.
|
||||
*
|
||||
* The operand must have an integer type, which will also be the result type.
|
||||
*/
|
||||
class BitComplementInstruction extends UnaryBitwiseInstruction {
|
||||
BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the logical complement of its operand.
|
||||
*
|
||||
* The operand must have a Boolean type, which will also be the result type.
|
||||
*/
|
||||
class LogicalNotInstruction extends UnaryInstruction {
|
||||
LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that compares two numeric operands.
|
||||
*/
|
||||
class CompareInstruction extends BinaryInstruction {
|
||||
CompareInstruction() { getOpcode() instanceof CompareOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its operands are equal.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if `left == right`, and `false` if `left != right` or the two operands are
|
||||
* unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareEQInstruction extends CompareInstruction {
|
||||
CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its operands are not equal.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if `left != right` or if the two operands are unordered, and `false` if
|
||||
* `left == right`. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareNEInstruction extends CompareInstruction {
|
||||
CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
* An instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() { getOpcode() instanceof RelationalOpcode }
|
||||
@@ -874,6 +1327,13 @@ class RelationalInstruction extends CompareInstruction {
|
||||
predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is less than its right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT }
|
||||
|
||||
@@ -884,6 +1344,13 @@ class CompareLTInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is greater than its right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT }
|
||||
|
||||
@@ -894,6 +1361,14 @@ class CompareGTInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is less than or equal to its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE }
|
||||
|
||||
@@ -904,6 +1379,14 @@ class CompareLEInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is greater than or equal to its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE }
|
||||
|
||||
@@ -914,15 +1397,32 @@ class CompareGEInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that branches to one of multiple successor instructions based on the value of an
|
||||
* integer operand.
|
||||
*
|
||||
* This instruction will have zero or more successors whose edge kind is `CaseEdge`, each
|
||||
* representing the branch that will be taken if the controlling expression is within the range
|
||||
* specified for that case edge. The range of a case edge must be disjoint from the range of each
|
||||
* other case edge.
|
||||
*
|
||||
* The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`,
|
||||
* representing the branch that will be taken if the controlling expression is not within the range
|
||||
* of any case edge.
|
||||
*/
|
||||
class SwitchInstruction extends Instruction {
|
||||
SwitchInstruction() { getOpcode() instanceof Opcode::Switch }
|
||||
|
||||
/** Gets the operand that provides the integer value controlling the switch. */
|
||||
final ConditionOperand getExpressionOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the instruction whose result provides the integer value controlling the switch. */
|
||||
final Instruction getExpression() { result = getExpressionOperand().getDef() }
|
||||
|
||||
/** Gets the successor instructions along the case edges of the switch. */
|
||||
final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) }
|
||||
|
||||
/** Gets the successor instruction along the default edge of the switch, if any. */
|
||||
final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) }
|
||||
}
|
||||
|
||||
@@ -998,6 +1498,9 @@ class CallInstruction extends Instruction {
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose execution causes this side effect.
|
||||
*/
|
||||
final Instruction getPrimaryInstruction() {
|
||||
result = Construction::getPrimaryInstructionForSideEffect(this)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes that represent the individual instructions in the IR for a function.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
import IRFunction
|
||||
import IRBlock
|
||||
@@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single operation in the IR.
|
||||
* A single instruction in the IR.
|
||||
*/
|
||||
class Instruction extends Construction::TStageInstruction {
|
||||
Instruction() {
|
||||
@@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
Construction::hasInstruction(this)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||
|
||||
/**
|
||||
@@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction {
|
||||
* given by `getResultType()`.
|
||||
*
|
||||
* For example, the statement `y = x;` generates the following IR:
|
||||
* ```
|
||||
* r1_0(glval: int) = VariableAddress[x]
|
||||
* r1_1(int) = Load r1_0, mu0_1
|
||||
* r1_2(glval: int) = VariableAddress[y]
|
||||
* mu1_3(int) = Store r1_2, r1_1
|
||||
* ```
|
||||
*
|
||||
* The result of each `VariableAddress` instruction is a glvalue of type
|
||||
* `int`, representing the address of the corresponding integer variable. The
|
||||
@@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction {
|
||||
final Instruction getAPredecessor() { result = getPredecessor(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a variable.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* variable. For example, it is used for `VariableAddress`, which returns the address of a specific
|
||||
* variable, and `InitializeParameter`, which returns the value that was passed to the specified
|
||||
* parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions
|
||||
* that happen to load from or store to a particular variable; in those cases, the memory location
|
||||
* being accessed is specified by the `AddressOperand` on the instruction, which may or may not be
|
||||
* defined by the result of a `VariableAddress` instruction.
|
||||
*/
|
||||
class VariableInstruction extends Instruction {
|
||||
IRVariable var;
|
||||
|
||||
@@ -406,6 +424,9 @@ class VariableInstruction extends Instruction {
|
||||
|
||||
override string getImmediateString() { result = var.toString() }
|
||||
|
||||
/**
|
||||
* Gets the variable that this instruction references.
|
||||
*/
|
||||
final IRVariable getIRVariable() { result = var }
|
||||
|
||||
/**
|
||||
@@ -414,6 +435,16 @@ class VariableInstruction extends Instruction {
|
||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a field of a class, struct, or union.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* field. For example, it is used for `FieldAddress`, which computes the address of a specific
|
||||
* field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen
|
||||
* to load from or store to a particular field; in those cases, the memory location being accessed
|
||||
* is specified by the `AddressOperand` on the instruction, which may or may not be defined by the
|
||||
* result of a `FieldAddress` instruction.
|
||||
*/
|
||||
class FieldInstruction extends Instruction {
|
||||
Language::Field field;
|
||||
|
||||
@@ -421,9 +452,22 @@ class FieldInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = field.toString() }
|
||||
|
||||
/**
|
||||
* Gets the field that this instruction references.
|
||||
*/
|
||||
final Language::Field getField() { result = field }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to a function.
|
||||
*
|
||||
* This class is used for any instruction whose operation fundamentally depends on a specific
|
||||
* function. For example, it is used for `FunctionAddress`, which returns the address of a specific
|
||||
* function. `FunctionInstruction` is not used for `Call` instructions that happen to call a
|
||||
* particular function; in that case, the function being called is specified by the
|
||||
* `CallTargetOperand` on the instruction, which may or may not be defined by the result of a
|
||||
* `FunctionAddress` instruction.
|
||||
*/
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
|
||||
@@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = funcSymbol.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function that this instruction references.
|
||||
*/
|
||||
final Language::Function getFunctionSymbol() { result = funcSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a compile-time constant value.
|
||||
*/
|
||||
class ConstantValueInstruction extends Instruction {
|
||||
string value;
|
||||
|
||||
@@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = value }
|
||||
|
||||
/**
|
||||
* Gets the constant value of this instruction's result.
|
||||
*/
|
||||
final string getValue() { result = value }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that refers to an argument of a `Call` instruction.
|
||||
*
|
||||
* This instruction is used for side effects of a `Call` instruction that read or write memory
|
||||
* pointed to by one of the arguments of the call.
|
||||
*/
|
||||
class IndexedInstruction extends Instruction {
|
||||
int index;
|
||||
|
||||
@@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction {
|
||||
|
||||
final override string getImmediateString() { result = index.toString() }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the argument that this instruction references.
|
||||
*/
|
||||
final int getIndex() { result = index }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the entry point to a function.
|
||||
*
|
||||
* Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins
|
||||
* at this instruction. This instruction has no predecessors.
|
||||
*/
|
||||
class EnterFunctionInstruction extends Instruction {
|
||||
EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns the address of a variable.
|
||||
*
|
||||
* This instruction returns the address of a local variable, parameter, static field,
|
||||
* namespace-scope variable, or global variable. For the address of a non-static field of a class,
|
||||
* struct, or union, see `FieldAddressInstruction`.
|
||||
*/
|
||||
class VariableAddressInstruction extends VariableInstruction {
|
||||
VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a parameter of the enclosing function with the value of the
|
||||
* corresponding argument passed by the caller.
|
||||
*
|
||||
* Each parameter of a function will have exactly one `InitializeParameter` instruction that
|
||||
* initializes that parameter.
|
||||
*/
|
||||
class InitializeParameterInstruction extends VariableInstruction {
|
||||
InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter }
|
||||
|
||||
/**
|
||||
* Gets the parameter initialized by this instruction.
|
||||
*/
|
||||
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes the memory pointed to by a parameter of the enclosing function
|
||||
* with the value of that memory on entry to the function.
|
||||
*/
|
||||
class InitializeIndirectionInstruction extends VariableInstruction {
|
||||
InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection }
|
||||
|
||||
/**
|
||||
* Gets the parameter initialized by this instruction.
|
||||
*/
|
||||
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
@@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the address of a non-static field of an object.
|
||||
*/
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the object containing the field.
|
||||
*/
|
||||
final UnaryOperand getObjectAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the object containing the field.
|
||||
*/
|
||||
final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
@@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() { getOpcode() instanceof Opcode::Error }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns an uninitialized value.
|
||||
*
|
||||
* This instruction is used to provide an initial definition for a stack variable that does not have
|
||||
* an initializer, or whose initializer only partially initializes the variable.
|
||||
*/
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized }
|
||||
|
||||
@@ -512,35 +619,94 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has no effect.
|
||||
*
|
||||
* This instruction is typically inserted to ensure that a particular AST is associated with at
|
||||
* least one instruction, even when the AST has no semantic effect.
|
||||
*/
|
||||
class NoOpInstruction extends Instruction {
|
||||
NoOpInstruction() { getOpcode() instanceof Opcode::NoOp }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function.
|
||||
*
|
||||
* This instruction represents the normal (non-exception) return from a function, either from an
|
||||
* explicit `return` statement or from control flow reaching the end of the function's body.
|
||||
*
|
||||
* Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is
|
||||
* represented as an initialization of the temporary variable that holds the return value, with
|
||||
* control then flowing to the common `ReturnInstruction` for that function. Exception: A function
|
||||
* that never returns will not have a `ReturnInstruction`.
|
||||
*
|
||||
* The `ReturnInstruction` for a function will have a control-flow successor edge to a block
|
||||
* containing the `ExitFunction` instruction for that function.
|
||||
*
|
||||
* There are two differet return instructions: `ReturnValueInstruction`, for returning a value from
|
||||
* a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a
|
||||
* `void`-returning function.
|
||||
*/
|
||||
class ReturnInstruction extends Instruction {
|
||||
ReturnInstruction() { getOpcode() instanceof ReturnOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function, without returning a value.
|
||||
*/
|
||||
class ReturnVoidInstruction extends ReturnInstruction {
|
||||
ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns control to the caller of the function, including a return value.
|
||||
*/
|
||||
class ReturnValueInstruction extends ReturnInstruction {
|
||||
ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the value being returned by the function.
|
||||
*/
|
||||
final LoadOperand getReturnValueOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value being returned by the function, if an
|
||||
* exact definition is available.
|
||||
*/
|
||||
final Instruction getReturnValue() { result = getReturnValueOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that represents the use of the value pointed to by a parameter of the function
|
||||
* after the function returns control to its caller.
|
||||
*
|
||||
* This instruction does not itself return control to the caller. It merely represents the potential
|
||||
* for a caller to use the memory pointed to by the parameter sometime after the call returns. This
|
||||
* is the counterpart to the `InitializeIndirection` instruction, which represents the possibility
|
||||
* that the caller initialized the memory pointed to by the parameter before the call.
|
||||
*/
|
||||
class ReturnIndirectionInstruction extends VariableInstruction {
|
||||
ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the value of the pointed-to memory.
|
||||
*/
|
||||
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the pointed-to memory, if an exact
|
||||
* definition is available.
|
||||
*/
|
||||
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the pointed-to memory.
|
||||
*/
|
||||
final AddressOperand getSourceAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the pointed-to memory.
|
||||
*/
|
||||
final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
|
||||
|
||||
/**
|
||||
@@ -555,60 +721,128 @@ class ReturnIndirectionInstruction extends VariableInstruction {
|
||||
final predicate isThisIndirection() { var instanceof IRThisVariable }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a copy of its operand.
|
||||
*
|
||||
* There are several different copy instructions, depending on the source and destination of the
|
||||
* copy operation:
|
||||
* - `CopyInstruction` - Copies a register operand to a register result.
|
||||
* - `LoadInstruction` - Copies a memory operand to a register result.
|
||||
* - `StoreInstruction` - Copies a register operand to a memory result.
|
||||
*/
|
||||
class CopyInstruction extends Instruction {
|
||||
CopyInstruction() { getOpcode() instanceof CopyOpcode }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the input value of the copy.
|
||||
*/
|
||||
Operand getSourceValueOperand() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the input value of the copy, if an exact definition
|
||||
* is available.
|
||||
*/
|
||||
final Instruction getSourceValue() { result = getSourceValueOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a register result containing a copy of its register operand.
|
||||
*/
|
||||
class CopyValueInstruction extends CopyInstruction, UnaryInstruction {
|
||||
CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue }
|
||||
|
||||
final override UnaryOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a register result containing a copy of its memory operand.
|
||||
*/
|
||||
class LoadInstruction extends CopyInstruction {
|
||||
LoadInstruction() { getOpcode() instanceof Opcode::Load }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the value being loaded.
|
||||
*/
|
||||
final AddressOperand getSourceAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the value being loaded.
|
||||
*/
|
||||
final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
|
||||
|
||||
final override LoadOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a memory result containing a copy of its register operand.
|
||||
*/
|
||||
class StoreInstruction extends CopyInstruction {
|
||||
StoreInstruction() { getOpcode() instanceof Opcode::Store }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the address of the location to which the value will be stored.
|
||||
*/
|
||||
final AddressOperand getDestinationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the address of the location to which the value will
|
||||
* be stored, if an exact definition is available.
|
||||
*/
|
||||
final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() }
|
||||
|
||||
final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that branches to one of two successor instructions based on the value of a Boolean
|
||||
* operand.
|
||||
*/
|
||||
class ConditionalBranchInstruction extends Instruction {
|
||||
ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch }
|
||||
|
||||
/**
|
||||
* Gets the operand that provides the Boolean condition controlling the branch.
|
||||
*/
|
||||
final ConditionOperand getConditionOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the Boolean condition controlling the branch.
|
||||
*/
|
||||
final Instruction getCondition() { result = getConditionOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the instruction to which control will flow if the condition is true.
|
||||
*/
|
||||
final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) }
|
||||
|
||||
/**
|
||||
* Gets the instruction to which control will flow if the condition is false.
|
||||
*/
|
||||
final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the exit point of a function.
|
||||
*
|
||||
* Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns
|
||||
* nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns
|
||||
* (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no
|
||||
* successors.
|
||||
*/
|
||||
class ExitFunctionInstruction extends Instruction {
|
||||
ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value.
|
||||
*/
|
||||
class ConstantInstruction extends ConstantValueInstruction {
|
||||
ConstantInstruction() { getOpcode() instanceof Opcode::Constant }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of integer or Boolean type.
|
||||
*/
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
@@ -618,27 +852,53 @@ class IntegerConstantInstruction extends ConstantInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of floating-point type.
|
||||
*/
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is the address of a string literal.
|
||||
*/
|
||||
class StringConstantInstruction extends VariableInstruction {
|
||||
override IRStringLiteral var;
|
||||
|
||||
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
|
||||
|
||||
/**
|
||||
* Gets the string literal whose address is returned by this instruction.
|
||||
*/
|
||||
final Language::StringLiteral getValue() { result = var.getLiteral() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed from two operands.
|
||||
*/
|
||||
class BinaryInstruction extends Instruction {
|
||||
BinaryInstruction() { getOpcode() instanceof BinaryOpcode }
|
||||
|
||||
/**
|
||||
* Gets the left operand of this binary instruction.
|
||||
*/
|
||||
final LeftOperand getLeftOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the right operand of this binary instruction.
|
||||
*/
|
||||
final RightOperand getRightOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left operand of this binary
|
||||
* instruction.
|
||||
*/
|
||||
final Instruction getLeft() { result = getLeftOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the right operand of this binary
|
||||
* instruction.
|
||||
*/
|
||||
final Instruction getRight() { result = getRightOperand().getDef() }
|
||||
|
||||
/**
|
||||
@@ -651,66 +911,161 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the result of an arithmetic operation.
|
||||
*/
|
||||
class ArithmeticInstruction extends Instruction {
|
||||
ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs an arithmetic operation on two numeric operands.
|
||||
*/
|
||||
class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed by performing an arithmetic operation on a single
|
||||
* numeric operand.
|
||||
*/
|
||||
class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that computes the sum of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is
|
||||
* performed according to IEEE-754.
|
||||
*/
|
||||
class AddInstruction extends BinaryArithmeticInstruction {
|
||||
AddInstruction() { getOpcode() instanceof Opcode::Add }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the difference of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed
|
||||
* according to IEEE-754.
|
||||
*/
|
||||
class SubInstruction extends BinaryArithmeticInstruction {
|
||||
SubInstruction() { getOpcode() instanceof Opcode::Sub }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the product of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is
|
||||
* performed according to IEEE-754.
|
||||
*/
|
||||
class MulInstruction extends BinaryArithmeticInstruction {
|
||||
MulInstruction() { getOpcode() instanceof Opcode::Mul }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the quotient of two numeric operands.
|
||||
*
|
||||
* Both operands must have the same numeric type, which will also be the result type. The result of
|
||||
* division by zero or integer overflow is undefined. Floating-point division is performed according
|
||||
* to IEEE-754.
|
||||
*/
|
||||
class DivInstruction extends BinaryArithmeticInstruction {
|
||||
DivInstruction() { getOpcode() instanceof Opcode::Div }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the remainder of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type. The result of
|
||||
* division by zero or integer overflow is undefined.
|
||||
*/
|
||||
class RemInstruction extends BinaryArithmeticInstruction {
|
||||
RemInstruction() { getOpcode() instanceof Opcode::Rem }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that negates a single numeric operand.
|
||||
*
|
||||
* The operand must have a numeric type, which will also be the result type. The result of integer
|
||||
* negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation
|
||||
* is performed according to IEEE-754.
|
||||
*/
|
||||
class NegateInstruction extends UnaryArithmeticInstruction {
|
||||
NegateInstruction() { getOpcode() instanceof Opcode::Negate }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the result of a bitwise operation.
|
||||
*/
|
||||
class BitwiseInstruction extends Instruction {
|
||||
BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs a bitwise operation on two integer operands.
|
||||
*/
|
||||
class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that performs a bitwise operation on a single integer operand.
|
||||
*/
|
||||
class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { }
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "and" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitAndInstruction extends BinaryBitwiseInstruction {
|
||||
BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "or" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitOrInstruction extends BinaryBitwiseInstruction {
|
||||
BitOrInstruction() { getOpcode() instanceof Opcode::BitOr }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise "xor" of two integer operands.
|
||||
*
|
||||
* Both operands must have the same integer type, which will also be the result type.
|
||||
*/
|
||||
class BitXorInstruction extends BinaryBitwiseInstruction {
|
||||
BitXorInstruction() { getOpcode() instanceof Opcode::BitXor }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that shifts its left operand to the left by the number of bits specified by its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have an integer type. The result has the same type as the left operand. The
|
||||
* rightmost bits are zero-filled.
|
||||
*/
|
||||
class ShiftLeftInstruction extends BinaryBitwiseInstruction {
|
||||
ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that shifts its left operand to the right by the number of bits specified by its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have an integer type. The result has the same type as the left operand. If the
|
||||
* left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand
|
||||
* has a signed integer type, the leftmost bits are filled by duplicating the most significant bit
|
||||
* of the left operand.
|
||||
*/
|
||||
class ShiftRightInstruction extends BinaryBitwiseInstruction {
|
||||
ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that performs a binary arithmetic operation involving at least one pointer
|
||||
* operand.
|
||||
*/
|
||||
class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
int elementSize;
|
||||
|
||||
@@ -721,25 +1076,64 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
final override string getImmediateString() { result = elementSize.toString() }
|
||||
|
||||
/**
|
||||
* Gets the size of the elements pointed to by the pointer operands, in bytes.
|
||||
*
|
||||
* When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer
|
||||
* offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the
|
||||
* element size to compute the actual number of bytes added to or subtracted from the pointer
|
||||
* address. When computing the integer difference between two pointers (`PointerDiffInstruction`),
|
||||
* the result is computed by computing the difference between the two pointer byte addresses, then
|
||||
* dividing that byte count by the element size.
|
||||
*/
|
||||
final int getElementSize() { result = elementSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that adds or subtracts an integer offset from a pointer.
|
||||
*/
|
||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||
PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that adds an integer offset to a pointer.
|
||||
*
|
||||
* The result is the byte address computed by adding the value of the right (integer) operand,
|
||||
* multiplied by the element size, to the value of the left (pointer) operand. The result of pointer
|
||||
* overflow is undefined.
|
||||
*/
|
||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||
PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that subtracts an integer offset from a pointer.
|
||||
*
|
||||
* The result is the byte address computed by subtracting the value of the right (integer) operand,
|
||||
* multiplied by the element size, from the value of the left (pointer) operand. The result of
|
||||
* pointer underflow is undefined.
|
||||
*/
|
||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||
PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the difference between two pointers.
|
||||
*
|
||||
* Both operands must have the same pointer type. The result must have an integer type whose size is
|
||||
* the same as that of the pointer operands. The result is computed by subtracting the byte address
|
||||
* in the right operand from the byte address in the left operand, and dividing by the element size.
|
||||
* If the difference in byte addresses is not divisible by the element size, the result is
|
||||
* undefined.
|
||||
*/
|
||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||
PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is computed from a single operand.
|
||||
*/
|
||||
class UnaryInstruction extends Instruction {
|
||||
UnaryInstruction() { getOpcode() instanceof UnaryOpcode }
|
||||
|
||||
@@ -748,17 +1142,44 @@ class UnaryInstruction extends Instruction {
|
||||
final Instruction getUnary() { result = getUnaryOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the value of its operand to a value of a different type.
|
||||
*/
|
||||
class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the address of a polymorphic object to the address of a different
|
||||
* subobject of the same polymorphic object, returning a null address if the dynamic type of the
|
||||
* object is not compatible with the result type.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*
|
||||
* This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or
|
||||
* `as` expression.
|
||||
*/
|
||||
class CheckedConvertOrNullInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts between two addresses
|
||||
* related by inheritance.
|
||||
* An instruction that converts the address of a polymorphic object to the address of a different
|
||||
* subobject of the same polymorphic object, throwing an exception if the dynamic type of the object
|
||||
* is not compatible with the result type.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*
|
||||
* This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast
|
||||
* expression.
|
||||
*/
|
||||
class CheckedConvertOrThrowInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that converts the address of an object to the address of a different subobject of
|
||||
* the same object, without any type checking at runtime.
|
||||
*/
|
||||
class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Language::Class baseClass;
|
||||
@@ -795,59 +1216,91 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a base class.
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a direct non-virtual base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a direct
|
||||
* non-virtual base class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction {
|
||||
ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a virtual base class.
|
||||
* An instruction that converts from the address of a derived class to the address of a virtual base
|
||||
* class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction {
|
||||
ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a base class
|
||||
* to the address of a direct non-virtual derived class.
|
||||
* An instruction that converts from the address of a base class to the address of a direct
|
||||
* non-virtual derived class.
|
||||
*
|
||||
* If the operand holds a null address, the result is a null address.
|
||||
*/
|
||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the bitwise complement of its operand.
|
||||
*
|
||||
* The operand must have an integer type, which will also be the result type.
|
||||
*/
|
||||
class BitComplementInstruction extends UnaryBitwiseInstruction {
|
||||
BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that computes the logical complement of its operand.
|
||||
*
|
||||
* The operand must have a Boolean type, which will also be the result type.
|
||||
*/
|
||||
class LogicalNotInstruction extends UnaryInstruction {
|
||||
LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that compares two numeric operands.
|
||||
*/
|
||||
class CompareInstruction extends BinaryInstruction {
|
||||
CompareInstruction() { getOpcode() instanceof CompareOpcode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its operands are equal.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if `left == right`, and `false` if `left != right` or the two operands are
|
||||
* unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareEQInstruction extends CompareInstruction {
|
||||
CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its operands are not equal.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if `left != right` or if the two operands are unordered, and `false` if
|
||||
* `left == right`. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareNEInstruction extends CompareInstruction {
|
||||
CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
* An instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() { getOpcode() instanceof RelationalOpcode }
|
||||
@@ -874,6 +1327,13 @@ class RelationalInstruction extends CompareInstruction {
|
||||
predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is less than its right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT }
|
||||
|
||||
@@ -884,6 +1344,13 @@ class CompareLTInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is greater than its right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT }
|
||||
|
||||
@@ -894,6 +1361,14 @@ class CompareGTInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is less than or equal to its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE }
|
||||
|
||||
@@ -904,6 +1379,14 @@ class CompareLEInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that returns a `true` result if its left operand is greater than or equal to its
|
||||
* right operand.
|
||||
*
|
||||
* Both operands must have the same numeric or address type. The result must have a Boolean type.
|
||||
* The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands
|
||||
* are unordered. Floating-point comparison is performed according to IEEE-754.
|
||||
*/
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE }
|
||||
|
||||
@@ -914,15 +1397,32 @@ class CompareGEInstruction extends RelationalInstruction {
|
||||
override predicate isStrict() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that branches to one of multiple successor instructions based on the value of an
|
||||
* integer operand.
|
||||
*
|
||||
* This instruction will have zero or more successors whose edge kind is `CaseEdge`, each
|
||||
* representing the branch that will be taken if the controlling expression is within the range
|
||||
* specified for that case edge. The range of a case edge must be disjoint from the range of each
|
||||
* other case edge.
|
||||
*
|
||||
* The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`,
|
||||
* representing the branch that will be taken if the controlling expression is not within the range
|
||||
* of any case edge.
|
||||
*/
|
||||
class SwitchInstruction extends Instruction {
|
||||
SwitchInstruction() { getOpcode() instanceof Opcode::Switch }
|
||||
|
||||
/** Gets the operand that provides the integer value controlling the switch. */
|
||||
final ConditionOperand getExpressionOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the instruction whose result provides the integer value controlling the switch. */
|
||||
final Instruction getExpression() { result = getExpressionOperand().getDef() }
|
||||
|
||||
/** Gets the successor instructions along the case edges of the switch. */
|
||||
final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) }
|
||||
|
||||
/** Gets the successor instruction along the default edge of the switch, if any. */
|
||||
final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) }
|
||||
}
|
||||
|
||||
@@ -998,6 +1498,9 @@ class CallInstruction extends Instruction {
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode }
|
||||
|
||||
/**
|
||||
* Gets the instruction whose execution causes this side effect.
|
||||
*/
|
||||
final Instruction getPrimaryInstruction() {
|
||||
result = Construction::getPrimaryInstructionForSideEffect(this)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user