C# IR: Add support for multiple decls and updates

Added support for multiple declarations and updates in a for stmt.
Added test cases and updated the expected output.
This commit is contained in:
AndreiDiaconu1 2019-09-02 15:46:09 +01:00
Родитель ad4715fd52
Коммит d9f3c14c9c
10 изменённых файлов: 523 добавлений и 251 удалений

Просмотреть файл

@ -179,7 +179,7 @@ private module Cached {
exists(TranslatedElement bodyOrUpdate |
bodyOrUpdate = s.getBody()
or
bodyOrUpdate = s.getUpdate()
bodyOrUpdate = s.getUpdate(_)
|
inLoop = bodyOrUpdate.getAChild*()
) and

Просмотреть файл

@ -10,7 +10,7 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* The IR translation of a call to a function. The function can be a normal function
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
* (eg. `MethodCall`) or a constructor call (eg. `ObjectCreation`). Notice that the
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
* which can be attached to either a statement or an expression).
*/

Просмотреть файл

@ -651,43 +651,70 @@ class TranslatedForStmt extends TranslatedLoop {
override ForStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = this.getDeclAndInit()
initializerIndices(id) and result = this.getDeclAndInit(id)
or
id = 1 and result = this.getCondition()
updateIndices(id) and result = this.getUpdate(id - initializersNo())
or
id = 2 and result = this.getUpdate()
id = initializersNo() + updatesNo() and result = this.getCondition()
or
id = 3 and result = this.getBody()
id = initializersNo() + updatesNo() + 1 and result = this.getBody()
}
private TranslatedLocalDeclaration getDeclAndInit() {
result = getTranslatedLocalDeclaration(stmt.getAnInitializer())
private TranslatedLocalDeclaration getDeclAndInit(int index) {
result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
}
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
TranslatedExpr getUpdate() { result = getTranslatedExpr(stmt.getAnUpdate()) }
TranslatedExpr getUpdate(int index) { result = getTranslatedExpr(stmt.getUpdate(index)) }
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
private int initializersNo() { result = count(stmt.getAnInitializer()) }
private int updatesNo() { result = count(stmt.getAnUpdate()) }
private predicate initializerIndices(int index) { index in [0 .. initializersNo() - 1] }
private predicate updateIndices(int index) {
index in [initializersNo() .. initializersNo() + updatesNo() - 1]
}
override Instruction getFirstInstruction() {
if this.hasInitialization()
then result = this.getDeclAndInit().getFirstInstruction()
then result = this.getDeclAndInit(0).getFirstInstruction()
else result = this.getFirstConditionInstruction()
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getDeclAndInit() and
exists(int index |
this.hasInitialization() and
child = this.getDeclAndInit(index) and
index < initializersNo() - 1 and
result = this.getDeclAndInit(index + 1).getFirstInstruction()
)
or
this.hasInitialization() and
child = this.getDeclAndInit(initializersNo() - 1) and
result = this.getFirstConditionInstruction()
or
(
child = this.getBody() and
if this.hasUpdate()
then result = this.getUpdate().getFirstInstruction()
then result = this.getUpdate(0).getFirstInstruction()
else result = this.getFirstConditionInstruction()
)
or
child = this.getUpdate() and result = this.getFirstConditionInstruction()
exists(int index |
this.hasUpdate() and
child = this.getUpdate(index) and
index < updatesNo() - 1 and
result = this.getUpdate(index + 1).getFirstInstruction()
)
or
this.hasUpdate() and
child = this.getUpdate(updatesNo() - 1) and
result = this.getFirstConditionInstruction()
}
}

Просмотреть файл

