Merge pull request #1674 from dave-bartolomeo/dave/ExternDecls2

C++: Two IR fixes and a PrintAST workaround
This commit is contained in:
Jonas Jensen
2019-08-06 13:46:04 +02:00
committed by GitHub
15 changed files with 514 additions and 61 deletions

View File

@@ -67,11 +67,6 @@ private Function getEnclosingFunction(Locatable ast) {
or
result = ast.(Parameter).getFunction()
or
exists(DeclStmt stmt |
stmt.getADeclarationEntry() = ast and
result = stmt.getEnclosingFunction()
)
or
result = ast
}
@@ -80,7 +75,14 @@ private Function getEnclosingFunction(Locatable ast) {
* nodes for things like parameter lists and constructor init lists.
*/
private newtype TPrintASTNode =
TASTNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
TASTNode(Locatable ast) {
shouldPrintFunction(getEnclosingFunction(ast))
} or
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
// multiple parents due to extractor bug CPP-413.
stmt.getADeclarationEntry() = entry
} or
TParametersNode(Function func) { shouldPrintFunction(func) } or
TConstructorInitializersNode(Constructor ctor) {
ctor.hasEntryPoint() and
@@ -161,11 +163,9 @@ private string qlClass(ElementBase el) { result = "[" + concat(el.getCanonicalQL
/**
* A node representing an AST node.
*/
abstract class ASTNode extends PrintASTNode, TASTNode {
abstract class BaseASTNode extends PrintASTNode {
Locatable ast;
ASTNode() { this = TASTNode(ast) }
override string toString() { result = qlClass(ast) + ast.toString() }
final override Location getLocation() { result = getRepresentativeLocation(ast) }
@@ -176,6 +176,13 @@ abstract class ASTNode extends PrintASTNode, TASTNode {
final Locatable getAST() { result = ast }
}
/**
* A node representing an AST node other than a `DeclarationEntry`.
*/
abstract class ASTNode extends BaseASTNode, TASTNode {
ASTNode() { this = TASTNode(ast) }
}
/**
* A node representing an `Expr`.
*/
@@ -250,18 +257,21 @@ class CastNode extends ConversionNode {
/**
* A node representing a `DeclarationEntry`.
*/
class DeclarationEntryNode extends ASTNode {
DeclarationEntry entry;
class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
override DeclarationEntry ast;
DeclStmt declStmt;
DeclarationEntryNode() { entry = ast }
DeclarationEntryNode() {
this = TDeclarationEntryNode(declStmt, ast)
}
override PrintASTNode getChild(int childIndex) { none() }
override string getProperty(string key) {
result = super.getProperty(key)
result = BaseASTNode.super.getProperty(key)
or
key = "Type" and
result = qlClass(entry.getType()) + entry.getType().toString()
result = qlClass(ast.getType()) + ast.getType().toString()
}
}
@@ -269,13 +279,11 @@ class DeclarationEntryNode extends ASTNode {
* A node representing a `VariableDeclarationEntry`.
*/
class VariableDeclarationEntryNode extends DeclarationEntryNode {
VariableDeclarationEntry varEntry;
VariableDeclarationEntryNode() { varEntry = entry }
override VariableDeclarationEntry ast;
override ASTNode getChild(int childIndex) {
childIndex = 0 and
result.getAST() = varEntry.getVariable().getInitializer()
result.getAST() = ast.getVariable().getInitializer()
}
override string getChildEdgeLabel(int childIndex) { childIndex = 0 and result = "init" }
@@ -289,7 +297,7 @@ class StmtNode extends ASTNode {
StmtNode() { stmt = ast }
override ASTNode getChild(int childIndex) {
override BaseASTNode getChild(int childIndex) {
exists(Locatable child |
child = stmt.getChild(childIndex) and
(
@@ -308,8 +316,11 @@ class DeclStmtNode extends StmtNode {
DeclStmtNode() { declStmt = stmt }
override ASTNode getChild(int childIndex) {
result.getAST() = declStmt.getDeclarationEntry(childIndex)
override DeclarationEntryNode getChild(int childIndex) {
exists (DeclarationEntry entry |
declStmt.getDeclarationEntry(childIndex) = entry and
result = TDeclarationEntryNode(declStmt, entry)
)
}
}

View File

@@ -215,6 +215,55 @@ module InstructionSanity {
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
(
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
) or
exists (Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(Operand useOperand, string message, IRFunction func,
string funcText) {
exists (IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
)
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock) or
(
defBlock = useBlock and
defIndex < useIndex
)
) and
message = "Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
}
/**

View File

@@ -215,6 +215,55 @@ module InstructionSanity {
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
(
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
) or
exists (Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(Operand useOperand, string message, IRFunction func,
string funcText) {
exists (IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
)
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock) or
(
defBlock = useBlock and
defIndex < useIndex
)
) and
message = "Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
}
/**

View File

@@ -18,8 +18,8 @@ TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry)
/**
* Represents the IR translation of a declaration within the body of a function.
* Most often, this is the declaration of an automatic local variable, although
* it can also be the declaration of a static local variable, an extern
* variable, or an extern function.
* it can also be the declaration of a static local variable. Declarations of extern variables and
* functions do not have a `TranslatedDeclarationEntry`.
*/
abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslatedDeclarationEntry {
DeclarationEntry entry;
@@ -44,39 +44,6 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
}
}
/**
* Represents the IR translation of a declaration within the body of a function,
* for declarations other than local variables. Since these have no semantic
* effect, they do not generate any instructions.
*/
class TranslatedNonVariableDeclarationEntry extends TranslatedDeclarationEntry {
TranslatedNonVariableDeclarationEntry() {
not entry.getDeclaration() instanceof LocalVariable
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
none()
}
override Instruction getFirstInstruction() {
result = getParent().getChildSuccessor(this)
}
override TranslatedElement getChild(int id) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
none()
}
override Instruction getChildSuccessor(TranslatedElement child) {
none()
}
}
/**
* Represents the IR translation of the declaration of a local variable,
* including its initialization, if any.

View File

@@ -376,7 +376,9 @@ newtype TTranslatedElement =
TTranslatedDeclarationEntry(DeclarationEntry entry) {
exists(DeclStmt declStmt |
translateStmt(declStmt) and
declStmt.getADeclarationEntry() = entry
declStmt.getADeclarationEntry() = entry and
// Only declarations of local variables need to be translated to IR.
entry.getDeclaration() instanceof LocalVariable
)
} or
// A compiler-generated variable to implement a range-based for loop. These don't have a

View File

@@ -69,6 +69,11 @@ class TranslatedEmptyStmt extends TranslatedStmt {
}
}
/**
* The IR translation of a declaration statement. This consists of the IR for each of the individual
* local variables declared by the statement. Declarations for extern variables and functions
* do not generate any instructions.
*/
class TranslatedDeclStmt extends TranslatedStmt {
override DeclStmt stmt;
@@ -82,15 +87,25 @@ class TranslatedDeclStmt extends TranslatedStmt {
}
override Instruction getFirstInstruction() {
result = getDeclarationEntry(0).getFirstInstruction() //REVIEW: Empty?
result = getDeclarationEntry(0).getFirstInstruction() or
not exists(getDeclarationEntry(0)) and result = getParent().getChildSuccessor(this)
}
private int getChildCount() {
result = stmt.getNumDeclarations()
result = count(getDeclarationEntry(_))
}
/**
* Gets the `TranslatedDeclarationEntry` child at zero-based index `index`. Since not all
* `DeclarationEntry` objects have a `TranslatedDeclarationEntry` (e.g. extern functions), we map
* the original children into a contiguous range containing only those with an actual
* `TranslatedDeclarationEntry`.
*/
private TranslatedDeclarationEntry getDeclarationEntry(int index) {
result = getTranslatedDeclarationEntry(stmt.getDeclarationEntry(index))
result = rank[index + 1](TranslatedDeclarationEntry entry, int originalIndex |
entry = getTranslatedDeclarationEntry(stmt.getDeclarationEntry(originalIndex)) |
entry order by originalIndex
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
@@ -273,7 +288,7 @@ class TranslatedTryStmt extends TranslatedStmt {
// The last catch clause flows to the exception successor of the parent
// of the `try`, because the exception successor of the `try` itself is
// the first catch clause.
handler = getHandler(stmt.getNumberOfCatchClauses()) and
handler = getHandler(stmt.getNumberOfCatchClauses() - 1) and
result = getParent().getExceptionSuccessorInstruction()
)
}

View File

@@ -215,6 +215,55 @@ module InstructionSanity {
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
(
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
) or
exists (Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(Operand useOperand, string message, IRFunction func,
string funcText) {
exists (IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
)
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock) or
(
defBlock = useBlock and
defIndex < useIndex
)
) and
message = "Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
}
/**

View File

@@ -7865,3 +7865,139 @@ ir.cpp:
# 1118| params:
# 1118| 0: [Parameter] p#0
# 1118| Type = [FloatType] float
# 1128| [TopLevelFunction] void ExternDeclarationsInMacro()
# 1128| params:
# 1129| body: [Block] { ... }
# 1130| 0: [DeclStmt] declaration
# 1130| 0: [VariableDeclarationEntry] declaration of g
# 1130| Type = [IntType] int
# 1130| 1: [ForStmt] for(...;...;...) ...
# 1130| 0: [DeclStmt] declaration
# 1130| 0: [VariableDeclarationEntry] definition of i
# 1130| Type = [IntType] int
# 1130| init: [Initializer] initializer for i
# 1130| expr: [Literal,Zero] 0
# 1130| Type = [IntType] int
# 1130| Value = [Literal,Zero] 0
# 1130| ValueCategory = prvalue
# 1130| 1: [LTExpr] ... < ...
# 1130| Type = [BoolType] bool
# 1130| ValueCategory = prvalue
# 1130| 0: [VariableAccess] i
# 1130| Type = [IntType] int
# 1130| ValueCategory = prvalue(load)
# 1130| 1: [Literal] 10
# 1130| Type = [IntType] int
# 1130| Value = [Literal] 10
# 1130| ValueCategory = prvalue
# 1130| 2: [PrefixIncrExpr] ++ ...
# 1130| Type = [IntType] int
# 1130| ValueCategory = lvalue
# 1130| 0: [VariableAccess] i
# 1130| Type = [IntType] int
# 1130| ValueCategory = lvalue
# 1130| 3: [Block] { ... }
# 1130| 0: [DeclStmt] declaration
# 1130| 0: [VariableDeclarationEntry] declaration of g
# 1130| Type = [IntType] int
# 1130| 2: [EmptyStmt] ;
# 1131| 3: [ReturnStmt] return ...
# 1133| [TopLevelFunction] void TryCatchNoCatchAny(bool)
# 1133| params:
# 1133| 0: [Parameter] b
# 1133| Type = [BoolType] bool
# 1133| body: [Block] { ... }
# 1134| 0: [TryStmt] try { ... }
# 1134| 0: [Block] { ... }
# 1135| 0: [DeclStmt] declaration
# 1135| 0: [VariableDeclarationEntry] definition of x
# 1135| Type = [IntType] int
# 1135| init: [Initializer] initializer for x
# 1135| expr: [Literal] 5
# 1135| Type = [IntType] int
# 1135| Value = [Literal] 5
# 1135| ValueCategory = prvalue
# 1136| 1: [IfStmt] if (...) ...
# 1136| 0: [VariableAccess] b
# 1136| Type = [BoolType] bool
# 1136| ValueCategory = prvalue(load)
# 1136| 1: [Block] { ... }
# 1137| 0: [ExprStmt] ExprStmt
# 1137| 0: [ThrowExpr] throw ...
# 1137| Type = [PointerType] const char *
# 1137| ValueCategory = prvalue
# 1137| 0: [ArrayToPointerConversion] array to pointer conversion
# 1137| Type = [PointerType] const char *
# 1137| ValueCategory = prvalue
# 1137| expr: string literal
# 1137| Type = [ArrayType] const char[15]
# 1137| Value = [StringLiteral] "string literal"
# 1137| ValueCategory = lvalue
# 1139| 2: [IfStmt] if (...) ...
# 1139| 0: [LTExpr] ... < ...
# 1139| Type = [BoolType] bool
# 1139| ValueCategory = prvalue
# 1139| 0: [VariableAccess] x
# 1139| Type = [IntType] int
# 1139| ValueCategory = prvalue(load)
# 1139| 1: [Literal] 2
# 1139| Type = [IntType] int
# 1139| Value = [Literal] 2
# 1139| ValueCategory = prvalue
# 1139| 1: [Block] { ... }
# 1140| 0: [ExprStmt] ExprStmt
# 1140| 0: [AssignExpr] ... = ...
# 1140| Type = [IntType] int
# 1140| ValueCategory = lvalue
# 1140| 0: [VariableAccess] x
# 1140| Type = [IntType] int
# 1140| ValueCategory = lvalue
# 1140| 1: [ConditionalExpr] ... ? ... : ...
# 1140| Type = [IntType] int
# 1140| ValueCategory = prvalue
# 1140| 0: [VariableAccess] b
# 1140| Type = [BoolType] bool
# 1140| ValueCategory = prvalue(load)
# 1140| 1: [Literal] 7
# 1140| Type = [IntType] int
# 1140| Value = [Literal] 7
# 1140| ValueCategory = prvalue
# 1140| 2: [ThrowExpr] throw ...
# 1140| Type = [Struct] String
# 1140| ValueCategory = prvalue
# 1140| 0: [ConstructorCall] call to String
# 1140| Type = [VoidType] void
# 1140| ValueCategory = prvalue
# 1140| 0: [ArrayToPointerConversion] array to pointer conversion
# 1140| Type = [PointerType] const char *
# 1140| ValueCategory = prvalue
# 1140| expr: String object
# 1140| Type = [ArrayType] const char[14]
# 1140| Value = [StringLiteral] "String object"
# 1140| ValueCategory = lvalue
# 1142| 2: [ExprStmt] ExprStmt
# 1142| 0: [AssignExpr] ... = ...
# 1142| Type = [IntType] int
# 1142| ValueCategory = lvalue
# 1142| 0: [VariableAccess] x
# 1142| Type = [IntType] int
# 1142| ValueCategory = lvalue
# 1142| 1: [Literal] 7
# 1142| Type = [IntType] int
# 1142| Value = [Literal] 7
# 1142| ValueCategory = prvalue
# 1144| 1: [Handler] <handler>
# 1144| 0: [CatchBlock] { ... }
# 1145| 0: [ExprStmt] ExprStmt
# 1145| 0: [ThrowExpr] throw ...
# 1145| Type = [Struct] String
# 1145| ValueCategory = prvalue
# 1145| 0: [ConstructorCall] call to String
# 1145| Type = [VoidType] void
# 1145| ValueCategory = prvalue
# 1145| 0: [VariableAccess] s
# 1145| Type = [PointerType] const char *
# 1145| ValueCategory = prvalue(load)
# 1147| 2: [Handler] <handler>
# 1147| 0: [CatchBlock] { ... }
# 1149| 1: [ReturnStmt] return ...

View File

@@ -12,3 +12,4 @@ instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition

View File

@@ -1119,4 +1119,33 @@ void ExternDeclarations()
typedef double d;
}
#define EXTERNS_IN_MACRO \
extern int g; \
for (int i = 0; i < 10; ++i) { \
extern int g; \
}
void ExternDeclarationsInMacro()
{
EXTERNS_IN_MACRO;
}
void TryCatchNoCatchAny(bool b) {
try {
int x = 5;
if (b) {
throw "string literal";
}
else if (x < 2) {
x = b ? 7 : throw String("String object");
}
x = 7;
}
catch (const char* s) {
throw String(s);
}
catch (const String& e) {
}
}
// semmle-extractor-options: -std=c++17

View File

@@ -5128,3 +5128,144 @@ ir.cpp:
# 1113| v0_10(void) = ReturnVoid :
# 1113| v0_11(void) = UnmodeledUse : mu*
# 1113| v0_12(void) = ExitFunction :
# 1128| void ExternDeclarationsInMacro()
# 1128| Block 0
# 1128| v0_0(void) = EnterFunction :
# 1128| mu0_1(unknown) = AliasedDefinition :
# 1128| mu0_2(unknown) = UnmodeledDefinition :
# 1130| r0_3(glval<int>) = VariableAddress[i] :
# 1130| r0_4(int) = Constant[0] :
# 1130| mu0_5(int) = Store : &:r0_3, r0_4
#-----| Goto -> Block 1
# 1130| Block 1
# 1130| r1_0(glval<int>) = VariableAddress[i] :
# 1130| r1_1(int) = Load : &:r1_0, ~mu0_2
# 1130| r1_2(int) = Constant[10] :
# 1130| r1_3(bool) = CompareLT : r1_1, r1_2
# 1130| v1_4(void) = ConditionalBranch : r1_3
#-----| False -> Block 3
#-----| True -> Block 2
# 1130| Block 2
# 1130| r2_0(glval<int>) = VariableAddress[i] :
# 1130| r2_1(int) = Load : &:r2_0, ~mu0_2
# 1130| r2_2(int) = Constant[1] :
# 1130| r2_3(int) = Add : r2_1, r2_2
# 1130| mu2_4(int) = Store : &:r2_0, r2_3
#-----| Goto (back edge) -> Block 1
# 1130| Block 3
# 1130| v3_0(void) = NoOp :
# 1131| v3_1(void) = NoOp :
# 1128| v3_2(void) = ReturnVoid :
# 1128| v3_3(void) = UnmodeledUse : mu*
# 1128| v3_4(void) = ExitFunction :
# 1133| void TryCatchNoCatchAny(bool)
# 1133| Block 0
# 1133| v0_0(void) = EnterFunction :
# 1133| mu0_1(unknown) = AliasedDefinition :
# 1133| mu0_2(unknown) = UnmodeledDefinition :
# 1133| r0_3(glval<bool>) = VariableAddress[b] :
# 1133| mu0_4(bool) = InitializeParameter[b] : &:r0_3
# 1135| r0_5(glval<int>) = VariableAddress[x] :
# 1135| r0_6(int) = Constant[5] :
# 1135| mu0_7(int) = Store : &:r0_5, r0_6
# 1136| r0_8(glval<bool>) = VariableAddress[b] :
# 1136| r0_9(bool) = Load : &:r0_8, ~mu0_2
# 1136| v0_10(void) = ConditionalBranch : r0_9
#-----| False -> Block 4
#-----| True -> Block 3
# 1133| Block 1
# 1133| v1_0(void) = UnmodeledUse : mu*
# 1133| v1_1(void) = ExitFunction :
# 1133| Block 2
# 1133| v2_0(void) = Unwind :
#-----| Goto -> Block 1
# 1137| Block 3
# 1137| r3_0(glval<char *>) = VariableAddress[#throw1137:7] :
# 1137| r3_1(glval<char[15]>) = StringConstant["string literal"] :
# 1137| r3_2(char *) = Convert : r3_1
# 1137| mu3_3(char *) = Store : &:r3_0, r3_2
# 1137| v3_4(void) = ThrowValue : &:r3_0, ~mu0_2
#-----| Exception -> Block 9
# 1139| Block 4
# 1139| r4_0(glval<int>) = VariableAddress[x] :
# 1139| r4_1(int) = Load : &:r4_0, ~mu0_2
# 1139| r4_2(int) = Constant[2] :
# 1139| r4_3(bool) = CompareLT : r4_1, r4_2
# 1139| v4_4(void) = ConditionalBranch : r4_3
#-----| False -> Block 8
#-----| True -> Block 5
# 1140| Block 5
# 1140| r5_0(glval<bool>) = VariableAddress[b] :
# 1140| r5_1(bool) = Load : &:r5_0, ~mu0_2
# 1140| v5_2(void) = ConditionalBranch : r5_1
#-----| False -> Block 7
#-----| True -> Block 6
# 1140| Block 6
# 1140| r6_0(int) = Constant[7] :
# 1140| r6_1(glval<int>) = VariableAddress[#temp1140:11] :
# 1140| mu6_2(int) = Store : &:r6_1, r6_0
# 1140| r6_3(glval<int>) = VariableAddress[#temp1140:11] :
# 1140| r6_4(int) = Load : &:r6_3, ~mu0_2
# 1140| r6_5(glval<int>) = VariableAddress[x] :
# 1140| mu6_6(int) = Store : &:r6_5, r6_4
#-----| Goto -> Block 8
# 1140| Block 7
# 1140| r7_0(glval<String>) = VariableAddress[#throw1140:19] :
# 1140| r7_1(glval<unknown>) = FunctionAddress[String] :
# 1140| r7_2(glval<char[14]>) = StringConstant["String object"] :
# 1140| r7_3(char *) = Convert : r7_2
# 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3
# 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2
# 1140| v7_6(void) = ThrowValue : &:r7_0, ~mu0_2
#-----| Exception -> Block 9
# 1142| Block 8
# 1142| r8_0(int) = Constant[7] :
# 1142| r8_1(glval<int>) = VariableAddress[x] :
# 1142| mu8_2(int) = Store : &:r8_1, r8_0
#-----| Goto -> Block 13
# 1144| Block 9
# 1144| v9_0(void) = CatchByType[const char *] :
#-----| Exception -> Block 11
#-----| Goto -> Block 10
# 1144| Block 10
# 1144| r10_0(glval<char *>) = VariableAddress[s] :
# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0
# 1145| r10_2(glval<String>) = VariableAddress[#throw1145:5] :
# 1145| r10_3(glval<unknown>) = FunctionAddress[String] :
# 1145| r10_4(glval<char *>) = VariableAddress[s] :
# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2
# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5
# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2
# 1145| v10_8(void) = ThrowValue : &:r10_2, ~mu0_2
#-----| Exception -> Block 2
# 1147| Block 11
# 1147| v11_0(void) = CatchByType[const String &] :
#-----| Exception -> Block 2
#-----| Goto -> Block 12
# 1147| Block 12
# 1147| r12_0(glval<String &>) = VariableAddress[e] :
# 1147| mu12_1(String &) = InitializeParameter[e] : &:r12_0
# 1147| v12_2(void) = NoOp :
#-----| Goto -> Block 13
# 1149| Block 13
# 1149| v13_0(void) = NoOp :
# 1133| v13_1(void) = ReturnVoid :
#-----| Goto -> Block 1

View File

@@ -12,3 +12,4 @@ instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition

View File

@@ -12,3 +12,4 @@ instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition

View File

@@ -12,3 +12,4 @@ instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition

View File

@@ -12,3 +12,4 @@ instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition