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 | exists(TranslatedElement bodyOrUpdate |
bodyOrUpdate = s.getBody() bodyOrUpdate = s.getBody()
or or
bodyOrUpdate = s.getUpdate() bodyOrUpdate = s.getUpdate(_)
| |
inLoop = bodyOrUpdate.getAChild*() inLoop = bodyOrUpdate.getAChild*()
) and ) 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 * 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, * AST generated translated calls are tied to an expression (unlike compiler generated ones,
* which can be attached to either a statement or an expression). * which can be attached to either a statement or an expression).
*/ */

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

@ -651,43 +651,70 @@ class TranslatedForStmt extends TranslatedLoop {
override ForStmt stmt; override ForStmt stmt;
override TranslatedElement getChild(int id) { override TranslatedElement getChild(int id) {
id = 0 and result = this.getDeclAndInit() initializerIndices(id) and result = this.getDeclAndInit(id)
or or
id = 1 and result = this.getCondition() updateIndices(id) and result = this.getUpdate(id - initializersNo())
or or
id = 2 and result = this.getUpdate() id = initializersNo() + updatesNo() and result = this.getCondition()
or or
id = 3 and result = this.getBody() id = initializersNo() + updatesNo() + 1 and result = this.getBody()
} }
private TranslatedLocalDeclaration getDeclAndInit() { private TranslatedLocalDeclaration getDeclAndInit(int index) {
result = getTranslatedLocalDeclaration(stmt.getAnInitializer()) result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
} }
private predicate hasInitialization() { exists(stmt.getAnInitializer()) } 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 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() { override Instruction getFirstInstruction() {
if this.hasInitialization() if this.hasInitialization()
then result = this.getDeclAndInit().getFirstInstruction() then result = this.getDeclAndInit(0).getFirstInstruction()
else result = this.getFirstConditionInstruction() else result = this.getFirstConditionInstruction()
} }
override Instruction getChildSuccessor(TranslatedElement child) { 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() result = this.getFirstConditionInstruction()
or or
( (
child = this.getBody() and child = this.getBody() and
if this.hasUpdate() if this.hasUpdate()
then result = this.getUpdate().getFirstInstruction() then result = this.getUpdate(0).getFirstInstruction()
else result = this.getFirstConditionInstruction() else result = this.getFirstConditionInstruction()
) )
or 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). * (both AST generated and compiler generated).
*/ */
import csharp import csharp
private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag private import semmle.code.csharp.ir.implementation.internal.OperandTag
@ -18,129 +17,112 @@ abstract class TranslatedCallBase extends TranslatedElement {
override final TranslatedElement getChild(int id) { override final TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation. // We choose the child's id in the order of evaluation.
// Note: some calls do need qualifiers, though instructions for them have already // 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 // though the `this` argument exists and is the result of the instruction
// that allocated the new object. For those calls, `getQualifier()` should // that allocated the new object. For those calls, `getQualifier()` should
// be void. // be void.
id = -1 and result = getQualifier() or id = -1 and result = getQualifier()
or
result = getArgument(id) result = getArgument(id)
} }
override final Instruction getFirstInstruction() { final override Instruction getFirstInstruction() {
if exists(getQualifier()) then if exists(getQualifier())
result = getQualifier().getFirstInstruction() then result = getQualifier().getFirstInstruction()
else else result = getInstruction(CallTargetTag())
result = getInstruction(CallTargetTag())
} }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, override predicate hasInstruction(
Type resultType, boolean isLValue) { 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 if hasWriteSideEffect()
opcode instanceof Opcode::Call and then (
resultType = getCallResultType() and opcode instanceof Opcode::CallSideEffect and
isLValue = false resultType instanceof Language::UnknownType
) or ) else (
( opcode instanceof Opcode::CallReadSideEffect and
hasSideEffect() and resultType instanceof Language::UnknownType
tag = CallSideEffectTag() and )
( ) and
if hasWriteSideEffect() then ( isLValue = false
opcode instanceof Opcode::CallSideEffect and or
resultType instanceof Language::UnknownType tag = CallTargetTag() and
) opcode instanceof Opcode::FunctionAddress and
else ( // Since the DB does not have a function type,
opcode instanceof Opcode::CallReadSideEffect and // we just use the UnknownType
resultType instanceof Language::UnknownType resultType instanceof Language::UnknownType and
) isLValue = true
) 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) { override Instruction getChildSuccessor(TranslatedElement child) {
( child = getQualifier() and
child = getQualifier() and result = getInstruction(CallTargetTag())
result = getInstruction(CallTargetTag()) or
) or
exists(int argIndex | exists(int argIndex |
child = getArgument(argIndex) and child = getArgument(argIndex) and
if exists(getArgument(argIndex + 1)) then if exists(getArgument(argIndex + 1))
result = getArgument(argIndex + 1).getFirstInstruction() then result = getArgument(argIndex + 1).getFirstInstruction()
else else result = getInstruction(CallTag())
result = getInstruction(CallTag())
) )
} }
override Instruction getInstructionSuccessor(InstructionTag tag, override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
EdgeKind kind) {
kind instanceof GotoEdge and kind instanceof GotoEdge and
( (
( (
tag = CallTag() and tag = CallTag() and
if hasSideEffect() then if hasSideEffect()
result = getInstruction(CallSideEffectTag()) then result = getInstruction(CallSideEffectTag())
else else result = getParent().getChildSuccessor(this)
result = getParent().getChildSuccessor(this)
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
) )
) or
}
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 hasSideEffect() and
operandTag instanceof SideEffectOperandTag and tag = CallSideEffectTag() and
result = getUnmodeledDefinitionInstruction() result = getParent().getChildSuccessor(this)
or
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
) )
} }
override final Type getInstructionOperandType(InstructionTag tag, override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
TypedOperandTag 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 tag = CallSideEffectTag() and
hasSideEffect() and hasSideEffect() and
operandTag instanceof SideEffectOperandTag and operandTag instanceof SideEffectOperandTag and
result instanceof Language::UnknownType result instanceof Language::UnknownType
} }
Instruction getResult() { Instruction getResult() { result = getInstruction(CallTag()) }
result = getInstruction(CallTag())
}
/** /**
* Gets the result type of the call. * 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). * function (of the element this call is attached to).
*/ */
abstract Instruction getUnmodeledDefinitionInstruction(); abstract Instruction getUnmodeledDefinitionInstruction();
/** /**
* Holds if the call has a `this` argument. * Holds if the call has a `this` argument.
*/ */
predicate hasQualifier() { predicate hasQualifier() { exists(getQualifier()) }
exists(getQualifier())
}
/** /**
* Gets the expr for the qualifier of the call. * Gets the expr for the qualifier of the call.
*/ */
abstract TranslatedExprBase getQualifier(); abstract TranslatedExprBase getQualifier();
@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
* argument. Otherwise, returns the call instruction. * argument. Otherwise, returns the call instruction.
*/ */
final Instruction getFirstArgumentOrCallInstruction() { final Instruction getFirstArgumentOrCallInstruction() {
if hasArguments() then if hasArguments()
result = getArgument(0).getFirstInstruction() then result = getArgument(0).getFirstInstruction()
else else result = getInstruction(CallTag())
result = getInstruction(CallTag())
} }
/** /**
@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
exists(getArgument(0)) exists(getArgument(0))
} }
predicate hasReadSideEffect() { predicate hasReadSideEffect() { any() }
any()
}
predicate hasWriteSideEffect() { predicate hasWriteSideEffect() { any() }
any()
}
private predicate hasSideEffect() { private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
hasReadSideEffect() or hasWriteSideEffect()
}
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
hasSideEffect() and hasSideEffect() and
tag = CallSideEffectTag() and tag = CallSideEffectTag() and
result = getResult() 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.implementation.raw.internal.TranslatedCondition
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/** /**
* Represents the context of the condition, ie. provides * Represents the context of the condition, ie. provides
* information about the instruction that follows a conditional branch. * 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). * and the compiler generated ones (captures the common patterns).
*/ */
abstract class ConditionBase extends TranslatedElement { abstract class ConditionBase extends TranslatedElement {
final ConditionContext getConditionContext() { final ConditionContext getConditionContext() { result = getParent() }
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). * and the compiler generated ones (captures the common patterns).
*/ */
abstract class ValueConditionBase extends ConditionBase { abstract class ValueConditionBase extends ConditionBase {
override TranslatedElement getChild(int id) { override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
id = 0 and result = getValueExpr()
}
override Instruction getFirstInstruction() { override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
result = getValueExpr().getFirstInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, override predicate hasInstruction(
Type resultType, boolean isLValue) { Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = ValueConditionConditionalBranchTag() and tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and resultType instanceof VoidType and
@ -58,23 +52,18 @@ abstract class ValueConditionBase extends ConditionBase {
result = getInstruction(ValueConditionConditionalBranchTag()) result = getInstruction(ValueConditionConditionalBranchTag())
} }
override Instruction getInstructionSuccessor(InstructionTag tag, override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and tag = ValueConditionConditionalBranchTag() and
( (
( kind instanceof TrueEdge and
kind instanceof TrueEdge and result = getConditionContext().getChildTrueSuccessor(this)
result = getConditionContext().getChildTrueSuccessor(this) or
) or kind instanceof FalseEdge and
( result = getConditionContext().getChildFalseSuccessor(this)
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
) )
} }
override Instruction getInstructionOperand(InstructionTag tag, override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and operandTag instanceof ConditionOperandTag and
result = valueExprResult() result = valueExprResult()
@ -84,9 +73,9 @@ abstract class ValueConditionBase extends ConditionBase {
* Gets the instruction that represents the result of the value expression. * Gets the instruction that represents the result of the value expression.
*/ */
abstract Instruction valueExprResult(); abstract Instruction valueExprResult();
/** /**
* Gets the `TranslatedElements that represents the value expression. * Gets the `TranslatedElements that represents the value expression.
*/ */
abstract TranslatedElement getValueExpr(); 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). * 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.implementation.raw.internal.TranslatedInitialization
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class LocalVariableDeclarationBase extends TranslatedElement { abstract class LocalVariableDeclarationBase extends TranslatedElement {
override TranslatedElement getChild(int id) { override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
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() { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
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) {
( (
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and kind instanceof GotoEdge and
if hasUninitializedInstruction() then if hasUninitializedInstruction()
result = getInstruction(InitializerStoreTag()) then result = getInstruction(InitializerStoreTag())
else else
if isInitializedByElement() then if isInitializedByElement()
then
// initialization is done by an element // initialization is done by an element
result = getParent().getChildSuccessor(this) result = getParent().getChildSuccessor(this)
else else result = getInitialization().getFirstInstruction()
result = getInitialization().getFirstInstruction() )
) or or
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
( (
hasUninitializedInstruction() and result = getInitialization().getFirstInstruction()
kind instanceof GotoEdge and or
tag = InitializerStoreTag() and 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 operandTag instanceof AddressOperandTag and
result = getVarAddress() result = getVarAddress()
} }
/** /**
* Holds if the declaration should have an `Uninitialized` instruction. * Holds if the declaration should have an `Uninitialized` instruction.
* Compiler generated elements should override this predicate and * 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. * desugaring process.
*/ */
predicate hasUninitializedInstruction() { predicate hasUninitializedInstruction() {
@ -89,29 +81,27 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
) and ) and
not isInitializedByElement() not isInitializedByElement()
} }
Instruction getVarAddress() { Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
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). * should be empty (since we treat temp vars differently).
*/ */
abstract LocalVariable getDeclVar(); abstract LocalVariable getDeclVar();
/** /**
* Gets the type of the declared variable. * Gets the type of the declared variable.
*/ */
abstract Type getVarType(); abstract Type getVarType();
/** /**
* Gets the initialization, if there is one. * Gets the initialization, if there is one.
* For compiler generated elements we don't treat the initialization * For compiler generated elements we don't treat the initialization
* as a different step, but do it during the declaration. * as a different step, but do it during the declaration.
*/ */
abstract TranslatedElement getInitialization(); abstract TranslatedElement getInitialization();
/** /**
* Holds if a declaration is not explicitly initialized, * Holds if a declaration is not explicitly initialized,
* but will be implicitly initialized by an element. * 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. * Gets the instruction that produces the result of the expression.
*/ */
abstract Instruction getResult(); 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_6(glval<Int32>) = VariableAddress[i] :
# 71| r0_7(Int32) = Constant[0] : # 71| r0_7(Int32) = Constant[0] :
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7 # 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 #-----| Goto -> Block 2
# 68| Block 1 # 68| Block 1
@ -1058,53 +1061,86 @@ stmts.cs:
# 71| Block 2 # 71| Block 2
# 71| r2_0(glval<Int32>) = VariableAddress[i] : # 71| r2_0(glval<Int32>) = VariableAddress[i] :
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2 # 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 71| r2_2(Int32) = Constant[10] : # 71| r2_2(glval<Int32>) = VariableAddress[j] :
# 71| r2_3(Boolean) = CompareLE : r2_1, r2_2 # 71| r2_3(Int32) = Load : &:r2_2, ~mu0_2
# 71| v2_4(Void) = ConditionalBranch : r2_3 # 71| r2_4(Boolean) = CompareLT : r2_1, r2_3
#-----| False -> Block 1 # 71| v2_5(Void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3 #-----| True -> Block 3
# 73| Block 3 # 73| Block 3
# 73| r3_0(glval<Int32>) = VariableAddress[x] : # 73| r3_0(glval<Int32>) = VariableAddress[x] :
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2 # 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
# 73| r3_2(Int32) = Constant[1] : # 73| r3_2(Int32) = Constant[1] :
# 73| r3_3(Int32) = Sub : r3_1, r3_2 # 73| r3_3(Int32) = Sub : r3_1, r3_2
# 73| r3_4(glval<Int32>) = VariableAddress[x] : # 73| r3_4(glval<Int32>) = VariableAddress[x] :
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3 # 73| mu3_5(Int32) = Store : &:r3_4, r3_3
# 71| r3_6(glval<Int32>) = VariableAddress[i] : # 71| r3_6(glval<Int32>) = VariableAddress[i] :
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2 # 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
# 71| r3_8(Int32) = Constant[1] : # 71| r3_8(Int32) = Constant[1] :
# 71| r3_9(Int32) = Add : r3_7, r3_8 # 71| r3_9(Int32) = Add : r3_7, r3_8
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9 # 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 #-----| Goto (back edge) -> Block 2
# 77| System.Void test_stmts.doWhile() # 76| Block 4
# 77| Block 0 # 76| r4_0(glval<Int32>) = VariableAddress[a] :
# 77| v0_0(Void) = EnterFunction : # 76| r4_1(Int32) = Constant[0] :
# 77| mu0_1(null) = AliasedDefinition : # 76| mu4_2(Int32) = Store : &:r4_0, r4_1
# 77| mu0_2(null) = UnmodeledDefinition : # 76| r4_3(glval<Int32>) = VariableAddress[b] :
# 79| r0_3(glval<Int32>) = VariableAddress[x] : # 76| r4_4(Int32) = Constant[10] :
# 79| r0_4(Int32) = Constant[0] : # 76| mu4_5(Int32) = Store : &:r4_3, r4_4
# 79| mu0_5(Int32) = Store : &:r0_3, r0_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 #-----| Goto -> Block 2
# 77| Block 1 # 83| Block 1
# 77| v1_0(Void) = ReturnVoid : # 83| v1_0(Void) = ReturnVoid :
# 77| v1_1(Void) = UnmodeledUse : mu* # 83| v1_1(Void) = UnmodeledUse : mu*
# 77| v1_2(Void) = ExitFunction : # 83| v1_2(Void) = ExitFunction :
# 82| Block 2 # 88| Block 2
# 82| r2_0(glval<Int32>) = VariableAddress[x] : # 88| r2_0(glval<Int32>) = VariableAddress[x] :
# 82| r2_1(Int32) = Load : &:r2_0, ~mu0_2 # 88| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 82| r2_2(Int32) = Constant[1] : # 88| r2_2(Int32) = Constant[1] :
# 82| r2_3(Int32) = Add : r2_1, r2_2 # 88| r2_3(Int32) = Add : r2_1, r2_2
# 82| r2_4(glval<Int32>) = VariableAddress[x] : # 88| r2_4(glval<Int32>) = VariableAddress[x] :
# 82| mu2_5(Int32) = Store : &:r2_4, r2_3 # 88| mu2_5(Int32) = Store : &:r2_4, r2_3
# 84| r2_6(glval<Int32>) = VariableAddress[x] : # 90| r2_6(glval<Int32>) = VariableAddress[x] :
# 84| r2_7(Int32) = Load : &:r2_6, ~mu0_2 # 90| r2_7(Int32) = Load : &:r2_6, ~mu0_2
# 84| r2_8(Int32) = Constant[10] : # 90| r2_8(Int32) = Constant[10] :
# 84| r2_9(Boolean) = CompareLT : r2_7, r2_8 # 90| r2_9(Boolean) = CompareLT : r2_7, r2_8
# 84| v2_10(Void) = ConditionalBranch : r2_9 # 90| v2_10(Void) = ConditionalBranch : r2_9
#-----| False -> Block 1 #-----| False -> Block 1
#-----| True (back edge) -> Block 2 #-----| True (back edge) -> Block 2

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

@ -68,9 +68,15 @@ public class test_stmts
public static void forStmt() public static void forStmt()
{ {
int x = 0; 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++;
} }
} }