@ -3,7 +3,6 @@
* (both AST generated and compiler generated).
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
@ -18,129 +17,112 @@ abstract class TranslatedCallBase extends TranslatedElement {
override final TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation.
// Note: some calls do need qualifiers, though instructions for them have already
// been generated; eg. a constructor does not need to generate a qualifier,
// been generated; eg. a constructor does not need to generate a qualifier,
// though the `this` argument exists and is the result of the instruction
// that allocated the new object. For those calls, `getQualifier()` should
// be void.
id = -1 and result = getQualifier() or
id = -1 and result = getQualifier()
or
result = getArgument(id)
}
override final Instruction getFirstInstruction() {
if exists(getQualifier()) then
result = getQualifier().getFirstInstruction()
else
result = getInstruction(CallTargetTag())
final override Instruction getFirstInstruction() {
if exists(getQualifier())
then result = getQualifier().getFirstInstruction()
else result = getInstruction(CallTargetTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
or
hasSideEffect() and
tag = CallSideEffectTag() and
(
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
(
if hasWriteSideEffect() then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
)
else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
) or
(
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// Since the DB does not have a function type,
// we just use the UnknownType
resultType instanceof Language::UnknownType and
isLValue = true
)
if hasWriteSideEffect()
then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
) else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
or
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// Since the DB does not have a function type,
// we just use the UnknownType
resultType instanceof Language::UnknownType and
isLValue = true
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = getQualifier() and
result = getInstruction(CallTargetTag())
) or
child = getQualifier() and
result = getInstruction(CallTargetTag())
or
exists(int argIndex |
child = getArgument(argIndex) and
if exists(getArgument(argIndex + 1)) then
result = getArgument(argIndex + 1).getFirstInstruction()
else
result = getInstruction(CallTag())
if exists(getArgument(argIndex + 1))
then result = getArgument(argIndex + 1).getFirstInstruction()
else result = getInstruction(CallTag())
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
(
tag = CallTag() and
if hasSideEffect() then
result = getInstruction(CallSideEffectTag())
else
result = getParent().getChildSuccessor(this)
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
if hasSideEffect()
then result = getInstruction(CallSideEffectTag())
else result = getParent().getChildSuccessor(this)
)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
(
tag = CallTag() and
(
(
operandTag instanceof CallTargetOperandTag and
result = getInstruction(CallTargetTag())
) or
(
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
) or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
)
) or
(
tag = CallSideEffectTag() and
or
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
or
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
)
}
override final Type getInstructionOperandType(InstructionTag tag,
TypedOperandTag operandTag) {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = CallTag() and
(
operandTag instanceof CallTargetOperandTag and
result = getInstruction(CallTargetTag())
or
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
)
or
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
}
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result instanceof Language::UnknownType
}
Instruction getResult() {
result = getInstruction(CallTag())
}
Instruction getResult() { result = getInstruction(CallTag()) }
/**
* Gets the result type of the call.
@ -152,16 +134,14 @@ abstract class TranslatedCallBase extends TranslatedElement {
* function (of the element this call is attached to).
*/
abstract Instruction getUnmodeledDefinitionInstruction();
/**
* Holds if the call has a `this` argument.
*/
predicate hasQualifier() {
exists(getQualifier())
}
predicate hasQualifier() { exists(getQualifier()) }
/**
* Gets the expr for the qualifier of the call.
* Gets the expr for the qualifier of the call.
*/
abstract TranslatedExprBase getQualifier();
@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
* argument. Otherwise, returns the call instruction.
*/
final Instruction getFirstArgumentOrCallInstruction() {
if hasArguments() then
result = getArgument(0).getFirstInstruction()
else
result = getInstruction(CallTag())
if hasArguments()
then result = getArgument(0).getFirstInstruction()
else result = getInstruction(CallTag())
}
/**
@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
exists(getArgument(0))
}
predicate hasReadSideEffect() {
any()
}
predicate hasReadSideEffect() { any() }
predicate hasWriteSideEffect() {
any()
}
predicate hasWriteSideEffect() { any() }
private predicate hasSideEffect() {
hasReadSideEffect() or hasWriteSideEffect()
}
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
}
}
}

Просмотреть файл

@ -11,7 +11,6 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* Represents the context of the condition, ie. provides
* information about the instruction that follows a conditional branch.
@ -23,30 +22,25 @@ abstract class ConditionContext extends TranslatedElement {
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ConditionBase extends TranslatedElement {
final ConditionContext getConditionContext() {
result = getParent()
}
final ConditionContext getConditionContext() { result = getParent() }
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ValueConditionBase extends ConditionBase {
override TranslatedElement getChild(int id) {
id = 0 and result = getValueExpr()
}
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
override Instruction getFirstInstruction() {
result = getValueExpr().getFirstInstruction()
}
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and
@ -58,23 +52,18 @@ abstract class ValueConditionBase extends ConditionBase {
result = getInstruction(ValueConditionConditionalBranchTag())
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
(
kind instanceof TrueEdge and
result = getConditionContext().getChildTrueSuccessor(this)
) or
(
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
kind instanceof TrueEdge and
result = getConditionContext().getChildTrueSuccessor(this)
or
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and
result = valueExprResult()
@ -84,9 +73,9 @@ abstract class ValueConditionBase extends ConditionBase {
* Gets the instruction that represents the result of the value expression.
*/
abstract Instruction valueExprResult();
/**
/**
* Gets the `TranslatedElements that represents the value expression.
*/
abstract TranslatedElement getValueExpr();
}
}

Просмотреть файл

@ -1,5 +1,5 @@
/**
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
* generated declarations and the compiler generated ones (captures the common patterns).
*/
@ -13,55 +13,47 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class LocalVariableDeclarationBase extends TranslatedElement {
override TranslatedElement getChild(int id) {
id = 0 and result = getInitialization()
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
override Instruction getFirstInstruction() { result = getVarAddress() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVarType() and
isLValue = true
or
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVarType() and
isLValue = false
}
override Instruction getFirstInstruction() {
result = getVarAddress()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
(
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVarType() and
isLValue = true
) or
(
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVarType() and
isLValue = false
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
(
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
if hasUninitializedInstruction() then
result = getInstruction(InitializerStoreTag())
if hasUninitializedInstruction()
then result = getInstruction(InitializerStoreTag())
else
if isInitializedByElement() then
if isInitializedByElement()
then
// initialization is done by an element
result = getParent().getChildSuccessor(this)
else
result = getInitialization().getFirstInstruction()
) or
else result = getInitialization().getFirstInstruction()
)
or
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
result = getInitialization().getFirstInstruction() or
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
)
result = getInitialization().getFirstInstruction()
or
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
)
}
@ -75,11 +67,11 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
operandTag instanceof AddressOperandTag and
result = getVarAddress()
}
/**
* Holds if the declaration should have an `Uninitialized` instruction.
* Compiler generated elements should override this predicate and
* make it empty, since we always initialize the vars declared during the
* make it empty, since we always initialize the vars declared during the
* desugaring process.
*/
predicate hasUninitializedInstruction() {
@ -89,29 +81,27 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
) and
not isInitializedByElement()
}
Instruction getVarAddress() {
result = getInstruction(InitializerVariableAddressTag())
}
Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
/**
* Gets the declared variable. For compiler generated elements, this
* Gets the declared variable. For compiler generated elements, this
* should be empty (since we treat temp vars differently).
*/
abstract LocalVariable getDeclVar();
/**
* Gets the type of the declared variable.
*/
abstract Type getVarType();
/**
* Gets the initialization, if there is one.
* For compiler generated elements we don't treat the initialization
* as a different step, but do it during the declaration.
*/
abstract TranslatedElement getInitialization();
/**
* Holds if a declaration is not explicitly initialized,
* but will be implicitly initialized by an element.

Просмотреть файл

@ -11,4 +11,4 @@ abstract class TranslatedExprBase extends TranslatedElement {
* Gets the instruction that produces the result of the expression.
*/
abstract Instruction getResult();
}
}

Просмотреть файл

@ -0,0 +1,251 @@
import csharp
private int getMaxCallArgIndex() {
result = max(int argIndex |
exists(Call call | exists(call.getArgument(argIndex)))
or
// Quick fix so that generated calls (`Invoke` etc) will have the
// correct number of parameters; it is an overestimation,
// since we don't care about all the callables, so it
// should be restricted more
exists(Callable callable | callable.getNumberOfParameters() = argIndex)
)
}
private newtype TOperandTag =
TAddressOperand() or
TBufferSizeOperand() or
TSideEffectOperand() or
TLoadOperand() or
TStoreValueOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) { argIndex in [0 .. getMaxCallArgIndex()] } or
TChiTotalOperand() or
TChiPartialOperand()
/**
* 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 = "" }
}
/**
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
*/
abstract class MemoryOperandTag extends OperandTag { }
/**
* An operand that consumes a register (non-memory) result.
*/
abstract class RegisterOperandTag extends OperandTag { }
/**
* A memory operand whose type may be different from the result type of its definition instruction.
*/
abstract class TypedOperandTag extends MemoryOperandTag { }
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
*/
class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
final override string toString() { result = "Address" }
final override int getSortOrder() { result = 0 }
final override string getLabel() { result = "&:" }
}
AddressOperandTag addressOperand() { result = TAddressOperand() }
/**
* The buffer size operand of an instruction that represents a read or write of
* a buffer.
*/
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
final override string toString() { result = "BufferSize" }
final override int getSortOrder() { result = 1 }
}
/**
* The operand representing the read side effect of a `SideEffectInstruction`.
*/
class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
final override string toString() { result = "SideEffect" }
final override int getSortOrder() { result = 2 }
}
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
/**
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
* `ReturnValue`, `ThrowValue`).
*/
class LoadOperandTag extends TypedOperandTag, TLoadOperand {
final override string toString() { result = "Load" }
final override int getSortOrder() { result = 3 }
}
LoadOperandTag loadOperand() { result = TLoadOperand() }
/**
* The source value operand of a `Store` instruction.
*/
class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
final override string toString() { result = "StoreValue" }
final override int getSortOrder() { result = 4 }
}
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
*/
class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
final override string toString() { result = "Unary" }
final override int getSortOrder() { result = 5 }
}
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
final override string toString() { result = "Left" }
final override int getSortOrder() { result = 6 }
}
LeftOperandTag leftOperand() { result = TLeftOperand() }
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperandTag extends RegisterOperandTag, TRightOperand {
final override string toString() { result = "Right" }
final override int getSortOrder() { result = 7 }
}
RightOperandTag rightOperand() { result = TRightOperand() }
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
final override string toString() { result = "Condition" }
final override int getSortOrder() { result = 8 }
}
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand {
final override string toString() { result = "UnmodeledUse" }
final override int getSortOrder() { result = 9 }
}
UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() }
/**
* The operand representing the target function of an `Call` instruction.
*/
class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
final override string toString() { result = "CallTarget" }
final override int getSortOrder() { result = 10 }
final override string getLabel() { result = "func:" }
}
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperandTag extends RegisterOperandTag { }
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
ThisArgumentOperandTag() { this = TThisArgumentOperand() }
final override string toString() { result = "Arg(this)" }
final override int getSortOrder() { result = 11 }
final override string getLabel() { result = "this:" }
}
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperandTag() { this = TPositionalArgumentOperand(argIndex) }
final override string toString() { result = "Arg(" + argIndex + ")" }
final override int getSortOrder() { result = 12 + argIndex }
final override string getLabel() { result = argIndex.toString() + ":" }
final int getArgIndex() { result = argIndex }
}
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
final override string toString() { result = "ChiTotal" }
final override int getSortOrder() { result = 13 }
final override string getLabel() { result = "total:" }
}
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
final override string toString() { result = "ChiPartial" }
final override int getSortOrder() { result = 14 }
final override string getLabel() { result = "partial:" }
}
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }

Просмотреть файл

@ -1048,6 +1048,9 @@ stmts.cs:
# 71| r0_6(glval<Int32>) = VariableAddress[i] :
# 71| r0_7(Int32) = Constant[0] :
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7
# 71| r0_9(glval<Int32>) = VariableAddress[j] :
# 71| r0_10(Int32) = Constant[10] :
# 71| mu0_11(Int32) = Store : &:r0_9, r0_10
#-----| Goto -> Block 2
# 68| Block 1
@ -1058,53 +1061,86 @@ stmts.cs:
# 71| Block 2
# 71| r2_0(glval<Int32>) = VariableAddress[i] :
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 71| r2_2(Int32) = Constant[10] :
# 71| r2_3(Boolean) = CompareLE : r2_1, r2_2
# 71| v2_4(Void) = ConditionalBranch : r2_3
#-----| False -> Block 1
# 71| r2_2(glval<Int32>) = VariableAddress[j] :
# 71| r2_3(Int32) = Load : &:r2_2, ~mu0_2
# 71| r2_4(Boolean) = CompareLT : r2_1, r2_3
# 71| v2_5(Void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 73| Block 3
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
# 73| r3_2(Int32) = Constant[1] :
# 73| r3_3(Int32) = Sub : r3_1, r3_2
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
# 71| r3_8(Int32) = Constant[1] :
# 71| r3_9(Int32) = Add : r3_7, r3_8
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
# 73| r3_2(Int32) = Constant[1] :
# 73| r3_3(Int32) = Sub : r3_1, r3_2
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
# 71| r3_8(Int32) = Constant[1] :
# 71| r3_9(Int32) = Add : r3_7, r3_8
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
# 71| r3_11(glval<Int32>) = VariableAddress[j] :
# 71| r3_12(Int32) = Load : &:r3_11, ~mu0_2
# 71| r3_13(Int32) = Constant[1] :
# 71| r3_14(Int32) = Sub : r3_12, r3_13
# 71| mu3_15(Int32) = Store : &:r3_11, r3_14
#-----| Goto (back edge) -> Block 2
# 77| System.Void test_stmts.doWhile()
# 77| Block 0
# 77| v0_0(Void) = EnterFunction :
# 77| mu0_1(null) = AliasedDefinition :
# 77| mu0_2(null) = UnmodeledDefinition :
# 79| r0_3(glval<Int32>) = VariableAddress[x] :
# 79| r0_4(Int32) = Constant[0] :
# 79| mu0_5(Int32) = Store : &:r0_3, r0_4
# 76| Block 4
# 76| r4_0(glval<Int32>) = VariableAddress[a] :
# 76| r4_1(Int32) = Constant[0] :
# 76| mu4_2(Int32) = Store : &:r4_0, r4_1
# 76| r4_3(glval<Int32>) = VariableAddress[b] :
# 76| r4_4(Int32) = Constant[10] :
# 76| mu4_5(Int32) = Store : &:r4_3, r4_4
#-----| Goto -> Block 5
# 77| Block 5
# 77| r5_0(glval<Int32>) = VariableAddress[a] :
# 77| r5_1(Int32) = Load : &:r5_0, ~mu0_2
# 77| r5_2(glval<Int32>) = VariableAddress[b] :
# 77| r5_3(Int32) = Load : &:r5_2, ~mu0_2
# 77| r5_4(Boolean) = CompareLT : r5_1, r5_3
# 77| v5_5(Void) = ConditionalBranch : r5_4
#-----| False -> Block 1
#-----| True -> Block 6
# 79| Block 6
# 79| r6_0(glval<Int32>) = VariableAddress[a] :
# 79| r6_1(Int32) = Load : &:r6_0, ~mu0_2
# 79| r6_2(Int32) = Constant[1] :
# 79| r6_3(Int32) = Add : r6_1, r6_2
# 79| mu6_4(Int32) = Store : &:r6_0, r6_3
#-----| Goto (back edge) -> Block 5
# 83| System.Void test_stmts.doWhile()
# 83| Block 0
# 83| v0_0(Void) = EnterFunction :
# 83| mu0_1(null) = AliasedDefinition :
# 83| mu0_2(null) = UnmodeledDefinition :
# 85| r0_3(glval<Int32>) = VariableAddress[x] :
# 85| r0_4(Int32) = Constant[0] :
# 85| mu0_5(Int32) = Store : &:r0_3, r0_4
#-----| Goto -> Block 2
# 77| Block 1
# 77| v1_0(Void) = ReturnVoid :
# 77| v1_1(Void) = UnmodeledUse : mu*
# 77| v1_2(Void) = ExitFunction :
# 83| Block 1
# 83| v1_0(Void) = ReturnVoid :
# 83| v1_1(Void) = UnmodeledUse : mu*
# 83| v1_2(Void) = ExitFunction :
# 82| Block 2
# 82| r2_0(glval<Int32>) = VariableAddress[x] :
# 82| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 82| r2_2(Int32) = Constant[1] :
# 82| r2_3(Int32) = Add : r2_1, r2_2
# 82| r2_4(glval<Int32>) = VariableAddress[x] :
# 82| mu2_5(Int32) = Store : &:r2_4, r2_3
# 84| r2_6(glval<Int32>) = VariableAddress[x] :
# 84| r2_7(Int32) = Load : &:r2_6, ~mu0_2
# 84| r2_8(Int32) = Constant[10] :
# 84| r2_9(Boolean) = CompareLT : r2_7, r2_8
# 84| v2_10(Void) = ConditionalBranch : r2_9
# 88| Block 2
# 88| r2_0(glval<Int32>) = VariableAddress[x] :
# 88| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 88| r2_2(Int32) = Constant[1] :
# 88| r2_3(Int32) = Add : r2_1, r2_2
# 88| r2_4(glval<Int32>) = VariableAddress[x] :
# 88| mu2_5(Int32) = Store : &:r2_4, r2_3
# 90| r2_6(glval<Int32>) = VariableAddress[x] :
# 90| r2_7(Int32) = Load : &:r2_6, ~mu0_2
# 90| r2_8(Int32) = Constant[10] :
# 90| r2_9(Boolean) = CompareLT : r2_7, r2_8
# 90| v2_10(Void) = ConditionalBranch : r2_9
#-----| False -> Block 1
#-----| True (back edge) -> Block 2

Просмотреть файл

@ -68,9 +68,15 @@ public class test_stmts
public static void forStmt()
{
int x = 0;
for (int i = 0; i <= 10; i++)
for (int i = 0, j = 10; i < j; i++, j--)
{
x = x - 1;
}
int a = 0, b = 10;
for (; a < b; )
{
x = x - 1;
a++;
}
}