From 5b48bc4a3ea7e90026ff6c81db14c2490823911b Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 7 Mar 2024 09:43:11 +0100 Subject: [PATCH 1/2] C#: Delete the experimental IR queries. --- csharp/ql/src/experimental/ir/IR.qll | 6 - .../src/experimental/ir/IRConfiguration.qll | 1 - .../ql/src/experimental/ir/IRConsistency.ql | 8 - csharp/ql/src/experimental/ir/PrintIR.ql | 8 - csharp/ql/src/experimental/ir/PrintIR.qll | 1 - csharp/ql/src/experimental/ir/Util.qll | 43 - .../ql/src/experimental/ir/ValueNumbering.qll | 1 - .../ir/implementation/EdgeKind.qll | 139 - .../ir/implementation/IRConfiguration.qll | 45 - .../experimental/ir/implementation/IRType.qll | 349 --- .../ir/implementation/MemoryAccessKind.qll | 101 - .../experimental/ir/implementation/Opcode.qll | 1272 ---------- .../ir/implementation/TempVariableTag.qll | 17 - .../implementation/UseSoundEscapeAnalysis.qll | 9 - .../internal/AliasedSSAStub.qll | 19 - .../internal/EdgeKindInternal.qll | 1 - .../internal/IRConfigurationInternal.qll | 1 - .../internal/IRFunctionBase.qll | 32 - .../internal/IRFunctionBaseInternal.qll | 2 - .../internal/IRTypeInternal.qll | 1 - .../implementation/internal/OpcodeImports.qll | 1 - .../ir/implementation/internal/OperandTag.qll | 300 --- .../internal/OperandTagInternal.qll | 1 - .../implementation/internal/TIRVariable.qll | 23 - .../internal/TIRVariableInternal.qll | 7 - .../implementation/internal/TInstruction.qll | 106 - .../internal/TInstructionImports.qll | 2 - .../internal/TInstructionInternal.qll | 4 - .../ir/implementation/internal/TOperand.qll | 150 -- .../internal/TempVariableTagInternal.qll | 6 - .../experimental/ir/implementation/raw/IR.qll | 92 - .../ir/implementation/raw/IRBlock.qll | 356 --- .../ir/implementation/raw/IRConsistency.ql | 8 - .../ir/implementation/raw/IRConsistency.qll | 549 ---- .../ir/implementation/raw/IRFunction.qll | 61 - .../ir/implementation/raw/IRVariable.qll | 337 --- .../ir/implementation/raw/Instruction.qll | 2231 ----------------- .../ir/implementation/raw/Operand.qll | 499 ---- .../ir/implementation/raw/PrintIR.ql | 8 - .../ir/implementation/raw/PrintIR.qll | 342 --- .../raw/constant/ConstantAnalysis.qll | 62 - .../raw/constant/PrintConstantAnalysis.qll | 11 - .../internal/ConstantAnalysisInternal.qll | 1 - .../raw/gvn/PrintValueNumbering.qll | 17 - .../implementation/raw/gvn/ValueNumbering.qll | 90 - .../gvn/internal/ValueNumberingImports.qll | 3 - .../gvn/internal/ValueNumberingInternal.qll | 356 --- .../raw/internal/IRBlockImports.qll | 1 - .../raw/internal/IRConsistencyImports.qll | 1 - .../raw/internal/IRConstruction.qll | 435 ---- .../raw/internal/IRFunctionImports.qll | 1 - .../implementation/raw/internal/IRImports.qll | 3 - .../raw/internal/IRInternal.qll | 4 - .../raw/internal/IRVariableImports.qll | 5 - .../raw/internal/InstructionImports.qll | 6 - .../raw/internal/InstructionTag.qll | 204 -- .../raw/internal/OperandImports.qll | 5 - .../raw/internal/OperandInternal.qll | 2 - .../raw/internal/PrintIRImports.qll | 2 - .../raw/internal/TranslatedCall.qll | 102 - .../raw/internal/TranslatedCondition.qll | 164 -- .../raw/internal/TranslatedDeclaration.qll | 76 - .../raw/internal/TranslatedElement.qll | 569 ----- .../raw/internal/TranslatedExpr.qll | 2095 ---------------- .../raw/internal/TranslatedFunction.qll | 333 --- .../raw/internal/TranslatedInitialization.qll | 388 --- .../raw/internal/TranslatedStmt.qll | 1092 -------- .../internal/common/TranslatedCallBase.qll | 174 -- .../common/TranslatedConditionBase.qll | 79 - .../common/TranslatedDeclarationBase.qll | 93 - .../internal/common/TranslatedExprBase.qll | 14 - .../raw/internal/desugar/Common.qll | 235 -- .../raw/internal/desugar/Delegate.qll | 109 - .../raw/internal/desugar/Foreach.qll | 457 ---- .../raw/internal/desugar/Lock.qll | 426 ---- .../raw/internal/desugar/Using.qll | 1 - .../TranslatedCompilerGeneratedCall.qll | 18 - .../TranslatedCompilerGeneratedCondition.qll | 17 - ...TranslatedCompilerGeneratedDeclaration.qll | 81 - .../TranslatedCompilerGeneratedElement.qll | 23 - .../TranslatedCompilerGeneratedExpr.qll | 18 - .../TranslatedCompilerGeneratedStmt.qll | 14 - .../raw/internal/reachability/Dominance.qll | 22 - .../reachability/DominanceInternal.qll | 7 - .../internal/reachability/PrintDominance.qll | 22 - .../reachability/PrintReachableBlock.qll | 17 - .../internal/reachability/ReachableBlock.qll | 53 - .../reachability/ReachableBlockInternal.qll | 2 - .../ir/implementation/unaliased_ssa/IR.qll | 92 - .../implementation/unaliased_ssa/IRBlock.qll | 356 --- .../unaliased_ssa/IRConsistency.ql | 8 - .../unaliased_ssa/IRConsistency.qll | 549 ---- .../unaliased_ssa/IRFunction.qll | 61 - .../unaliased_ssa/IRVariable.qll | 337 --- .../unaliased_ssa/Instruction.qll | 2231 ----------------- .../implementation/unaliased_ssa/Operand.qll | 499 ---- .../implementation/unaliased_ssa/PrintIR.ql | 8 - .../implementation/unaliased_ssa/PrintIR.qll | 342 --- .../constant/ConstantAnalysis.qll | 54 - .../constant/PrintConstantAnalysis.qll | 11 - .../internal/ConstantAnalysisInternal.qll | 1 - .../unaliased_ssa/gvn/PrintValueNumbering.qll | 17 - .../unaliased_ssa/gvn/ValueNumbering.qll | 90 - .../gvn/internal/ValueNumberingImports.qll | 3 - .../gvn/internal/ValueNumberingInternal.qll | 356 --- .../unaliased_ssa/internal/AliasAnalysis.qll | 474 ---- .../internal/AliasAnalysisImports.qll | 269 -- .../internal/AliasAnalysisInternal.qll | 3 - .../internal/AliasConfiguration.qll | 18 - .../internal/AliasConfigurationImports.qll | 1 - .../unaliased_ssa/internal/IRBlockImports.qll | 1 - .../internal/IRConsistencyImports.qll | 1 - .../internal/IRFunctionImports.qll | 1 - .../unaliased_ssa/internal/IRImports.qll | 3 - .../unaliased_ssa/internal/IRInternal.qll | 4 - .../internal/IRVariableImports.qll | 5 - .../internal/InstructionImports.qll | 6 - .../unaliased_ssa/internal/OperandImports.qll | 5 - .../internal/OperandInternal.qll | 2 - .../unaliased_ssa/internal/PrintIRImports.qll | 2 - .../unaliased_ssa/internal/PrintSSA.qll | 157 -- .../unaliased_ssa/internal/SSAConsistency.ql | 8 - .../unaliased_ssa/internal/SSAConsistency.qll | 55 - .../internal/SSAConsistencyImports.qll | 3 - .../internal/SSAConstruction.qll | 1056 -------- .../internal/SSAConstructionImports.qll | 5 - .../internal/SSAConstructionInternal.qll | 9 - .../unaliased_ssa/internal/SimpleSSA.qll | 111 - .../internal/SimpleSSAImports.qll | 4 - .../internal/SimpleSSAPublicImports.qll | 1 - .../internal/reachability/Dominance.qll | 22 - .../reachability/DominanceInternal.qll | 7 - .../internal/reachability/PrintDominance.qll | 22 - .../reachability/PrintReachableBlock.qll | 17 - .../internal/reachability/ReachableBlock.qll | 53 - .../reachability/ReachableBlockInternal.qll | 2 - .../experimental/ir/internal/CSharpType.qll | 365 --- .../ir/internal/IRCSharpLanguage.qll | 162 -- .../ir/internal/IRCSharpLanguageDebug.qll | 5 - .../src/experimental/ir/internal/IRGuards.qll | 670 ----- .../experimental/ir/internal/IRUtilities.qll | 16 - .../ir/internal/IntegerConstant.qll | 236 -- .../ir/internal/IntegerInterval.qll | 35 - .../ir/internal/IntegerPartial.qll | 99 - .../src/experimental/ir/internal/Overlap.qll | 70 - .../ir/internal/TempVariableTag.qll | 32 - .../experimental/ir/rangeanalysis/Bound.qll | 79 - .../ir/rangeanalysis/RangeAnalysis.qll | 633 ----- .../ir/rangeanalysis/RangeUtils.qll | 96 - .../ir/rangeanalysis/SignAnalysis.qll | 585 ----- .../test/experimental/ir/ir/PrintAst.expected | 1379 ---------- .../ql/test/experimental/ir/ir/PrintAst.qlref | 1 - csharp/ql/test/experimental/ir/ir/array.cs | 22 - csharp/ql/test/experimental/ir/ir/assignop.cs | 22 - csharp/ql/test/experimental/ir/ir/casts.cs | 17 - .../ql/test/experimental/ir/ir/collections.cs | 19 - .../experimental/ir/ir/constructor_init.cs | 35 - csharp/ql/test/experimental/ir/ir/crement.cs | 11 - .../ql/test/experimental/ir/ir/delegates.cs | 15 - csharp/ql/test/experimental/ir/ir/events.cs | 35 - csharp/ql/test/experimental/ir/ir/foreach.cs | 12 - .../ir/ir/func_with_param_call.cs | 14 - csharp/ql/test/experimental/ir/ir/indexers.cs | 26 - .../ir/ir/inheritance_polymorphism.cs | 37 - csharp/ql/test/experimental/ir/ir/inoutref.cs | 38 - csharp/ql/test/experimental/ir/ir/isexpr.cs | 22 - csharp/ql/test/experimental/ir/ir/jumps.cs | 40 - csharp/ql/test/experimental/ir/ir/lock.cs | 13 - .../test/experimental/ir/ir/obj_creation.cs | 29 - csharp/ql/test/experimental/ir/ir/options | 1 - csharp/ql/test/experimental/ir/ir/pointers.cs | 42 - csharp/ql/test/experimental/ir/ir/prop.cs | 32 - .../test/experimental/ir/ir/raw_ir.expected | 2008 --------------- .../ql/test/experimental/ir/ir/raw_ir.qlref | 1 - .../ir/ir/raw_ir_consistency.expected | 35 - .../ir/ir/raw_ir_consistency.qlref | 1 - .../ql/test/experimental/ir/ir/simple_call.cs | 14 - .../experimental/ir/ir/simple_function.cs | 9 - csharp/ql/test/experimental/ir/ir/stmts.cs | 110 - .../ir/ir/unaliased_ssa_consistency.expected | 35 - .../ir/ir/unaliased_ssa_consistency.qlref | 1 - .../ir/unaliased_ssa_ssa_consistency.expected | 3 - .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 1 - csharp/ql/test/experimental/ir/ir/using.cs | 28 - .../ql/test/experimental/ir/ir/variables.cs | 12 - .../ir/offbyone/OffByOneRA.expected | 5 - .../experimental/ir/offbyone/OffByOneRA.ql | 50 - .../ql/test/experimental/ir/offbyone/null.cs | 5 - .../ql/test/experimental/ir/offbyone/test.cs | 107 - .../ir/rangeanalysis/RangeAnalysis.expected | 18 - .../ir/rangeanalysis/RangeAnalysis.ql | 25 - .../experimental/ir/rangeanalysis/null.cs | 5 - .../experimental/ir/rangeanalysis/test.cs | 85 - 193 files changed, 29894 deletions(-) delete mode 100644 csharp/ql/src/experimental/ir/IR.qll delete mode 100644 csharp/ql/src/experimental/ir/IRConfiguration.qll delete mode 100644 csharp/ql/src/experimental/ir/IRConsistency.ql delete mode 100644 csharp/ql/src/experimental/ir/PrintIR.ql delete mode 100644 csharp/ql/src/experimental/ir/PrintIR.qll delete mode 100644 csharp/ql/src/experimental/ir/Util.qll delete mode 100644 csharp/ql/src/experimental/ir/ValueNumbering.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/EdgeKind.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/IRType.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/Opcode.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IR.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/Operand.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRConsistencyImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRConsistencyImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistencyImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll delete mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/CSharpType.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IRCSharpLanguageDebug.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IRGuards.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IRUtilities.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IntegerConstant.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IntegerInterval.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/IntegerPartial.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/Overlap.qll delete mode 100644 csharp/ql/src/experimental/ir/internal/TempVariableTag.qll delete mode 100644 csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll delete mode 100644 csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll delete mode 100644 csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll delete mode 100644 csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll delete mode 100644 csharp/ql/test/experimental/ir/ir/PrintAst.expected delete mode 100644 csharp/ql/test/experimental/ir/ir/PrintAst.qlref delete mode 100644 csharp/ql/test/experimental/ir/ir/array.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/assignop.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/casts.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/collections.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/constructor_init.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/crement.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/delegates.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/events.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/foreach.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/func_with_param_call.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/indexers.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/inoutref.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/isexpr.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/jumps.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/lock.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/obj_creation.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/options delete mode 100644 csharp/ql/test/experimental/ir/ir/pointers.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/prop.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir.expected delete mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir.qlref delete mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected delete mode 100644 csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref delete mode 100644 csharp/ql/test/experimental/ir/ir/simple_call.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/simple_function.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/stmts.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected delete mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref delete mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected delete mode 100644 csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref delete mode 100644 csharp/ql/test/experimental/ir/ir/using.cs delete mode 100644 csharp/ql/test/experimental/ir/ir/variables.cs delete mode 100644 csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected delete mode 100644 csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql delete mode 100644 csharp/ql/test/experimental/ir/offbyone/null.cs delete mode 100644 csharp/ql/test/experimental/ir/offbyone/test.cs delete mode 100644 csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected delete mode 100644 csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql delete mode 100644 csharp/ql/test/experimental/ir/rangeanalysis/null.cs delete mode 100644 csharp/ql/test/experimental/ir/rangeanalysis/test.cs diff --git a/csharp/ql/src/experimental/ir/IR.qll b/csharp/ql/src/experimental/ir/IR.qll deleted file mode 100644 index 24eaa1efd85..00000000000 --- a/csharp/ql/src/experimental/ir/IR.qll +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Most queries should operate on the aliased SSA IR, so that's what we expose - * publicly as the "IR". - */ - -import implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/experimental/ir/IRConfiguration.qll b/csharp/ql/src/experimental/ir/IRConfiguration.qll deleted file mode 100644 index b5b7d7de7c2..00000000000 --- a/csharp/ql/src/experimental/ir/IRConfiguration.qll +++ /dev/null @@ -1 +0,0 @@ -import implementation.IRConfiguration diff --git a/csharp/ql/src/experimental/ir/IRConsistency.ql b/csharp/ql/src/experimental/ir/IRConsistency.ql deleted file mode 100644 index 6344b237dfd..00000000000 --- a/csharp/ql/src/experimental/ir/IRConsistency.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name IR Consistency Check - * @description Performs consistency checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cs/ir-consistency-check - */ - -import implementation.raw.IRConsistency diff --git a/csharp/ql/src/experimental/ir/PrintIR.ql b/csharp/ql/src/experimental/ir/PrintIR.ql deleted file mode 100644 index 3bc50831fd2..00000000000 --- a/csharp/ql/src/experimental/ir/PrintIR.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Print IR - * @description Outputs a representation of the IR graph - * @id cs/print-ir - * @kind graph - */ - -import implementation.unaliased_ssa.PrintIR diff --git a/csharp/ql/src/experimental/ir/PrintIR.qll b/csharp/ql/src/experimental/ir/PrintIR.qll deleted file mode 100644 index 711c134210c..00000000000 --- a/csharp/ql/src/experimental/ir/PrintIR.qll +++ /dev/null @@ -1 +0,0 @@ -import implementation.unaliased_ssa.PrintIR diff --git a/csharp/ql/src/experimental/ir/Util.qll b/csharp/ql/src/experimental/ir/Util.qll deleted file mode 100644 index 77280f5046f..00000000000 --- a/csharp/ql/src/experimental/ir/Util.qll +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Temporary file that has stubs for various functionalities in the IR conversion. - */ - -import csharp - -class ArrayInitWithMod extends ArrayInitializer { - predicate isInitialized(int entry) { entry in [0 .. this.getNumberOfElements() - 1] } - - predicate isValueInitialized(int elementIndex) { - this.isInitialized(elementIndex) and - not exists(this.getElement(elementIndex)) - } -} - -class ObjectInitializerMod extends ObjectInitializer { - private predicate isInitialized(Field field) { - not field.isReadOnly() and // TODO: Is this the only instance whena field can not be init? - this.getAMemberInitializer().getTargetVariable() = field - } - - predicate isValueInitialized(Field field) { - this.isInitialized(field) and - not field = this.getAMemberInitializer().getInitializedMember() - } -} - -// TODO: See if we need to adapt this for C# -abstract class SideEffectFunction extends Callable { - /** - * Holds if the function never reads from memory that was defined before entry to the function. - * This memory could be from global variables, or from other memory that was reachable from a - * pointer that was passed into the function. - */ - abstract predicate neverReadsMemory(); - - /** - * Holds if the function never writes to memory that remains allocated after the function - * returns. This memory could be from global variables, or from other memory that was reachable - * from a pointer that was passed into the function. - */ - abstract predicate neverWritesMemory(); -} diff --git a/csharp/ql/src/experimental/ir/ValueNumbering.qll b/csharp/ql/src/experimental/ir/ValueNumbering.qll deleted file mode 100644 index f6cdc912a12..00000000000 --- a/csharp/ql/src/experimental/ir/ValueNumbering.qll +++ /dev/null @@ -1 +0,0 @@ -import implementation.unaliased_ssa.gvn.ValueNumbering diff --git a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll deleted file mode 100644 index 91e1fe03e23..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Provides classes that specify the conditions under which control flows along a given edge. - */ - -private import internal.EdgeKindInternal - -private newtype TEdgeKind = - TGotoEdge() or // Single successor (including fall-through) - TTrueEdge() or // 'true' edge of conditional branch - TFalseEdge() or // 'false' edge of conditional branch - TExceptionEdge() or // Thrown exception - TDefaultEdge() or // 'default' label of switch - TCaseEdge(string minValue, string maxValue) { - // Case label of switch - Language::hasCaseEdge(minValue, maxValue) - } - -/** - * Represents the kind of an edge in the IR control flow graph. Each - * `Instruction` or `IRBlock` has at most one successor of any single - * `EdgeKind`. - */ -abstract class EdgeKind extends TEdgeKind { - /** Gets a textual representation of this edge kind. */ - abstract string toString(); -} - -/** - * A "goto" edge, representing the unconditional successor of an `Instruction` - * or `IRBlock`. - */ -class GotoEdge extends EdgeKind, TGotoEdge { - final override string toString() { result = "Goto" } -} - -/** - * A "true" edge, representing the successor of a conditional branch when the - * condition is non-zero. - */ -class TrueEdge extends EdgeKind, TTrueEdge { - final override string toString() { result = "True" } -} - -/** - * A "false" edge, representing the successor of a conditional branch when the - * condition is zero. - */ -class FalseEdge extends EdgeKind, TFalseEdge { - final override string toString() { result = "False" } -} - -/** - * An "exception" edge, representing the successor of an instruction when that - * instruction's evaluation throws an exception. - */ -class ExceptionEdge extends EdgeKind, TExceptionEdge { - final override string toString() { result = "Exception" } -} - -/** - * A "default" edge, representing the successor of a `Switch` instruction when - * none of the case values matches the condition value. - */ -class DefaultEdge extends EdgeKind, TDefaultEdge { - final override string toString() { result = "Default" } -} - -/** - * A "case" edge, representing the successor of a `Switch` instruction when the - * the condition value matches a corresponding `case` label. - */ -class CaseEdge extends EdgeKind, TCaseEdge { - string minValue; - string maxValue; - - CaseEdge() { this = TCaseEdge(minValue, maxValue) } - - final override string toString() { - if minValue = maxValue - then result = "Case[" + minValue + "]" - else result = "Case[" + minValue + ".." + maxValue + "]" - } - - /** - * Gets the smallest value of the switch expression for which control will flow along this edge. - */ - final string getMinValue() { result = minValue } - - /** - * Gets the largest value of the switch expression for which control will flow along this edge. - */ - final string getMaxValue() { result = maxValue } -} - -/** - * Predicates to access the single instance of each `EdgeKind` class. - */ -module EdgeKind { - /** - * Gets the single instance of the `GotoEdge` class. - */ - GotoEdge gotoEdge() { result = TGotoEdge() } - - /** - * Gets the single instance of the `TrueEdge` class. - */ - TrueEdge trueEdge() { result = TTrueEdge() } - - /** - * Gets the single instance of the `FalseEdge` class. - */ - FalseEdge falseEdge() { result = TFalseEdge() } - - /** - * Gets the single instance of the `ExceptionEdge` class. - */ - ExceptionEdge exceptionEdge() { result = TExceptionEdge() } - - /** - * Gets the single instance of the `DefaultEdge` class. - */ - DefaultEdge defaultEdge() { result = TDefaultEdge() } - - /** - * Gets the `CaseEdge` representing a `case` label with the specified lower and upper bounds. - * For example: - * ``` - * switch (x) { - * case 1: // Edge kind is `caseEdge("1", "1")` - * return x; - * case 2...8: // Edge kind is `caseEdge("2", "8")` - * return x - 1; - * default: // Edge kind is `defaultEdge()` - * return 0; - * } - * ``` - */ - CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } -} diff --git a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll deleted file mode 100644 index 90cdb9e0f5f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Module used to configure the IR generation process. - */ - -private import internal.IRConfigurationInternal - -private newtype TIRConfiguration = MkIRConfiguration() - -/** - * The query can extend this class to control which functions have IR generated for them. - */ -class IRConfiguration extends TIRConfiguration { - /** Gets a textual representation of this element. */ - string toString() { result = "IRConfiguration" } - - /** - * Holds if IR should be created for function `func`. By default, holds for all functions. - */ - predicate shouldCreateIRForFunction(Language::Declaration func) { any() } - - /** - * Holds if the strings used as part of an IR dump should be generated for function `func`. - * - * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number - * of debug strings for IR that will not be dumped. We still generate the actual IR for these - * functions, however, to preserve the results of any interprocedural analysis. - */ - predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { any() } -} - -private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration() - -/** - * The query can extend this class to control what escape analysis is used when generating SSA. - */ -class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { - /** Gets a textual representation of this element. */ - string toString() { result = "IREscapeAnalysisConfiguration" } - - /** - * Holds if the escape analysis done by SSA construction should be sound. By default, the SSA is - * built assuming that no variable's address ever escapes. - */ - predicate useSoundEscapeAnalysis() { none() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll deleted file mode 100644 index 9fbcf8c4a3b..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/IRType.qll +++ /dev/null @@ -1,349 +0,0 @@ -/** - * Minimal, language-neutral type system for the IR. - */ - -private import internal.IRTypeInternal - -cached -private newtype TIRType = - TIRVoidType() or - TIRUnknownType() or - TIRErrorType() { Language::hasErrorType() } or - TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or - TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or - TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or - TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { - Language::hasFloatingPointType(byteSize, base, domain) - } or - TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or - TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or - TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) { - Language::hasOpaqueType(tag, byteSize) - } - -/** - * The language-neutral type of an IR `Instruction`, `Operand`, or `IRVariable`. - * The interface to `IRType` and its subclasses is the same across all languages for which the IR - * is supported, so analyses that expect to be used for multiple languages should generally use - * `IRType` rather than a language-specific type. - * - * Many types from the language-specific type system will map to a single canonical `IRType`. Two - * types that map to the same `IRType` are considered equivalent by the IR. As an example, in C++, - * all pointer types map to the same instance of `IRAddressType`. - */ -class IRType extends TIRType { - /** Gets a textual representation of this type. */ - string toString() { none() } - - /** - * Gets a string that uniquely identifies this `IRType`. This string is often the same as the - * result of `IRType.toString()`, but for some types it may be more verbose to ensure uniqueness. - */ - string getIdentityString() { result = this.toString() } - - /** - * Gets the size of the type, in bytes, if known. - * - * This will hold for all `IRType` objects except `IRUnknownType`. - */ - // This predicate is overridden with `pragma[noinline]` in every leaf subclass. - // This allows callers to ask for things like _the_ floating-point type of - // size 4 without getting a join that first finds all types of size 4 and - // _then_ restricts them to floating-point types. - int getByteSize() { none() } - - /** - * Gets a single instance of `LanguageType` that maps to this `IRType`. - */ - Language::LanguageType getCanonicalLanguageType() { none() } -} - -/** - * An unknown type. Generally used to represent results and operands that access an unknown set of - * memory locations, such as the side effects of a function call. - */ -class IRUnknownType extends IRType, TIRUnknownType { - final override string toString() { result = "unknown" } - - final override int getByteSize() { none() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalUnknownType() - } -} - -/** - * A void type, which has no values. Used to represent the result type of an instruction that does - * not produce a result. - */ -class IRVoidType extends IRType, TIRVoidType { - final override string toString() { result = "void" } - - final override int getByteSize() { result = 0 } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalVoidType() - } -} - -/** - * An error type. Used when an error in the source code prevents the extractor from determining the - * proper type. - */ -class IRErrorType extends IRType, TIRErrorType { - final override string toString() { result = "error" } - - final override int getByteSize() { result = 0 } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalErrorType() - } -} - -private class IRSizedType extends IRType { - int byteSize; - - IRSizedType() { - this = TIRBooleanType(byteSize) or - this = TIRSignedIntegerType(byteSize) or - this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize, _, _) or - this = TIRAddressType(byteSize) or - this = TIRFunctionAddressType(byteSize) or - this = TIROpaqueType(_, byteSize) - } - // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is - // overridden only in the leaf classes. -} - -/** - * A Boolean type, which can hold the values `true` (non-zero) or `false` (zero). - */ -class IRBooleanType extends IRSizedType, TIRBooleanType { - final override string toString() { result = "bool" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalBooleanType(byteSize) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } -} - -/** - * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and - * `IRFloatingPointType`. - */ -class IRNumericType extends IRSizedType { - IRNumericType() { - this = TIRSignedIntegerType(byteSize) or - this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize, _, _) - } - // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is - // overridden only in the leaf classes. -} - -/** - * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. - */ -class IRIntegerType extends IRNumericType { - IRIntegerType() { - this = TIRSignedIntegerType(byteSize) or - this = TIRUnsignedIntegerType(byteSize) - } - - /** Holds if this integer type is signed. */ - predicate isSigned() { none() } - - /** Holds if this integer type is unsigned. */ - predicate isUnsigned() { none() } - // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is - // overridden only in the leaf classes. -} - -/** - * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed - * integer, as well as character types whose representation is signed. - */ -class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { - final override string toString() { result = "int" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalSignedIntegerType(byteSize) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } - - override predicate isSigned() { any() } -} - -/** - * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an - * unsigned integer, as well as character types whose representation is unsigned. - */ -class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { - final override string toString() { result = "uint" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalUnsignedIntegerType(byteSize) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } - - override predicate isUnsigned() { any() } -} - -/** - * A floating-point type. - */ -class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { - final private int base; - final private Language::TypeDomain domain; - - IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) } - - final override string toString() { - result = this.getDomainPrefix() + this.getBaseString() + byteSize.toString() - } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalFloatingPointType(byteSize, base, domain) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } - - /** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */ - final int getBase() { result = base } - - /** - * Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`. - */ - final Language::TypeDomain getDomain() { result = domain } - - private string getBaseString() { - base = 2 and result = "float" - or - base = 10 and result = "decimal" - } - - private string getDomainPrefix() { - domain instanceof Language::RealDomain and result = "" - or - domain instanceof Language::ComplexDomain and result = "c" - or - domain instanceof Language::ImaginaryDomain and result = "i" - } -} - -/** - * An address type, representing the memory address of data. Used to represent pointers, references, - * and lvalues, include those that are garbage collected. - * - * The address of a function is represented by the separate `IRFunctionAddressType`. - */ -class IRAddressType extends IRSizedType, TIRAddressType { - final override string toString() { result = "addr" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalAddressType(byteSize) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } -} - -/** - * An address type, representing the memory address of code. Used to represent function pointers, - * function references, and the target of a direct function call. - */ -class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType { - final override string toString() { result = "func" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalFunctionAddressType(byteSize) - } - - pragma[noinline] - final override int getByteSize() { result = byteSize } -} - -/** - * A type with known size that does not fit any of the other kinds of type. Used to represent - * classes, structs, unions, fixed-size arrays, pointers-to-member, and more. - */ -class IROpaqueType extends IRSizedType, TIROpaqueType { - Language::OpaqueTypeTag tag; - - IROpaqueType() { this = TIROpaqueType(tag, byteSize) } - - final override string toString() { - result = "opaque" + byteSize.toString() + "{" + tag.toString() + "}" - } - - final override string getIdentityString() { - result = "opaque" + byteSize.toString() + "{" + Language::getOpaqueTagIdentityString(tag) + "}" - } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalOpaqueType(tag, byteSize) - } - - /** - * Gets the "tag" that differentiates this type from other incompatible opaque types that have the - * same size. - */ - final Language::OpaqueTypeTag getTag() { result = tag } - - pragma[noinline] - final override int getByteSize() { result = byteSize } -} - -/** - * INTERNAL: Do not use. - * Query predicates used to check invariants that should hold for all `IRType` objects. To run all - * consistency queries for the IR, including the ones below, run - * "semmle/code/cpp/IR/IRConsistency.ql". - */ -module IRTypeConsistency { - /** - * Holds if the type has no result for `IRType.getCanonicalLanguageType()`. - */ - query predicate missingCanonicalLanguageType(IRType type, string message) { - not exists(type.getCanonicalLanguageType()) and - message = "Type does not have a canonical `LanguageType`" - } - - /** - * Holds if the type has more than one result for `IRType.getCanonicalLanguageType()`. - */ - query predicate multipleCanonicalLanguageTypes(IRType type, string message) { - strictcount(type.getCanonicalLanguageType()) > 1 and - message = - "Type has multiple canonical `LanguageType`s: " + - concat(type.getCanonicalLanguageType().toString(), ", ") - } - - /** - * Holds if the type has no result for `LanguageType.getIRType()`. - */ - query predicate missingIRType(Language::LanguageType type, string message) { - not exists(type.getIRType()) and - message = "`LanguageType` does not have a corresponding `IRType`." - } - - /** - * Holds if the type has more than one result for `LanguageType.getIRType()`. - */ - query predicate multipleIRTypes(Language::LanguageType type, string message) { - strictcount(type.getIRType()) > 1 and - message = - "`LanguageType` " + type + " has multiple `IRType`s: " + - concat(type.getIRType().toString(), ", ") - } - - import Language::LanguageTypeConsistency -} diff --git a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll deleted file mode 100644 index 5e11a310e2f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Provides classes that describe how a particular `Instruction` or its operands access memory. - */ - -private import IRConfiguration - -private newtype TMemoryAccessKind = - TIndirectMemoryAccess() or - TBufferMemoryAccess() or - TEntireAllocationMemoryAccess() or - TEscapedMemoryAccess() or - TNonLocalMemoryAccess() or - TPhiMemoryAccess() or - TUnmodeledMemoryAccess() or - TChiTotalMemoryAccess() or - TChiPartialMemoryAccess() - -/** - * Describes the set of memory locations memory accessed by a memory operand or - * memory result. - */ -class MemoryAccessKind extends TMemoryAccessKind { - /** Gets a textual representation of this access kind. */ - string toString() { none() } - - /** - * Holds if the operand or result accesses memory pointed to by the `AddressOperand` on the - * same instruction. - */ - predicate usesAddressOperand() { none() } -} - -/** - * The operand or result accesses memory at the address specified by the `AddressOperand` on the - * same instruction. - */ -class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess { - override string toString() { result = "indirect" } - - final override predicate usesAddressOperand() { any() } -} - -/** - * The operand or result accesses memory starting at the address specified by the `AddressOperand` - * on the same instruction, accessing a number of consecutive elements given by the - * `BufferSizeOperand`. - */ -class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess { - override string toString() { result = "buffer" } - - final override predicate usesAddressOperand() { any() } -} - -/** - * The operand or results accesses all memory in the contiguous allocation that contains the address - * specified by the `AddressOperand` on the same instruction. - */ -class EntireAllocationMemoryAccess extends MemoryAccessKind, TEntireAllocationMemoryAccess { - override string toString() { result = "alloc" } - - final override predicate usesAddressOperand() { any() } -} - -/** - * The operand or result accesses all memory whose address has escaped. - */ -class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess { - override string toString() { result = "escaped" } -} - -/** - * The operand or result access all memory whose address has escaped, other than data on the stack - * frame of the current function. - */ -class NonLocalMemoryAccess extends MemoryAccessKind, TNonLocalMemoryAccess { - override string toString() { result = "nonlocal" } -} - -/** - * The operand is a Phi operand, which accesses the same memory as its - * definition. - */ -class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess { - override string toString() { result = "phi" } -} - -/** - * The operand is a ChiTotal operand, which accesses the same memory as its - * definition. - */ -class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess { - override string toString() { result = "chi(total)" } -} - -/** - * The operand is a ChiPartial operand, which accesses the same memory as its - * definition. - */ -class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess { - override string toString() { result = "chi(partial)" } -} diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll deleted file mode 100644 index c473969467d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ /dev/null @@ -1,1272 +0,0 @@ -/** - * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata - * about those opcodes, such as operand kinds and memory accesses. - */ - -private import internal.OpcodeImports as Imports -private import internal.OperandTag -import Imports::MemoryAccessKind - -private newtype TOpcode = - TNoOp() or - TUninitialized() or - TError() or - TInitializeParameter() or - TInitializeIndirection() or - TInitializeThis() or - TEnterFunction() or - TExitFunction() or - TReturnValue() or - TReturnVoid() or - TReturnIndirection() or - TCopyValue() or - TLoad() or - TStore() or - TAdd() or - TSub() or - TMul() or - TDiv() or - TRem() or - TNegate() or - TShiftLeft() or - TShiftRight() or - TUnsignedShiftRight() or - TBitAnd() or - TBitOr() or - TBitXor() or - TBitComplement() or - TLogicalNot() or - TCompareEQ() or - TCompareNE() or - TCompareLT() or - TCompareGT() or - TCompareLE() or - TCompareGE() or - TPointerAdd() or - TPointerSub() or - TPointerDiff() or - TConvert() or - TConvertToNonVirtualBase() or - TConvertToVirtualBase() or - TConvertToDerived() or - TCheckedConvertOrNull() or - TCheckedConvertOrThrow() or - TCompleteObjectAddress() or - TVariableAddress() or - TFieldAddress() or - TFunctionAddress() or - TVirtualDeleteFunctionAddress() or - TElementsAddress() or - TConstant() or - TStringConstant() or - TConditionalBranch() or - TSwitch() or - TCall() or - TCatchByType() or - TCatchAny() or - TThrowValue() or - TReThrow() or - TUnwind() or - TAliasedDefinition() or - TInitializeNonLocal() or - TAliasedUse() or - TPhi() or - TBuiltIn() or - TVarArgsStart() or - TVarArgsEnd() or - TVarArg() or - TNextVarArg() or - TCallSideEffect() or - TCallReadSideEffect() or - TIndirectReadSideEffect() or - TIndirectMustWriteSideEffect() or - TIndirectMayWriteSideEffect() or - TBufferReadSideEffect() or - TBufferMustWriteSideEffect() or - TBufferMayWriteSideEffect() or - TSizedBufferReadSideEffect() or - TSizedBufferMustWriteSideEffect() or - TSizedBufferMayWriteSideEffect() or - TInitializeDynamicAllocation() or - TChi() or - TInlineAsm() or - TUnreached() or - TNewObj() - -/** - * An opcode that specifies the operation performed by an `Instruction`. - */ -class Opcode extends TOpcode { - /** Gets a textual representation of this element. */ - string toString() { result = "UnknownOpcode" } - - /** - * Gets the kind of memory access performed by this instruction's result. - * Holds only for opcodes with a memory result. - */ - MemoryAccessKind getWriteMemoryAccess() { none() } - - /** - * Gets the kind of memory access performed by this instruction's `MemoryOperand`. Holds only for - * opcodes that read from memory. - */ - MemoryAccessKind getReadMemoryAccess() { none() } - - /** - * Holds if the instruction has an `AddressOperand`. - */ - predicate hasAddressOperand() { none() } - - /** - * Holds if the instruction has a `BufferSizeOperand`. - */ - predicate hasBufferSizeOperand() { none() } - - /** - * Holds if the instruction's write memory access is a `may` write, as opposed to a `must` write. - */ - predicate hasMayWriteMemoryAccess() { none() } - - /** - * Holds if the instruction's read memory access is a `may` read, as opposed to a `must` read. - */ - predicate hasMayReadMemoryAccess() { none() } - - /** - * Holds if the instruction must have an operand with the specified `OperandTag`. - */ - final predicate hasOperand(OperandTag tag) { - this.hasOperandInternal(tag) - or - this.hasAddressOperand() and tag instanceof AddressOperandTag - or - this.hasBufferSizeOperand() and tag instanceof BufferSizeOperandTag - } - - /** - * Holds if the instruction must have an operand with the specified `OperandTag`, ignoring - * `AddressOperandTag` and `BufferSizeOperandTag`. - */ - predicate hasOperandInternal(OperandTag tag) { none() } -} - -/** - * The `Opcode` for a `UnaryInstruction`. - * - * See the `UnaryInstruction` documentation for more details. - */ -abstract class UnaryOpcode extends Opcode { - final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } -} - -/** - * The `Opcode` for a `BinaryInstruction`. - * - * See the `BinaryInstruction` documentation for more details. - */ -abstract class BinaryOpcode extends Opcode { - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - } -} - -/** - * The `Opcode` for a `PointerArithmeticInstruction`. - * - * See the `PointerArithmeticInstruction` documentation for more details. - */ -abstract class PointerArithmeticOpcode extends BinaryOpcode { } - -/** - * The `Opcode` for a `PointerOffsetInstruction`. - * - * See the `PointerOffsetInstruction` documentation for more details. - */ -abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } - -/** - * The `Opcode` for an `ArithmeticInstruction`. - * - * See the `ArithmeticInstruction` documentation for more details. - */ -abstract class ArithmeticOpcode extends Opcode { } - -/** - * The `Opcode` for a `BinaryArithmeticInstruction`. - * - * See the `BinaryArithmeticInstruction` documentation for more details. - */ -abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } - -/** - * The `Opcode` for a `UnaryArithmeticInstruction`. - * - * See the `UnaryArithmeticInstruction` documentation for more details. - */ -abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } - -/** - * The `Opcode` for a `BitwiseInstruction`. - * - * See the `BitwiseInstruction` documentation for more details. - */ -abstract class BitwiseOpcode extends Opcode { } - -/** - * The `Opcode` for a `BinaryBitwiseInstruction`. - * - * See the `BinaryBitwiseInstruction` documentation for more details. - */ -abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } - -/** - * The `Opcode` for a `UnaryBitwiseInstruction`. - * - * See the `UnaryBitwiseInstruction` documentation for more details. - */ -abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } - -/** - * The `Opcode` for a `CompareInstruction`. - * - * See the `CompareInstruction` documentation for more details. - */ -abstract class CompareOpcode extends BinaryOpcode { } - -/** - * The `Opcode` for a `RelationalInstruction`. - * - * See the `RelationalInstruction` documentation for more details. - */ -abstract class RelationalOpcode extends CompareOpcode { } - -/** - * The `Opcode` for a `CopyInstruction`. - * - * See the `CopyInstruction` documentation for more details. - */ -abstract class CopyOpcode extends Opcode { } - -/** - * The `Opcode` for a `ConvertToBaseInstruction`. - * - * See the `ConvertToBaseInstruction` documentation for more details. - */ -abstract class ConvertToBaseOpcode extends UnaryOpcode { } - -/** - * The `Opcode` for a `ReturnInstruction`. - * - * See the `ReturnInstruction` documentation for more details. - */ -abstract class ReturnOpcode extends Opcode { } - -/** - * The `Opcode` for a `ThrowInstruction`. - * - * See the `ThrowInstruction` documentation for more details. - */ -abstract class ThrowOpcode extends Opcode { } - -/** - * The `Opcode` for a `CatchInstruction`. - * - * See the `CatchInstruction` documentation for more details. - */ -abstract class CatchOpcode extends Opcode { } - -abstract private class OpcodeWithCondition extends Opcode { - final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } -} - -/** - * The `Opcode` for a `BuiltInOperationInstruction`. - * - * See the `BuiltInOperationInstruction` documentation for more details. - */ -abstract class BuiltInOperationOpcode extends Opcode { } - -/** - * The `Opcode` for a `SideEffectInstruction`. - * - * See the `SideEffectInstruction` documentation for more details. - */ -abstract class SideEffectOpcode extends Opcode { } - -/** - * An opcode that accesses a single memory location via an `AddressOperand`. - */ -abstract class IndirectMemoryAccessOpcode extends Opcode { - final override predicate hasAddressOperand() { any() } -} - -/** - * An opcode that writes to a single memory location via an `AddressOperand`. - */ -abstract class IndirectWriteOpcode extends IndirectMemoryAccessOpcode { - final override MemoryAccessKind getWriteMemoryAccess() { result instanceof IndirectMemoryAccess } -} - -/** - * An opcode that reads from a single memory location via an `AddressOperand`. - */ -abstract class IndirectReadOpcode extends IndirectMemoryAccessOpcode { - final override MemoryAccessKind getReadMemoryAccess() { result instanceof IndirectMemoryAccess } -} - -/** - * An opcode that accesses a memory buffer. - */ -abstract class BufferAccessOpcode extends Opcode { - final override predicate hasAddressOperand() { any() } -} - -/** - * An opcode that accesses a memory buffer of unknown size. - */ -abstract class UnsizedBufferAccessOpcode extends BufferAccessOpcode { } - -/** - * An opcode that writes to a memory buffer of unknown size. - */ -abstract class UnsizedBufferWriteOpcode extends UnsizedBufferAccessOpcode { - final override MemoryAccessKind getWriteMemoryAccess() { result instanceof BufferMemoryAccess } -} - -/** - * An opcode that reads from a memory buffer of unknown size. - */ -abstract class UnsizedBufferReadOpcode extends UnsizedBufferAccessOpcode { - final override MemoryAccessKind getReadMemoryAccess() { result instanceof BufferMemoryAccess } -} - -/** - * An opcode that access an entire memory allocation. - */ -abstract class EntireAllocationAccessOpcode extends Opcode { - final override predicate hasAddressOperand() { any() } -} - -/** - * An opcode that write to an entire memory allocation. - */ -abstract class EntireAllocationWriteOpcode extends EntireAllocationAccessOpcode { - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof EntireAllocationMemoryAccess - } -} - -/** - * An opcode that reads from an entire memory allocation. - */ -abstract class EntireAllocationReadOpcode extends EntireAllocationAccessOpcode { - final override MemoryAccessKind getReadMemoryAccess() { - result instanceof EntireAllocationMemoryAccess - } -} - -/** - * An opcode that accesses a memory buffer whose size is determined by a `BufferSizeOperand`. - */ -abstract class SizedBufferAccessOpcode extends BufferAccessOpcode { - final override predicate hasBufferSizeOperand() { any() } -} - -/** - * An opcode that writes to a memory buffer whose size is determined by a `BufferSizeOperand`. - */ -abstract class SizedBufferWriteOpcode extends SizedBufferAccessOpcode { - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof BufferMemoryAccess //TODO: SizedBufferMemoryAccess - } -} - -/** - * An opcode that reads from a memory buffer whose size is determined by a `BufferSizeOperand`. - */ -abstract class SizedBufferReadOpcode extends SizedBufferAccessOpcode { - final override MemoryAccessKind getReadMemoryAccess() { - result instanceof BufferMemoryAccess //TODO: SizedBufferMemoryAccess - } -} - -/** - * An opcode that might write to any escaped memory location. - */ -abstract class EscapedWriteOpcode extends Opcode { - final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } -} - -/** - * An opcode that might read from any escaped memory location. - */ -abstract class EscapedReadOpcode extends Opcode { - final override MemoryAccessKind getReadMemoryAccess() { result instanceof EscapedMemoryAccess } -} - -/** - * An opcode whose write memory access is a `may` write, as opposed to a `must` write. - */ -abstract class MayWriteOpcode extends Opcode { - final override predicate hasMayWriteMemoryAccess() { any() } -} - -/** - * An opcode whose read memory access is a `may` read, as opposed to a `must` read. - */ -abstract class MayReadOpcode extends Opcode { - final override predicate hasMayReadMemoryAccess() { any() } -} - -/** - * An opcode that reads a value from memory. - */ -abstract class OpcodeWithLoad extends IndirectReadOpcode { - final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LoadOperandTag } -} - -/** - * The `Opcode` for a `ReadSideEffectInstruction`. - * - * See the `ReadSideEffectInstruction` documentation for more details. - */ -abstract class ReadSideEffectOpcode extends SideEffectOpcode { - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof SideEffectOperandTag - } -} - -/** - * The `Opcode` for a `WriteSideEffectInstruction`. - * - * See the `WriteSideEffectInstruction` documentation for more details. - */ -abstract class WriteSideEffectOpcode extends SideEffectOpcode { } - -/** - * Provides `Opcode`s that specify the operation performed by an `Instruction`. - */ -module Opcode { - /** - * The `Opcode` for a `NoOpInstruction`. - * - * See the `NoOpInstruction` documentation for more details. - */ - class NoOp extends Opcode, TNoOp { - final override string toString() { result = "NoOp" } - } - - /** - * The `Opcode` for an `UninitializedInstruction`. - * - * See the `UninitializedInstruction` documentation for more details. - */ - class Uninitialized extends IndirectWriteOpcode, TUninitialized { - final override string toString() { result = "Uninitialized" } - } - - /** - * The `Opcode` for an `ErrorInstruction`. - * - * See the `ErrorInstruction` documentation for more details. - */ - class Error extends Opcode, TError { - final override string toString() { result = "Error" } - } - - /** - * The `Opcode` for an `InitializeParameterInstruction`. - * - * See the `InitializeParameterInstruction` documentation for more details. - */ - class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { - final override string toString() { result = "InitializeParameter" } - } - - /** - * The `Opcode` for an `InitializeIndirectionInstruction`. - * - * See the `InitializeIndirectionInstruction` documentation for more details. - */ - class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { - final override string toString() { result = "InitializeIndirection" } - } - - /** - * The `Opcode` for an `InitializeThisInstruction`. - * - * See the `InitializeThisInstruction` documentation for more details. - */ - class InitializeThis extends Opcode, TInitializeThis { - final override string toString() { result = "InitializeThis" } - } - - /** - * The `Opcode` for an `EnterFunctionInstruction`. - * - * See the `EnterFunctionInstruction` documentation for more details. - */ - class EnterFunction extends Opcode, TEnterFunction { - final override string toString() { result = "EnterFunction" } - } - - /** - * The `Opcode` for an `ExitFunctionInstruction`. - * - * See the `ExitFunctionInstruction` documentation for more details. - */ - class ExitFunction extends Opcode, TExitFunction { - final override string toString() { result = "ExitFunction" } - } - - /** - * The `Opcode` for a `ReturnValueInstruction`. - * - * See the `ReturnValueInstruction` documentation for more details. - */ - class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { - final override string toString() { result = "ReturnValue" } - } - - /** - * The `Opcode` for a `ReturnVoidInstruction`. - * - * See the `ReturnVoidInstruction` documentation for more details. - */ - class ReturnVoid extends ReturnOpcode, TReturnVoid { - final override string toString() { result = "ReturnVoid" } - } - - /** - * The `Opcode` for a `ReturnIndirectionInstruction`. - * - * See the `ReturnIndirectionInstruction` documentation for more details. - */ - class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { - final override string toString() { result = "ReturnIndirection" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof SideEffectOperandTag - } - } - - /** - * The `Opcode` for a `CopyValueInstruction`. - * - * See the `CopyValueInstruction` documentation for more details. - */ - class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { - final override string toString() { result = "CopyValue" } - } - - /** - * The `Opcode` for a `LoadInstruction`. - * - * See the `LoadInstruction` documentation for more details. - */ - class Load extends CopyOpcode, OpcodeWithLoad, TLoad { - final override string toString() { result = "Load" } - } - - /** - * The `Opcode` for a `StoreInstruction`. - * - * See the `StoreInstruction` documentation for more details. - */ - class Store extends CopyOpcode, IndirectWriteOpcode, TStore { - final override string toString() { result = "Store" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof StoreValueOperandTag - } - } - - /** - * The `Opcode` for an `AddInstruction`. - * - * See the `AddInstruction` documentation for more details. - */ - class Add extends BinaryArithmeticOpcode, TAdd { - final override string toString() { result = "Add" } - } - - /** - * The `Opcode` for a `SubInstruction`. - * - * See the `SubInstruction` documentation for more details. - */ - class Sub extends BinaryArithmeticOpcode, TSub { - final override string toString() { result = "Sub" } - } - - /** - * The `Opcode` for a `MulInstruction`. - * - * See the `MulInstruction` documentation for more details. - */ - class Mul extends BinaryArithmeticOpcode, TMul { - final override string toString() { result = "Mul" } - } - - /** - * The `Opcode` for a `DivInstruction`. - * - * See the `DivInstruction` documentation for more details. - */ - class Div extends BinaryArithmeticOpcode, TDiv { - final override string toString() { result = "Div" } - } - - /** - * The `Opcode` for a `RemInstruction`. - * - * See the `RemInstruction` documentation for more details. - */ - class Rem extends BinaryArithmeticOpcode, TRem { - final override string toString() { result = "Rem" } - } - - /** - * The `Opcode` for a `NegateInstruction`. - * - * See the `NegateInstruction` documentation for more details. - */ - class Negate extends UnaryArithmeticOpcode, TNegate { - final override string toString() { result = "Negate" } - } - - /** - * The `Opcode` for a `ShiftLeftInstruction`. - * - * See the `ShiftLeftInstruction` documentation for more details. - */ - class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { - final override string toString() { result = "ShiftLeft" } - } - - /** - * The `Opcode` for a `ShiftRightInstruction`. - * - * See the `ShiftRightInstruction` documentation for more details. - */ - class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { - final override string toString() { result = "ShiftRight" } - } - - /** - * The `Opcode` for a `UnsignedShiftRightInstruction`. - * - * See the `UnsignedShiftRightInstruction` documentation for more details. - */ - class UnsignedShiftRight extends BinaryBitwiseOpcode, TUnsignedShiftRight { - final override string toString() { result = "UnsignedShiftRight" } - } - - /** - * The `Opcode` for a `BitAndInstruction`. - * - * See the `BitAndInstruction` documentation for more details. - */ - class BitAnd extends BinaryBitwiseOpcode, TBitAnd { - final override string toString() { result = "BitAnd" } - } - - /** - * The `Opcode` for a `BitOrInstruction`. - * - * See the `BitOrInstruction` documentation for more details. - */ - class BitOr extends BinaryBitwiseOpcode, TBitOr { - final override string toString() { result = "BitOr" } - } - - /** - * The `Opcode` for a `BitXorInstruction`. - * - * See the `BitXorInstruction` documentation for more details. - */ - class BitXor extends BinaryBitwiseOpcode, TBitXor { - final override string toString() { result = "BitXor" } - } - - /** - * The `Opcode` for a `BitComplementInstruction`. - * - * See the `BitComplementInstruction` documentation for more details. - */ - class BitComplement extends UnaryBitwiseOpcode, TBitComplement { - final override string toString() { result = "BitComplement" } - } - - /** - * The `Opcode` for a `LogicalNotInstruction`. - * - * See the `LogicalNotInstruction` documentation for more details. - */ - class LogicalNot extends UnaryOpcode, TLogicalNot { - final override string toString() { result = "LogicalNot" } - } - - /** - * The `Opcode` for a `CompareEQInstruction`. - * - * See the `CompareEQInstruction` documentation for more details. - */ - class CompareEQ extends CompareOpcode, TCompareEQ { - final override string toString() { result = "CompareEQ" } - } - - /** - * The `Opcode` for a `CompareNEInstruction`. - * - * See the `CompareNEInstruction` documentation for more details. - */ - class CompareNE extends CompareOpcode, TCompareNE { - final override string toString() { result = "CompareNE" } - } - - /** - * The `Opcode` for a `CompareLTInstruction`. - * - * See the `CompareLTInstruction` documentation for more details. - */ - class CompareLT extends RelationalOpcode, TCompareLT { - final override string toString() { result = "CompareLT" } - } - - /** - * The `Opcode` for a `CompareGTInstruction`. - * - * See the `CompareGTInstruction` documentation for more details. - */ - class CompareGT extends RelationalOpcode, TCompareGT { - final override string toString() { result = "CompareGT" } - } - - /** - * The `Opcode` for a `CompareLEInstruction`. - * - * See the `CompareLEInstruction` documentation for more details. - */ - class CompareLE extends RelationalOpcode, TCompareLE { - final override string toString() { result = "CompareLE" } - } - - /** - * The `Opcode` for a `CompareGEInstruction`. - * - * See the `CompareGEInstruction` documentation for more details. - */ - class CompareGE extends RelationalOpcode, TCompareGE { - final override string toString() { result = "CompareGE" } - } - - /** - * The `Opcode` for a `PointerAddInstruction`. - * - * See the `PointerAddInstruction` documentation for more details. - */ - class PointerAdd extends PointerOffsetOpcode, TPointerAdd { - final override string toString() { result = "PointerAdd" } - } - - /** - * The `Opcode` for a `PointerSubInstruction`. - * - * See the `PointerSubInstruction` documentation for more details. - */ - class PointerSub extends PointerOffsetOpcode, TPointerSub { - final override string toString() { result = "PointerSub" } - } - - /** - * The `Opcode` for a `PointerDiffInstruction`. - * - * See the `PointerDiffInstruction` documentation for more details. - */ - class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { - final override string toString() { result = "PointerDiff" } - } - - /** - * The `Opcode` for a `ConvertInstruction`. - * - * See the `ConvertInstruction` documentation for more details. - */ - class Convert extends UnaryOpcode, TConvert { - final override string toString() { result = "Convert" } - } - - /** - * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. - * - * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. - */ - class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { - final override string toString() { result = "ConvertToNonVirtualBase" } - } - - /** - * The `Opcode` for a `ConvertToVirtualBaseInstruction`. - * - * See the `ConvertToVirtualBaseInstruction` documentation for more details. - */ - class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { - final override string toString() { result = "ConvertToVirtualBase" } - } - - /** - * The `Opcode` for a `ConvertToDerivedInstruction`. - * - * See the `ConvertToDerivedInstruction` documentation for more details. - */ - class ConvertToDerived extends UnaryOpcode, TConvertToDerived { - final override string toString() { result = "ConvertToDerived" } - } - - /** - * The `Opcode` for a `CheckedConvertOrNullInstruction`. - * - * See the `CheckedConvertOrNullInstruction` documentation for more details. - */ - class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { - final override string toString() { result = "CheckedConvertOrNull" } - } - - /** - * The `Opcode` for a `CheckedConvertOrThrowInstruction`. - * - * See the `CheckedConvertOrThrowInstruction` documentation for more details. - */ - class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { - final override string toString() { result = "CheckedConvertOrThrow" } - } - - /** - * The `Opcode` for a `CompleteObjectAddressInstruction`. - * - * See the `CompleteObjectAddressInstruction` documentation for more details. - */ - class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { - final override string toString() { result = "CompleteObjectAddress" } - } - - /** - * The `Opcode` for a `VariableAddressInstruction`. - * - * See the `VariableAddressInstruction` documentation for more details. - */ - class VariableAddress extends Opcode, TVariableAddress { - final override string toString() { result = "VariableAddress" } - } - - /** - * The `Opcode` for a `FieldAddressInstruction`. - * - * See the `FieldAddressInstruction` documentation for more details. - */ - class FieldAddress extends UnaryOpcode, TFieldAddress { - final override string toString() { result = "FieldAddress" } - } - - /** - * The `Opcode` for an `ElementsAddressInstruction`. - * - * See the `ElementsAddressInstruction` documentation for more details. - */ - class ElementsAddress extends UnaryOpcode, TElementsAddress { - final override string toString() { result = "ElementsAddress" } - } - - /** - * The `Opcode` for a `FunctionAddressInstruction`. - * - * See the `FunctionAddressInstruction` documentation for more details. - */ - class FunctionAddress extends Opcode, TFunctionAddress { - final override string toString() { result = "FunctionAddress" } - } - - /** - * The `Opcode` for a `VirtualDeleteFunctionAddress`. - * - * See the `VirtualDeleteFunctionAddressInstruction` documentation for more details. - */ - class VirtualDeleteFunctionAddress extends Opcode, TVirtualDeleteFunctionAddress { - final override string toString() { result = "VirtualDeleteFunctionAddress" } - } - - /** - * The `Opcode` for a `ConstantInstruction`. - * - * See the `ConstantInstruction` documentation for more details. - */ - class Constant extends Opcode, TConstant { - final override string toString() { result = "Constant" } - } - - /** - * The `Opcode` for a `StringConstantInstruction`. - * - * See the `StringConstantInstruction` documentation for more details. - */ - class StringConstant extends Opcode, TStringConstant { - final override string toString() { result = "StringConstant" } - } - - /** - * The `Opcode` for a `ConditionalBranchInstruction`. - * - * See the `ConditionalBranchInstruction` documentation for more details. - */ - class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { - final override string toString() { result = "ConditionalBranch" } - } - - /** - * The `Opcode` for a `SwitchInstruction`. - * - * See the `SwitchInstruction` documentation for more details. - */ - class Switch extends OpcodeWithCondition, TSwitch { - final override string toString() { result = "Switch" } - } - - /** - * The `Opcode` for a `CallInstruction`. - * - * See the `CallInstruction` documentation for more details. - */ - class Call extends Opcode, TCall { - final override string toString() { result = "Call" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof CallTargetOperandTag - } - } - - /** - * The `Opcode` for a `CatchByTypeInstruction`. - * - * See the `CatchByTypeInstruction` documentation for more details. - */ - class CatchByType extends CatchOpcode, TCatchByType { - final override string toString() { result = "CatchByType" } - } - - /** - * The `Opcode` for a `CatchAnyInstruction`. - * - * See the `CatchAnyInstruction` documentation for more details. - */ - class CatchAny extends CatchOpcode, TCatchAny { - final override string toString() { result = "CatchAny" } - } - - /** - * The `Opcode` for a `ThrowValueInstruction`. - * - * See the `ThrowValueInstruction` documentation for more details. - */ - class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { - final override string toString() { result = "ThrowValue" } - } - - /** - * The `Opcode` for a `ReThrowInstruction`. - * - * See the `ReThrowInstruction` documentation for more details. - */ - class ReThrow extends ThrowOpcode, TReThrow { - final override string toString() { result = "ReThrow" } - } - - /** - * The `Opcode` for an `UnwindInstruction`. - * - * See the `UnwindInstruction` documentation for more details. - */ - class Unwind extends Opcode, TUnwind { - final override string toString() { result = "Unwind" } - } - - /** - * The `Opcode` for an `AliasedDefinitionInstruction`. - * - * See the `AliasedDefinitionInstruction` documentation for more details. - */ - class AliasedDefinition extends Opcode, TAliasedDefinition { - final override string toString() { result = "AliasedDefinition" } - - final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } - } - - /** - * The `Opcode` for an `InitializeNonLocalInstruction`. - * - * See the `InitializeNonLocalInstruction` documentation for more details. - */ - class InitializeNonLocal extends Opcode, TInitializeNonLocal { - final override string toString() { result = "InitializeNonLocal" } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof NonLocalMemoryAccess - } - } - - /** - * The `Opcode` for an `AliasedUseInstruction`. - * - * See the `AliasedUseInstruction` documentation for more details. - */ - class AliasedUse extends Opcode, TAliasedUse { - final override string toString() { result = "AliasedUse" } - - final override MemoryAccessKind getReadMemoryAccess() { result instanceof NonLocalMemoryAccess } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof SideEffectOperandTag - } - } - - /** - * The `Opcode` for a `PhiInstruction`. - * - * See the `PhiInstruction` documentation for more details. - */ - class Phi extends Opcode, TPhi { - final override string toString() { result = "Phi" } - - final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } - } - - /** - * The `Opcode` for a `BuiltInInstruction`. - * - * See the `BuiltInInstruction` documentation for more details. - */ - class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { - final override string toString() { result = "BuiltIn" } - } - - /** - * The `Opcode` for a `VarArgsStartInstruction`. - * - * See the `VarArgsStartInstruction` documentation for more details. - */ - class VarArgsStart extends UnaryOpcode, TVarArgsStart { - final override string toString() { result = "VarArgsStart" } - } - - /** - * The `Opcode` for a `VarArgsEndInstruction`. - * - * See the `VarArgsEndInstruction` documentation for more details. - */ - class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { - final override string toString() { result = "VarArgsEnd" } - } - - /** - * The `Opcode` for a `VarArgInstruction`. - * - * See the `VarArgInstruction` documentation for more details. - */ - class VarArg extends UnaryOpcode, TVarArg { - final override string toString() { result = "VarArg" } - } - - /** - * The `Opcode` for a `NextVarArgInstruction`. - * - * See the `NextVarArgInstruction` documentation for more details. - */ - class NextVarArg extends UnaryOpcode, TNextVarArg { - final override string toString() { result = "NextVarArg" } - } - - /** - * The `Opcode` for a `CallSideEffectInstruction`. - * - * See the `CallSideEffectInstruction` documentation for more details. - */ - class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, - ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect - { - final override string toString() { result = "CallSideEffect" } - } - - /** - * The `Opcode` for a `CallReadSideEffectInstruction`. - * - * See the `CallReadSideEffectInstruction` documentation for more details. - */ - class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, - TCallReadSideEffect - { - final override string toString() { result = "CallReadSideEffect" } - } - - /** - * The `Opcode` for an `IndirectReadSideEffectInstruction`. - * - * See the `IndirectReadSideEffectInstruction` documentation for more details. - */ - class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, - TIndirectReadSideEffect - { - final override string toString() { result = "IndirectReadSideEffect" } - } - - /** - * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. - * - * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. - */ - class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, - TIndirectMustWriteSideEffect - { - final override string toString() { result = "IndirectMustWriteSideEffect" } - } - - /** - * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. - * - * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. - */ - class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, - MayWriteOpcode, TIndirectMayWriteSideEffect - { - final override string toString() { result = "IndirectMayWriteSideEffect" } - } - - /** - * The `Opcode` for a `BufferReadSideEffectInstruction`. - * - * See the `BufferReadSideEffectInstruction` documentation for more details. - */ - class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, - TBufferReadSideEffect - { - final override string toString() { result = "BufferReadSideEffect" } - } - - /** - * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. - * - * See the `BufferMustWriteSideEffectInstruction` documentation for more details. - */ - class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, - TBufferMustWriteSideEffect - { - final override string toString() { result = "BufferMustWriteSideEffect" } - } - - /** - * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. - * - * See the `BufferMayWriteSideEffectInstruction` documentation for more details. - */ - class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, - MayWriteOpcode, TBufferMayWriteSideEffect - { - final override string toString() { result = "BufferMayWriteSideEffect" } - } - - /** - * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. - * - * See the `SizedBufferReadSideEffectInstruction` documentation for more details. - */ - class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, - TSizedBufferReadSideEffect - { - final override string toString() { result = "SizedBufferReadSideEffect" } - } - - /** - * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. - * - * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. - */ - class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, - TSizedBufferMustWriteSideEffect - { - final override string toString() { result = "SizedBufferMustWriteSideEffect" } - } - - /** - * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. - * - * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. - */ - class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, - MayWriteOpcode, TSizedBufferMayWriteSideEffect - { - final override string toString() { result = "SizedBufferMayWriteSideEffect" } - } - - /** - * The `Opcode` for an `InitializeDynamicAllocationInstruction`. - * - * See the `InitializeDynamicAllocationInstruction` documentation for more details. - */ - class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, - TInitializeDynamicAllocation - { - final override string toString() { result = "InitializeDynamicAllocation" } - } - - /** - * The `Opcode` for a `ChiInstruction`. - * - * See the `ChiInstruction` documentation for more details. - */ - class Chi extends Opcode, TChi { - final override string toString() { result = "Chi" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof ChiTotalOperandTag - or - tag instanceof ChiPartialOperandTag - } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof ChiTotalMemoryAccess - } - } - - /** - * The `Opcode` for an `InlineAsmInstruction`. - * - * See the `InlineAsmInstruction` documentation for more details. - */ - class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, - MayReadOpcode, TInlineAsm - { - final override string toString() { result = "InlineAsm" } - - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof SideEffectOperandTag - } - } - - /** - * The `Opcode` for an `UnreachedInstruction`. - * - * See the `UnreachedInstruction` documentation for more details. - */ - class Unreached extends Opcode, TUnreached { - final override string toString() { result = "Unreached" } - } - - /** - * The `Opcode` for a `NewObjInstruction`. - * - * See the `NewObjInstruction` documentation for more details. - */ - class NewObj extends Opcode, TNewObj { - final override string toString() { result = "NewObj" } - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll deleted file mode 100644 index 5f230de560d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Defines the public interface to temporary variable tags, which describe the reason a particular - * `IRTempVariable` was generated. - */ - -private import internal.TempVariableTagInternal -private import Imports::TempVariableTag - -/** - * A reason that a particular IR temporary variable was generated. For example, it could be - * generated to hold the return value of a function, or to hold the result of a `?:` operator - * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. - */ -class TempVariableTag extends TTempVariableTag { - /** Gets a textual representation of this tag. */ - string toString() { result = getTempVariableTagId(this) } -} diff --git a/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll deleted file mode 100644 index b9b1dc243b1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll +++ /dev/null @@ -1,9 +0,0 @@ -import IRConfiguration - -/** - * Overrides the default IR configuration to use sound escape analysis, instead of assuming that - * variable addresses never escape. - */ -class SoundEscapeAnalysisConfiguration extends IREscapeAnalysisConfiguration { - override predicate useSoundEscapeAnalysis() { any() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll deleted file mode 100644 index 1efb7137147..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Provides a stub implementation of the required aliased SSA interface until we implement aliased - * SSA construction for C#. - */ - -private import IRFunctionBase -private import TInstruction - -module Ssa { - class MemoryLocation = boolean; - - predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) { - none() - } - - predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() } - - predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll deleted file mode 100644 index ebcc9573bce..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll deleted file mode 100644 index ebcc9573bce..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll deleted file mode 100644 index 571b0a12f49..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. - */ - -private import IRFunctionBaseInternal - -private newtype TIRFunction = - TFunctionIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } or - TVarInitIRFunction(Language::Variable var) { IRConstruction::Raw::varHasIRFunc(var) } - -/** - * The IR for a function. This base class contains only the predicates that are the same between all - * phases of the IR. Each instantiation of `IRFunction` extends this class. - */ -class IRFunctionBase extends TIRFunction { - Language::Declaration decl; - - IRFunctionBase() { - this = TFunctionIRFunction(decl) - or - this = TVarInitIRFunction(decl) - } - - /** Gets a textual representation of this element. */ - final string toString() { result = "IR: " + decl.toString() } - - /** Gets the function whose IR is represented. */ - final Language::Declaration getFunction() { result = decl } - - /** Gets the location of the function. */ - final Language::Location getLocation() { result = decl.getLocation() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll deleted file mode 100644 index f2da59bbb1d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBaseInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll deleted file mode 100644 index ebcc9573bce..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll deleted file mode 100644 index 8bacf51d8a2..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll deleted file mode 100644 index f2e23b01a13..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll +++ /dev/null @@ -1,300 +0,0 @@ -/** - * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` - * plays in the evaluation of its `Instruction`. - */ - -private import OperandTagInternal - -private newtype TOperandTag = - TAddressOperand() or - TBufferSizeOperand() or - TSideEffectOperand() or - TLoadOperand() or - TStoreValueOperand() or - TUnaryOperand() or - TLeftOperand() or - TRightOperand() or - TConditionOperand() or - TCallTargetOperand() or - TThisArgumentOperand() or - TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or - TChiTotalOperand() or - TChiPartialOperand() or - TAsmOperand(int index) { Language::hasAsmOperandIndex(index) } - -/** - * 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 { - /** Gets a textual representation of this operand tag */ - abstract string toString(); - - /** - * Gets an integer that represents where this this operand will appear in the operand list of an - * instruction when the IR is printed. - */ - abstract int getSortOrder(); - - /** - * Gets a label that will appear before the operand when the IR is printed. - */ - final string getLabel() { - if this.alwaysPrintLabel() then result = this.getId() + ":" else result = "" - } - - /** - * Gets an identifier that uniquely identifies this operand within its instruction. - */ - abstract string getId(); - - /** - * Holds if the operand should always be prefixed with its label in the dump of its instruction. - */ - predicate alwaysPrintLabel() { none() } -} - -/** - * 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 the IR is printed. -/** - * 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 predicate alwaysPrintLabel() { any() } - - final override string getId() { result = "&" } -} - -AddressOperandTag addressOperand() { result = TAddressOperand() } - -/** - * The buffer size operand of an instruction that represents a read or write of - * a buffer. - */ -class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { - final override string toString() { result = "BufferSize" } - - final override int getSortOrder() { result = 1 } - - final override string getId() { result = "size" } -} - -BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() } - -/** - * 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 } - - final override string getId() { result = "side_effect" } -} - -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 } - - final override string getId() { result = "load" } -} - -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 } - - final override string getId() { result = "store" } -} - -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 } - - final override string getId() { result = "unary" } -} - -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 } - - final override string getId() { result = "left" } -} - -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 } - - final override string getId() { result = "right" } -} - -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 } - - final override string getId() { result = "cond" } -} - -ConditionOperandTag conditionOperand() { result = TConditionOperand() } - -/** - * 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 predicate alwaysPrintLabel() { any() } - - final override string getId() { 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 predicate alwaysPrintLabel() { any() } - - final override string getId() { 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 predicate alwaysPrintLabel() { any() } - - final int getArgIndex() { result = argIndex } - - final override string getId() { result = argIndex.toString() } -} - -PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { - result = TPositionalArgumentOperand(argIndex) -} - -abstract class ChiOperandTag extends MemoryOperandTag { } - -class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { - final override string toString() { result = "ChiTotal" } - - final override int getSortOrder() { result = 13 } - - final override predicate alwaysPrintLabel() { any() } - - final override string getId() { result = "total" } -} - -ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } - -class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { - final override string toString() { result = "ChiPartial" } - - final override int getSortOrder() { result = 14 } - - final override predicate alwaysPrintLabel() { any() } - - final override string getId() { result = "partial" } -} - -ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() } - -class AsmOperandTag extends RegisterOperandTag, TAsmOperand { - int index; - - AsmOperandTag() { this = TAsmOperand(index) } - - final override string toString() { result = "AsmOperand(" + index + ")" } - - final override int getSortOrder() { result = 15 + index } - - final override predicate alwaysPrintLabel() { any() } - - final override string getId() { result = index.toString() } -} - -AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll deleted file mode 100644 index ebcc9573bce..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll deleted file mode 100644 index fe72263249f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll +++ /dev/null @@ -1,23 +0,0 @@ -private import TIRVariableInternal -private import Imports::TempVariableTag - -newtype TIRVariable = - TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Declaration func) { - Construction::hasUserVariable(func, var, type) - } or - TIRTempVariable( - Language::Declaration func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - Construction::hasTempVariable(func, ast, tag, type) - } or - TIRDynamicInitializationFlag( - Language::Declaration func, Language::Variable var, Language::LanguageType type - ) { - Construction::hasDynamicInitializationFlag(func, var, type) - } or - TIRStringLiteral( - Language::Declaration func, Language::AST ast, Language::LanguageType type, - Language::StringLiteral literal - ) { - Construction::hasStringLiteral(func, ast, type, literal) - } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll deleted file mode 100644 index e2b2c408a4f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll +++ /dev/null @@ -1,7 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction -private import experimental.ir.implementation.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll deleted file mode 100644 index bb3eb683653..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ /dev/null @@ -1,106 +0,0 @@ -private import TInstructionInternal -private import IRFunctionBase -private import TInstructionImports as Imports -private import Imports::IRType -private import Imports::Opcode - -/** - * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual - * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for - * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, - * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of - * all of the branches that can appear in that particular stage. The public `Instruction` class for - * each phase extends the `TStageInstruction` type for that stage. - */ -cached -newtype TInstruction = - TRawInstruction( - IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 - ) { - IRConstruction::Raw::hasInstruction(tag1, tag2) - } or - TRawUnreachedInstruction(IRFunctionBase irFunc) { - IRConstruction::hasUnreachedInstruction(irFunc) - } or - TUnaliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation - ) { - UnaliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) - } or - TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or - TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc) - } or - TAliasedSsaPhiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation - ) { - AliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation) - } or - TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) { - AliasedSsa::Ssa::hasChiInstruction(primaryInstruction) - } or - TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { - AliasedSsa::Ssa::hasUnreachedInstruction(irFunc) - } - -/** - * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the - * unaliased SSA stage. - * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via - * a class alias. - */ -module UnaliasedSsaInstructions { - class TPhiInstruction = TUnaliasedSsaPhiInstruction; - - TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation - ) { - result = TUnaliasedSsaPhiInstruction(blockStartInstr, memoryLocation) - } - - TRawInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) { none() } - - class TChiInstruction = TUnaliasedSsaChiInstruction; - - TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { - result = TUnaliasedSsaChiInstruction(primaryInstruction) - } - - class TUnreachedInstruction = TUnaliasedSsaUnreachedInstruction; - - TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { - result = TUnaliasedSsaUnreachedInstruction(irFunc) - } -} - -/** - * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the - * aliased SSA stage. - * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via - * a class alias. - */ -module AliasedSsaInstructions { - class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction; - - TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation - ) { - result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation) - } - - TPhiInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) { - result = TUnaliasedSsaPhiInstruction(blockStartInstr, _) - } - - class TChiInstruction = TAliasedSsaChiInstruction; - - TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { - result = TAliasedSsaChiInstruction(primaryInstruction) - } - - class TUnreachedInstruction = TAliasedSsaUnreachedInstruction; - - TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { - result = TAliasedSsaUnreachedInstruction(irFunc) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll deleted file mode 100644 index 6200f2a2796..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionImports.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.Opcode as Opcode diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll deleted file mode 100644 index 3778e532cef..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll +++ /dev/null @@ -1,4 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction -import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa -import AliasedSSAStub as AliasedSsa diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll deleted file mode 100644 index cf8a6a9b7b1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll +++ /dev/null @@ -1,150 +0,0 @@ -private import TInstruction -private import OperandTag -private import experimental.ir.implementation.raw.internal.IRConstruction as RawConstruction -private import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction -private import experimental.ir.implementation.raw.IR as Raw -private import experimental.ir.implementation.unaliased_ssa.IR as Unaliased -private import experimental.ir.internal.Overlap - -/** - * Provides the newtype used to represent operands across all phases of the IR. - */ -private module Internal { - /** - * An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this - * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`), - * for operands computed by each stage of SSA construction (`T*PhiOperand` and - * `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given - * stage of IR construction (`TNoOperand`). - */ - cached - newtype TOperand = - // RAW - TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) { - defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and - not RawConstruction::isInCycle(useInstr) and - strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - // Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions - TNoOperand() { none() } or - // Can be "removed" later when there's unreachable code - // These operands can be reused across all three stages. They just get different defs. - TNonSsaMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) { - // Has no definition in raw but will get definitions later - useInstr.getOpcode().hasOperand(tag) - } or - TUnaliasedPhiOperand( - Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, - Unaliased::IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } -} - -/** - * Reexports some branches from `TOperand` so they can be used in stage modules without importing - * `TOperand` itself. - */ -private module Shared { - class TRegisterOperand = Internal::TRegisterOperand; - - /** - * Returns the register operand with the specified parameters. - */ - TRegisterOperand registerOperand( - TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr - ) { - result = Internal::TRegisterOperand(useInstr, tag, defInstr) - } - - class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand; - - /** - * Returns the non-Phi memory operand with the specified parameters. - */ - TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { - result = Internal::TNonSsaMemoryOperand(useInstr, tag) - } -} - -/** - * Provides wrappers for the constructors of each branch of `TOperand` that is used by the - * raw IR stage. - * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via - * a class alias. - */ -module RawOperands { - import Shared - - class TPhiOperand = Internal::TNoOperand; - - class TChiOperand = Internal::TNoOperand; - - class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand; - - /** - * Returns the Phi operand with the specified parameters. - */ - TPhiOperand phiOperand( - Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock, - Overlap overlap - ) { - none() - } - - /** - * Returns the Phi operand with the specified parameters. - */ - TPhiOperand reusedPhiOperand( - Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock, - Overlap overlap - ) { - none() - } - - /** - * Returns the Chi operand with the specified parameters. - */ - TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() } -} - -/** - * Provides wrappers for the constructors of each branch of `TOperand` that is used by the - * unaliased SSA stage. - * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via - * a class alias. - */ -module UnaliasedSsaOperands { - import Shared - - class TPhiOperand = Internal::TUnaliasedPhiOperand; - - class TChiOperand = Internal::TNoOperand; - - class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand; - - /** - * Returns the Phi operand with the specified parameters. - */ - TPhiOperand phiOperand( - Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, - Unaliased::IRBlock predecessorBlock, Overlap overlap - ) { - result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) - } - - /** - * Returns the Phi operand with the specified parameters. - */ - TPhiOperand reusedPhiOperand( - Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, - Unaliased::IRBlock predecessorBlock, Overlap overlap - ) { - none() - } - - /** - * Returns the Chi operand with the specified parameters. - */ - TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll deleted file mode 100644 index 6d9f3e1e2db..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll +++ /dev/null @@ -1,6 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -private import experimental.ir.internal.TempVariableTag as TempVariableTag_ - -module Imports { - module TempVariableTag = TempVariableTag_; -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll deleted file mode 100644 index 79873d8366e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Provides classes that describe the Intermediate Representation (IR) of the program. - * - * The IR is a representation of the semantics of the program, with very little dependence on the - * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, - * and `++i` all have the same semantic effect, but appear in the AST as three different types of - * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental - * operations similar to: - * - * ``` - * r1(int*) = VariableAddress[i] // Compute the address of variable `i` - * r2(int) = Load &:r1, m0 // Load the value of `i` - * r3(int) = Constant[1] // An integer constant with the value `1` - * r4(int) = Add r2, r3 // Add `1` to the value of `i` - * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` - * ``` - * - * This allows IR-based analysis to focus on the fundamental operations, rather than having to be - * concerned with the various ways of expressing those operations in source code. - * - * The key classes in the IR are: - * - * - `IRFunction` - Contains the IR for an entire function definition, including all of that - * function's `Instruction`s, `IRBlock`s, and `IRVariables`. - * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be - * performed, the operands that produce the inputs to that operation, and the type of the result - * of the operation. Control flows from an `Instruction` to one of a set of successor - * `Instruction`s. - * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly - * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has - * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` - * that produces its value (its "definition"). - * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is - * created for each variable directly accessed by the function. In addition, `IRVariable`s are - * created to represent certain temporary storage locations that do not have explicitly declared - * variables in the source code, such as the return value of the function. - * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a - * sequence of instructions such that control flow can only enter the block at the first - * instruction, and can only leave the block from the last instruction. - * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` - * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all - * be represented as the `IRType` `uint4`, a four-byte unsigned integer. - */ - -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * A class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - /** Gets a textual representation of this element. */ - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified operand. - */ - string getOperandProperty(Operand operand, string key) { none() } - - /** - * Holds if the instruction `instr` should be included when printing - * the IR instructions. - */ - predicate shouldPrintInstruction(Instruction instr) { any() } - - /** - * Holds if the operand `operand` should be included when printing the an - * instruction's operand list. - */ - predicate shouldPrintOperand(Operand operand) { any() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll deleted file mode 100644 index 50395db47e7..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ /dev/null @@ -1,356 +0,0 @@ -/** - * Provides classes describing basic blocks in the IR of a function. - */ - -private import internal.IRInternal -import Instruction -private import internal.IRBlockImports as Imports -import Imports::EdgeKind -private import Cached - -/** - * Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the - * sort keys of the block (derived from its first instruction) - */ -pragma[nomagic] -private predicate blockSortKeys( - IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2 -) { - block.getEnclosingIRFunction() = func and - block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and - // Ensure that the block containing `EnterFunction` always comes first. - if block.getFirstInstruction() instanceof EnterFunctionInstruction - then sortOverride = 0 - else sortOverride = 1 -} - -/** - * A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only - * incoming edges at the beginning of the sequence and the only outgoing edges at the end of the - * sequence. - * - * This class does not contain any members that query the predecessor or successor edges of the - * block. This allows different classes that extend `IRBlockBase` to expose different subsets of - * edges (e.g. ignoring unreachable edges). - * - * Most consumers should use the class `IRBlock`. - */ -class IRBlockBase extends TIRBlock { - /** Gets a textual representation of this block. */ - final string toString() { result = getFirstInstruction(this).toString() } - - /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } - - /** - * INTERNAL: Do not use. - * - * Gets the zero-based index of the block within its function. - * - * This predicate is used by debugging and printing code only. - */ - int getDisplayIndex() { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) - ) and - exists(IRFunction func | - this = - rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2) - | - funcBlock order by sortOverride, sortKey1, sortKey2 - ) - ) - } - - /** - * Gets the `index`th non-`Phi` instruction in this block. - */ - final Instruction getInstruction(int index) { result = getInstruction(this, index) } - - /** - * Get the `Phi` instructions that appear at the start of this block. - */ - final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() - } - - /** - * Gets an instruction in this block. This includes `Phi` instructions. - */ - final Instruction getAnInstruction() { - result = this.getInstruction(_) or - result = this.getAPhiInstruction() - } - - /** - * Gets the first non-`Phi` instruction in this block. - */ - final Instruction getFirstInstruction() { result = getFirstInstruction(this) } - - /** - * Gets the last instruction in this block. - */ - final Instruction getLastInstruction() { - result = this.getInstruction(this.getInstructionCount() - 1) - } - - /** - * Gets the number of non-`Phi` instructions in this block. - */ - final int getInstructionCount() { result = getInstructionCount(this) } - - /** - * Gets the `IRFunction` that contains this block. - */ - final IRFunction getEnclosingIRFunction() { - result = getFirstInstruction(this).getEnclosingIRFunction() - } - - /** - * Gets the `Function` that contains this block. - */ - final Language::Declaration getEnclosingFunction() { - result = getFirstInstruction(this).getEnclosingFunction() - } -} - -/** - * A basic block with additional information about its predecessor and successor edges. Each edge - * corresponds to the control flow between the last instruction of one block and the first - * instruction of another block. - */ -class IRBlock extends IRBlockBase { - /** - * Gets a block to which control flows directly from this block. - */ - final IRBlock getASuccessor() { blockSuccessor(this, result) } - - /** - * Gets a block from which control flows directly to this block. - */ - final IRBlock getAPredecessor() { blockSuccessor(result, this) } - - /** - * Gets the block to which control flows directly from this block along an edge of kind `kind`. - */ - final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } - - /** - * Gets the block to which control flows directly from this block along a back edge of kind - * `kind`. - */ - final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } - - /** - * Holds if this block immediately dominates `block`. - * - * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` - * is a direct successor of block `A`. - */ - final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } - - /** - * Holds if this block strictly dominates `block`. - * - * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` - * are not the same block. - */ - final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } - - /** - * Holds if this block dominates `block`. - * - * Block `A` dominates block `B` if any control flow path from the entry block of the function to - * block `B` must pass through block `A`. A block always dominates itself. - */ - final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } - - /** - * Gets a block on the dominance frontier of this block. - * - * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not - * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. - */ - pragma[noinline] - final IRBlock dominanceFrontier() { - this.getASuccessor() = result and - not this.immediatelyDominates(result) - or - exists(IRBlock prev | result = prev.dominanceFrontier() | - this.immediatelyDominates(prev) and - not this.immediatelyDominates(result) - ) - } - - /** - * Holds if this block immediately post-dominates `block`. - * - * Block `A` immediate post-dominates block `B` if block `A` strictly post-dominates block `B` and - * block `B` is a direct successor of block `A`. - */ - final predicate immediatelyPostDominates(IRBlock block) { - blockImmediatelyPostDominates(this, block) - } - - /** - * Holds if this block strictly post-dominates `block`. - * - * Block `A` strictly post-dominates block `B` if block `A` post-dominates block `B` and blocks `A` - * and `B` are not the same block. - */ - final predicate strictlyPostDominates(IRBlock block) { - blockImmediatelyPostDominates+(this, block) - } - - /** - * Holds if this block is a post-dominator of `block`. - * - * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the - * function must pass through block `A`. A block always post-dominates itself. - */ - final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } - - /** - * Gets a block on the post-dominance frontier of this block. - * - * The post-dominance frontier of block `A` is the set of blocks `B` such that block `A` does not - * post-dominate block `B`, but block `A` does post-dominate an immediate successor of block `B`. - */ - pragma[noinline] - final IRBlock postDominanceFrontier() { - this.getAPredecessor() = result and - not this.immediatelyPostDominates(result) - or - exists(IRBlock prev | result = prev.postDominanceFrontier() | - this.immediatelyPostDominates(prev) and - not this.immediatelyPostDominates(result) - ) - } - - /** - * Holds if this block is reachable from the entry block of its function. - */ - final predicate isReachableFromFunctionEntry() { - this = this.getEnclosingIRFunction().getEntryBlock() or - this.getAPredecessor().isReachableFromFunctionEntry() - } -} - -private predicate startsBasicBlock(Instruction instr) { - not instr instanceof PhiInstruction and - not adjacentInBlock(_, instr) -} - -/** Holds if `i2` follows `i1` in a `IRBlock`. */ -private predicate adjacentInBlock(Instruction i1, Instruction i2) { - // - i2 must be the only successor of i1 - i2 = unique(Instruction i | i = i1.getASuccessor()) and - // - i1 must be the only predecessor of i2 - i1 = unique(Instruction i | i.getASuccessor() = i2) and - // - The edge between the two must be a GotoEdge. We just check that one - // exists since we've already checked that it's unique. - exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and - // - The edge must not be a back edge. This means we get the same back edges - // in the basic-block graph as we do in the raw CFG. - not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) - // This predicate could be simplified to remove one of the `unique`s if we - // were willing to rely on the CFG being well-formed and thus never having - // more than one successor to an instruction that has a `GotoEdge` out of it. -} - -private predicate isEntryBlock(TIRBlock block) { - block = MkIRBlock(any(EnterFunctionInstruction enter)) -} - -cached -private module Cached { - cached - newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ - private Instruction getInstructionFromFirst(Instruction first, int index) = - shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) - - /** Holds if `i` is the `index`th instruction in `block`. */ - cached - Instruction getInstruction(TIRBlock block, int index) { - result = getInstructionFromFirst(getFirstInstruction(block), index) - } - - cached - int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) } - - cached - predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - exists(Instruction predLast, Instruction succFirst | - predLast = getInstruction(pred, getInstructionCount(pred) - 1) and - succFirst = predLast.getSuccessor(kind) and - succ = MkIRBlock(succFirst) - ) - } - - pragma[noinline] - private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 } - - pragma[noopt] - cached - predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - backEdgeSuccessorRaw(pred, succ, kind) - or - // See the QLDoc on `backEdgeSuccessorRaw`. - exists(TIRBlock pred2 | - // Joining with `blockIdentity` is a performance trick to get - // `forwardEdgeRaw` on the RHS of a join, where it's fast. - blockIdentity(pred, pred2) and - forwardEdgeRaw+(pred, pred2) - ) and - blockSuccessor(pred, succ, kind) - } - - /** - * Holds if there is an edge from `pred` to `succ` that is not a back edge. - */ - private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) { - exists(EdgeKind kind | - blockSuccessor(pred, succ, kind) and - not backEdgeSuccessorRaw(pred, succ, kind) - ) - } - - /** - * Holds if the `kind`-edge from `pred` to `succ` is a back edge according to - * `Construction`. - * - * There could be loops of non-back-edges if there is a flaw in the IR - * construction or back-edge detection, and this could cause non-termination - * of subsequent analysis. To prevent that, a subsequent predicate further - * classifies all edges as back edges if they are involved in a loop of - * non-back-edges. - */ - private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - exists(Instruction predLast, Instruction succFirst | - predLast = getInstruction(pred, getInstructionCount(pred) - 1) and - succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and - succ = MkIRBlock(succFirst) - ) - } - - cached - predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) } - - cached - predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) = - idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) -} - -private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } - -private predicate blockFunctionExit(IRBlock exit) { - exit.getLastInstruction() instanceof ExitFunctionInstruction -} - -private predicate blockPredecessor(IRBlock src, IRBlock pred) { src.getAPredecessor() = pred } - -private predicate blockImmediatelyPostDominates(IRBlock postDominator, IRBlock block) = - idominance(blockFunctionExit/1, blockPredecessor/2)(_, postDominator, block) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql deleted file mode 100644 index 342e84a2b5e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Raw IR Consistency Check - * @description Performs consistency checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cs/raw-ir-consistency-check - */ - -import IRConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll deleted file mode 100644 index edc785dfabe..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll +++ /dev/null @@ -1,549 +0,0 @@ -private import IR -import InstructionConsistency // module is below -import IRTypeConsistency // module is in IRType.qll -import internal.IRConsistencyImports - -module InstructionConsistency { - private import internal.InstructionImports as Imports - private import Imports::OperandTag - private import Imports::Overlap - private import internal.IRInternal - - private newtype TOptionalIRFunction = - TPresentIRFunction(IRFunction irFunc) or - TMissingIRFunction() - - /** - * An `IRFunction` that might not exist. This is used so that we can produce consistency failures - * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. - */ - abstract private class OptionalIRFunction extends TOptionalIRFunction { - abstract string toString(); - - abstract Language::Location getLocation(); - } - - class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { - private IRFunction irFunc; - - PresentIRFunction() { this = TPresentIRFunction(irFunc) } - - override string toString() { - result = concat(LanguageDebug::getIdentityString(irFunc.getFunction()), "; ") - } - - override Language::Location getLocation() { - // To avoid an overwhelming number of results when the extractor merges functions with the - // same name, just pick a single location. - result = - min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) - } - - IRFunction getIRFunction() { result = irFunc } - } - - private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { - override string toString() { result = "" } - - override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } - } - - private OptionalIRFunction getInstructionIRFunction(Instruction instr) { - result = TPresentIRFunction(instr.getEnclosingIRFunction()) - or - not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - pragma[inline] - private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { - result = getInstructionIRFunction(instr) and - irFuncText = result.toString() - } - - private OptionalIRFunction getOperandIRFunction(Operand operand) { - result = TPresentIRFunction(operand.getEnclosingIRFunction()) - or - not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - pragma[inline] - private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { - result = getOperandIRFunction(operand) and - irFuncText = result.toString() - } - - private OptionalIRFunction getBlockIRFunction(IRBlock block) { - result = TPresentIRFunction(block.getEnclosingIRFunction()) - or - not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - /** - * Holds if instruction `instr` is missing an expected operand with tag `tag`. - */ - query predicate missingOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag | - instr.getOpcode().hasOperand(tag) and - not exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - message = - "Instruction '" + instr.getOpcode().toString() + - "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if instruction `instr` has an unexpected operand with tag `tag`. - */ - query predicate unexpectedOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag | - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and - message = - "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + - "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if instruction `instr` has multiple operands with tag `tag`. - */ - query predicate duplicateOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag, int operandCount | - operandCount = - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - operandCount > 1 and - message = - "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if `Phi` instruction `instr` is missing an operand corresponding to - * the predecessor block `pred`. - */ - query predicate missingPhiOperand( - PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRBlock pred | - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred - ) and - message = - "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + - pred.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - query predicate missingOperandType( - Operand operand, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Instruction use | - not exists(operand.getType()) and - use = operand.getUse() and - message = - "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' is missing a type in function '$@'." and - irFunc = getOperandIRFunction(operand, irFuncText) - ) - } - - query predicate duplicateChiOperand( - ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText - ) { - chi.getTotal() = chi.getPartial() and - message = - "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function '$@'." and - irFunc = getInstructionIRFunction(chi, irFuncText) - } - - query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(instr.getPrimaryInstruction()) and - message = - "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if an instruction, other than `ExitFunction`, has no successors. - */ - query predicate instructionWithoutSuccessor( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(instr.getASuccessor()) and - not instr instanceof ExitFunctionInstruction and - // Phi instructions aren't linked into the instruction-level flow graph. - not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction and - message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if there are multiple edges of the same kind from `source`. - */ - query predicate ambiguousSuccessors( - Instruction source, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(EdgeKind kind, int n | - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - message = - "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + - kind.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(source, irFuncText) - ) - } - - /** - * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function - * contains no element that can cause loops. - */ - query predicate unexplainedLoop( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Language::Function f | - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) and - message = - "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if a `Phi` instruction is present in a block with fewer than two - * predecessors. - */ - query predicate unnecessaryPhiInstruction( - PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int n | - n = count(instr.getBlock().getAPredecessor()) and - n < 2 and - message = - "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + - " predecessors in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if a memory operand is connected to a definition with an unmodeled result. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - def = operand.getAnyDef() and - not def.isResultModeled() and - message = - "Memory operand definition on instruction '" + instr.toString() + - "' has unmodeled result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if operand `operand` consumes a value that was defined in - * a different function. - */ - query predicate operandAcrossFunctions( - Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, - OptionalIRFunction defIRFunc, string defIRFuncText - ) { - exists(Instruction useInstr, Instruction defInstr | - operand.getUse() = useInstr and - operand.getAnyDef() = defInstr and - useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and - defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and - useIRFunc != defIRFunc and - message = - "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + - "' in function '$@', but is defined on instruction '" + defInstr.toString() + - "' in function '$@'." - ) - } - - /** - * Holds if instruction `instr` is not in exactly one block. - */ - query predicate instructionWithoutUniqueBlock( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int blockCount | - blockCount = count(instr.getBlock()) and - blockCount != 1 and - message = - "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + - " blocks in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - private predicate forwardEdge(IRBlock b1, IRBlock b2) { - b1.getASuccessor() = b2 and - not b1.getBackEdgeSuccessor(_) = b2 - } - - /** - * Holds if `f` contains a loop in which no edge is a back edge. - * - * This check ensures we don't have too _few_ back edges. - */ - query predicate containsLoopOfForwardEdges(IRFunction f, string message) { - exists(IRBlock block | - forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f and - message = "Function contains a loop consisting of only forward edges." - ) - } - - /** - * Holds if `block` is reachable from its function entry point but would not - * be reachable by traversing only forward edges. This check is skipped for - * functions containing `goto` statements as the property does not generally - * hold there. - * - * This check ensures we don't have too _many_ back edges. - */ - query predicate lostReachability( - IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRFunction f, IRBlock entry | - entry = f.getEntryBlock() and - entry.getASuccessor+() = block and - not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) and - message = - "Block '" + block.toString() + - "' is not reachable by traversing only forward edges in function '$@'." and - irFunc = TPresentIRFunction(f) and - irFuncText = irFunc.toString() - ) - } - - /** - * Holds if the number of back edges differs between the `Instruction` graph - * and the `IRBlock` graph. - */ - query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { - exists(int fromInstr, int fromBlock | - fromInstr = - count(Instruction i1, Instruction i2 | - getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock and - message = - "The instruction graph for function '" + irFunc.toString() + "' contains " + - fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() - + " back edges." - ) - } - - /** - * 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, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - 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 - irFunc = getOperandIRFunction(useOperand, irFuncText) - ) - } - - query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - irFunc = getInstructionIRFunction(switchInstr, irFuncText) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - shouldBeConflated(instr) and - not instr.isResultConflated() and - message = - "Instruction '" + instr.toString() + - "' should be marked as having a conflated result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate wronglyMarkedAsConflated( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - instr.isResultConflated() and - not shouldBeConflated(instr) and - message = - "Instruction '" + instr.toString() + - "' should not be marked as having a conflated result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - irFunc = getOperandIRFunction(useOperand, irFuncText) - ) - } - - query predicate nonUniqueEnclosingIRFunction( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int irFuncCount | - irFuncCount = count(instr.getEnclosingIRFunction()) and - irFuncCount != 1 and - message = - "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + - " results for `getEnclosingIRFunction()` in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if the object address operand for the given `FieldAddress` instruction does not have an - * address type. - */ - query predicate fieldAddressOnNonPointer( - FieldAddressInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not instr.getObjectAddressOperand().getIRType() instanceof IRAddressType and - message = - "FieldAddress instruction '" + instr.toString() + - "' has an object address operand that is not an address, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if the `this` argument operand for the given `Call` instruction does not have an address - * type. - */ - query predicate thisArgumentIsNonPointer( - CallInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(ThisArgumentOperand thisOperand | thisOperand = instr.getThisArgumentOperand() | - not thisOperand.getIRType() instanceof IRAddressType - ) and - message = - "Call instruction '" + instr.toString() + - "' has a `this` argument operand that is not an address, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate nonUniqueIRVariable( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(VariableInstruction vi, IRVariable v1, IRVariable v2 | - instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2 - ) and - message = - "Variable instruction '" + instr.toString() + - "' has multiple associated variables, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - or - instr.getOpcode() instanceof Opcode::VariableAddress and - not instr instanceof VariableInstruction and - message = - "Variable address instruction '" + instr.toString() + - "' has no associated variable, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll deleted file mode 100644 index 354ba41e3d1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Provides the class `IRFunction`, which represents the Intermediate Representation for the - * definition of a function. - */ - -private import internal.IRInternal -private import internal.IRFunctionImports as Imports -import Imports::IRFunctionBase -import Instruction - -/** - * The IR for a function. - */ -class IRFunction extends IRFunctionBase { - /** - * Gets the entry point for this function. - */ - pragma[noinline] - final EnterFunctionInstruction getEnterFunctionInstruction() { - result.getEnclosingIRFunction() = this - } - - /** - * Gets the exit point for this function. - */ - pragma[noinline] - final ExitFunctionInstruction getExitFunctionInstruction() { - result.getEnclosingIRFunction() = this - } - - /** - * Gets the single return instruction for this function. - */ - pragma[noinline] - final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this } - - /** - * Gets the variable used to hold the return value of this function. If this - * function does not return a value, this predicate does not hold. - */ - pragma[noinline] - final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this } - - /** - * Gets the block containing the entry point of this function. - */ - pragma[noinline] - final IRBlock getEntryBlock() { - result.getFirstInstruction() = this.getEnterFunctionInstruction() - } - - /** - * Gets all instructions in this function. - */ - final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this } - - /** - * Gets all blocks in this function. - */ - final IRBlock getABlock() { result.getEnclosingIRFunction() = this } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll deleted file mode 100644 index b31c7898ba7..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ /dev/null @@ -1,337 +0,0 @@ -/** - * Provides classes that represent variables accessed by the IR. - */ - -private import internal.IRInternal -import IRFunction -private import internal.IRVariableImports as Imports -import Imports::TempVariableTag -private import Imports::IRUtilities -private import Imports::TTempVariableTag -private import Imports::TIRVariable -private import Imports::IRType - -/** - * A variable referenced by the IR for a function. - * - * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated - * by the AST-to-IR translation (`IRTempVariable`). - */ -class IRVariable extends TIRVariable { - Language::Declaration func; - - IRVariable() { - this = TIRUserVariable(_, _, func) or - this = TIRTempVariable(func, _, _, _) or - this = TIRStringLiteral(func, _, _, _) or - this = TIRDynamicInitializationFlag(func, _, _) - } - - /** Gets a textual representation of this element. */ - string toString() { none() } - - /** - * Holds if this variable's value cannot be changed within a function. Currently used for string - * literals, but could also apply to `const` global and static variables. - */ - predicate isReadOnly() { none() } - - /** - * Gets the type of the variable. - */ - final Language::Type getType() { this.getLanguageType().hasType(result, false) } - - /** - * Gets the language-neutral type of the variable. - */ - final IRType getIRType() { result = this.getLanguageType().getIRType() } - - /** - * Gets the type of the variable. - */ - Language::LanguageType getLanguageType() { none() } - - /** - * Gets the AST node that declared this variable, or that introduced this - * variable as part of the AST-to-IR translation. - */ - Language::AST getAst() { none() } - - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - - /** - * Gets an identifier string for the variable. This identifier is unique - * within the function. - */ - string getUniqueId() { none() } - - /** - * Gets the source location of this variable. - */ - final Language::Location getLocation() { result = this.getAst().getLocation() } - - /** - * Gets the IR for the function that references this variable. - */ - final IRFunction getEnclosingIRFunction() { result.getFunction() = func } - - /** - * Gets the function that references this variable. - */ - final Language::Declaration getEnclosingFunction() { result = func } -} - -/** - * A user-declared variable referenced by the IR for a function. - */ -class IRUserVariable extends IRVariable, TIRUserVariable { - Language::Variable var; - Language::LanguageType type; - - IRUserVariable() { this = TIRUserVariable(var, type, func) } - - final override string toString() { result = this.getVariable().toString() } - - final override Language::AST getAst() { result = var } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - - final override string getUniqueId() { - result = this.getVariable().toString() + " " + this.getVariable().getLocation().toString() - } - - final override Language::LanguageType getLanguageType() { result = type } - - /** - * Gets the original user-declared variable. - */ - Language::Variable getVariable() { result = var } -} - -/** - * A variable (user-declared or temporary) that is allocated on the stack. This includes all - * parameters, non-static local variables, and temporary variables. - */ -class IRAutomaticVariable extends IRVariable { - IRAutomaticVariable() { - exists(Language::Variable var | - this = TIRUserVariable(var, _, func) and - Language::isVariableAutomatic(var) - ) - or - this = TIRTempVariable(func, _, _, _) - } -} - -/** - * A user-declared variable that is allocated on the stack. This includes all parameters and - * non-static local variables. - */ -class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { - override Language::AutomaticVariable var; - - final override Language::AutomaticVariable getVariable() { result = var } -} - -/** - * A user-declared variable that is not allocated on the stack. This includes all global variables, - * namespace-scope variables, static fields, and static local variables. - */ -class IRStaticUserVariable extends IRUserVariable { - override Language::StaticVariable var; - - IRStaticUserVariable() { not Language::isVariableAutomatic(var) } - - final override Language::StaticVariable getVariable() { result = var } -} - -/** - * A variable that is not user-declared. This includes temporary variables generated as part of IR - * construction, as well as string literals. - */ -class IRGeneratedVariable extends IRVariable { - Language::AST ast; - Language::LanguageType type; - - IRGeneratedVariable() { - this = TIRTempVariable(func, ast, _, type) or - this = TIRStringLiteral(func, ast, type, _) or - this = TIRDynamicInitializationFlag(func, ast, type) - } - - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAst() { result = ast } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - - override string toString() { result = this.getBaseString() + this.getLocationString() } - - override string getUniqueId() { none() } - - /** - * INTERNAL: Do not use. - * - * Gets a string containing the source code location of the AST that generated this variable. - * - * This is used by debugging and printing code only. - */ - final string getLocationString() { - result = - ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - /** - * INTERNAL: Do not use. - * - * Gets the string that is combined with the location of the variable to generate the string - * representation of this variable. - * - * This is used by debugging and printing code only. - */ - string getBaseString() { none() } -} - -/** - * A temporary variable introduced by IR construction. The most common examples are the variable - * generated to hold the return value of a function, or the variable generated to hold the result of - * a condition operator (`a ? b : c`). - */ -class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { - TempVariableTag tag; - - IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - - final override string getUniqueId() { - result = "Temp: " + Construction::getTempVariableUniqueId(this) - } - - /** - * Gets the "tag" object that differentiates this temporary variable from other temporary - * variables generated for the same AST. - */ - final TempVariableTag getTag() { result = tag } - - override string getBaseString() { result = "#temp" } -} - -/** - * A temporary variable generated to hold the return value of a function. - */ -class IRReturnVariable extends IRTempVariable { - IRReturnVariable() { tag = ReturnValueTempVar() } - - final override string toString() { result = "#return" } -} - -/** - * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. - */ -class IRThrowVariable extends IRTempVariable { - IRThrowVariable() { tag = ThrowTempVar() } - - final override string getBaseString() { result = "#throw" } -} - -/** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. - */ -class IREllipsisVariable extends IRTempVariable, IRParameter { - IREllipsisVariable() { tag = EllipsisTempVar() } - - final override string toString() { result = "#ellipsis" } - - final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() } -} - -/** - * A temporary variable generated to hold the `this` pointer. - */ -class IRThisVariable extends IRTempVariable, IRParameter { - IRThisVariable() { tag = ThisTempVar() } - - final override string toString() { result = "#this" } - - final override int getIndex() { result = -1 } -} - -/** - * A variable generated to represent the contents of a string literal. This variable acts much like - * a read-only global variable. - */ -class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { - Language::StringLiteral literal; - - IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } - - final override predicate isReadOnly() { any() } - - final override string getUniqueId() { - result = "String: " + this.getLocationString() + "=" + Language::getStringLiteralText(literal) - } - - final override string getBaseString() { result = "#string" } - - /** - * Gets the AST of the string literal represented by this `IRStringLiteral`. - */ - final Language::StringLiteral getLiteral() { result = literal } -} - -/** - * A variable generated to track whether a specific non-stack variable has been initialized. This is - * used to model the runtime initialization of static local variables in C++, as well as static - * fields in C#. - */ -class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag { - Language::Variable var; - - IRDynamicInitializationFlag() { - this = TIRDynamicInitializationFlag(func, var, type) and ast = var - } - - final override string toString() { result = var.toString() + "#init" } - - /** - * Gets variable whose initialization is guarded by this flag. - */ - final Language::Variable getVariable() { result = var } - - final override string getUniqueId() { - result = - "Init: " + this.getVariable().toString() + " " + this.getVariable().getLocation().toString() - } - - final override string getBaseString() { result = "#init:" + var.toString() + ":" } -} - -/** - * An IR variable which acts like a function parameter, including positional parameters and the - * temporary variables generated for `this` and ellipsis parameters. - */ -class IRParameter extends IRAutomaticVariable { - IRParameter() { - this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter - or - this = TIRTempVariable(_, _, ThisTempVar(), _) - or - this = TIRTempVariable(_, _, EllipsisTempVar(), _) - } - - /** - * Gets the zero-based index of this parameter. The `this` parameter has index -1. - */ - int getIndex() { none() } -} - -/** - * An IR variable representing a positional parameter. - */ -class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { - final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll deleted file mode 100644 index 189ffce2903..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ /dev/null @@ -1,2231 +0,0 @@ -/** - * Provides classes that represent the individual instructions in the IR for a function. - */ - -private import internal.IRInternal -import IRFunction -import IRBlock -import IRVariable -import Operand -private import internal.InstructionImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind -import Imports::Opcode -private import Imports::OperandTag - -/** - * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified - * `File` and line number. Used for assigning register names when printing IR. - */ -private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(irFunc.getFunction()) - ) and - exists(Language::Location location | - irFunc = result.getEnclosingIRFunction() and - location = result.getLocation() and - file = location.getFile() and - line = location.getStartLine() - ) -} - -/** - * A single instruction in the IR. - */ -class Instruction extends Construction::TStageInstruction { - Instruction() { - // The base `TStageInstruction` type is a superset of the actual instructions appearing in this - // stage. This call lets the stage filter out the ones that are not reused from raw IR. - Construction::hasInstruction(this) - } - - /** Gets a textual representation of this element. */ - final string toString() { result = this.getOpcode().toString() + ": " + this.getAst().toString() } - - /** - * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what - * would be printed by PrintIR.ql. For example: - * - * `mu0_28(int) = Store r0_26, r0_27` - */ - final string getDumpString() { - result = - this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() - } - - private predicate shouldGenerateDumpStrings() { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) - ) - } - - /** - * Gets a string describing the operation of this instruction. This includes - * the opcode and the immediate value, if any. For example: - * - * VariableAddress[x] - */ - final string getOperationString() { - this.shouldGenerateDumpStrings() and - if exists(this.getImmediateString()) - then - result = - this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + - "]" - else result = this.getOperationPrefix() + this.getOpcode().toString() - } - - /** - * Gets a string describing the immediate value of this instruction, if any. - */ - string getImmediateString() { none() } - - private string getOperationPrefix() { - this.shouldGenerateDumpStrings() and - if this instanceof SideEffectInstruction then result = "^" else result = "" - } - - private string getResultPrefix() { - this.shouldGenerateDumpStrings() and - if this.getResultIRType() instanceof IRVoidType - then result = "v" - else - if this.hasMemoryResult() - then if this.isResultModeled() then result = "m" else result = "mu" - else result = "r" - } - - /** - * Gets the zero-based index of this instruction within its block. This is - * used by debugging and printing code only. - */ - int getDisplayIndexInBlock() { - this.shouldGenerateDumpStrings() and - exists(IRBlock block | - this = block.getInstruction(result) - or - this = - rank[-result - 1](PhiInstruction phiInstr | - phiInstr = block.getAPhiInstruction() - | - phiInstr order by phiInstr.getUniqueId() - ) - ) - } - - private int getLineRank() { - this.shouldGenerateDumpStrings() and - exists(IRFunction enclosing, Language::File file, int line | - this = - rank[result](Instruction instr | - instr = getAnInstructionAtLine(enclosing, file, line) - | - instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() - ) - ) - } - - /** - * Gets a human-readable string that uniquely identifies this instruction - * within the function. This string is used to refer to this instruction when - * printing IR dumps. - * - * Example: `r1_1` - */ - string getResultId() { - this.shouldGenerateDumpStrings() and - result = - this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank() - } - - /** - * Gets a string describing the result of this instruction, suitable for - * display in IR dumps. This consists of the result ID plus the type of the - * result. - * - * Example: `r1_1(int*)` - */ - final string getResultString() { - this.shouldGenerateDumpStrings() and - result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" - } - - /** - * Gets a string describing the operands of this instruction, suitable for - * display in IR dumps. - * - * Example: `func:r3_4, this:r3_5` - */ - string getOperandsString() { - this.shouldGenerateDumpStrings() and - result = - concat(Operand operand | - operand = this.getAnOperand() - | - operand.getDumpString(), ", " order by operand.getDumpSortOrder() - ) - } - - /** - * Gets a string identifier for this function that is unique among all - * instructions in the same function. - * - * This is used for sorting IR output for tests, and is likely to be - * inefficient for any other use. - */ - final string getUniqueId() { result = Construction::getInstructionUniqueId(this) } - - /** - * INTERNAL: Do not use. - * - * Gets two sort keys for this instruction - used to order instructions for printing - * in test outputs. - */ - final predicate hasSortKeys(int key1, int key2) { - Construction::instructionHasSortKeys(this, key1, key2) - } - - /** - * Gets the basic block that contains this instruction. - */ - final IRBlock getBlock() { result.getAnInstruction() = this } - - /** - * Gets the function that contains this instruction. - */ - final Language::Declaration getEnclosingFunction() { - result = this.getEnclosingIRFunction().getFunction() - } - - /** - * Gets the IRFunction object that contains the IR for this instruction. - */ - final IRFunction getEnclosingIRFunction() { - result = Construction::getInstructionEnclosingIRFunction(this) - } - - /** - * Gets the AST that caused this instruction to be generated. - */ - final Language::AST getAst() { result = Construction::getInstructionAst(this) } - - /** - * Gets the location of the source code for this instruction. - */ - final Language::Location getLocation() { result = this.getAst().getLocation() } - - /** - * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a - * conversion. - */ - final Language::Expr getConvertedResultExpression() { - result = Raw::getInstructionConvertedResultExpression(this) - } - - /** - * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. - */ - final Language::Expr getUnconvertedResultExpression() { - result = Raw::getInstructionUnconvertedResultExpression(this) - } - - /** - * Gets the language-specific type of the result produced by this instruction. - * - * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a - * less complex, language-neutral type system in which all semantically equivalent types share the - * same `IRType` instance. For example, in C++, four different `Instruction`s might have three - * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, - * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. - */ - final Language::LanguageType getResultLanguageType() { - result = Construction::getInstructionResultType(this) - } - - /** - * Gets the type of the result produced by this instruction. If the instruction does not produce - * a result, its result type will be `IRVoidType`. - */ - cached - final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } - - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = this.getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * ``` - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * ``` - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } - - /** - * Gets the size of the result produced by this instruction, in bytes. If the - * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. - */ - final int getResultSize() { result = this.getResultLanguageType().getByteSize() } - - /** - * Gets the opcode that specifies the operation performed by this instruction. - */ - pragma[inline] - final Opcode getOpcode() { Construction::getInstructionOpcode(result, this) } - - /** - * Gets all direct uses of the result of this instruction. The result can be - * an `Operand` for which `isDefinitionInexact` holds. - */ - final Operand getAUse() { result.getAnyDef() = this } - - /** - * Gets all of this instruction's operands. - */ - final Operand getAnOperand() { result.getUse() = this } - - /** - * Holds if this instruction produces a memory result. - */ - final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } - - /** - * Gets the kind of memory access performed by this instruction's result. - * Holds only for instructions with a memory result. - */ - pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { - result = this.getOpcode().getWriteMemoryAccess() - } - - /** - * Holds if the memory access performed by this instruction's result will not always write to - * every bit in the memory location. This is most commonly used for memory accesses that may or - * may not actually occur depending on runtime state (for example, the write side effect of an - * output parameter that is not written to on all paths), or for accesses where the memory - * location is a conservative estimate of the memory that might actually be accessed at runtime - * (for example, the global side effects of a function call). - */ - pragma[inline] - final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } - - /** - * Gets the operand that holds the memory address to which this instruction stores its - * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` - * is `r1`. - */ - final AddressOperand getResultAddressOperand() { - this.getResultMemoryAccess().usesAddressOperand() and - result.getUse() = this - } - - /** - * Gets the instruction that holds the exact memory address to which this instruction stores its - * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` - * is the instruction that defines `r1`. - */ - final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } - - /** - * Holds if the result of this instruction is precisely modeled in SSA. Always - * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result has no uses. - * - * For example: - * ``` - * int x = 1; - * int *p = &x; - * int y = *p; - * ``` - * In non-aliased SSA, `x` will not be modeled because it has its address - * taken. In that case, `isResultModeled()` would not hold for the result of - * the `Store` to `x`. - */ - final predicate isResultModeled() { - // Register results are always in SSA form. - not this.hasMemoryResult() or - Construction::hasModeledMemoryResult(this) - } - - /** - * Holds if this is an instruction with a memory result that represents a - * conflation of more than one memory allocation. - * - * This happens in practice when dereferencing a pointer that cannot be - * tracked back to a single local allocation. Such memory is instead modeled - * as originating on the `AliasedDefinitionInstruction` at the entry of the - * function. - */ - final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) } - - /** - * Gets the successor of this instruction along the control flow edge - * specified by `kind`. - */ - final Instruction getSuccessor(EdgeKind kind) { - result = Construction::getInstructionSuccessor(this, kind) - } - - /** - * Gets the a _back-edge successor_ of this instruction along the control - * flow edge specified by `kind`. A back edge in the control-flow graph is - * intuitively the edge that goes back around a loop. If all back edges are - * removed from the control-flow graph, it becomes acyclic. - */ - final Instruction getBackEdgeSuccessor(EdgeKind kind) { - // We don't take these edges from - // `Construction::getInstructionBackEdgeSuccessor` since that relation has - // not been treated to remove any loops that might be left over due to - // flaws in the IR construction or back-edge detection. - exists(IRBlock block | - block = this.getBlock() and - this = block.getLastInstruction() and - result = block.getBackEdgeSuccessor(kind).getFirstInstruction() - ) - } - - /** - * Gets all direct successors of this instruction. - */ - final Instruction getASuccessor() { result = this.getSuccessor(_) } - - /** - * Gets a predecessor of this instruction such that the predecessor reaches - * this instruction along the control flow edge specified by `kind`. - */ - final Instruction getPredecessor(EdgeKind kind) { result.getSuccessor(kind) = this } - - /** - * Gets all direct predecessors of this instruction. - */ - final Instruction getAPredecessor() { result = this.getPredecessor(_) } -} - -/** - * An instruction that refers to a variable. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * variable. For example, it is used for `VariableAddress`, which returns the address of a specific - * variable, and `InitializeParameter`, which returns the value that was passed to the specified - * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions - * that happen to load from or store to a particular variable; in those cases, the memory location - * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be - * defined by the result of a `VariableAddress` instruction. - */ -class VariableInstruction extends Instruction { - IRVariable var; - - VariableInstruction() { var = Raw::getInstructionVariable(this) } - - override string getImmediateString() { result = var.toString() } - - /** - * Gets the variable that this instruction references. - */ - final IRVariable getIRVariable() { result = var } - - /** - * Gets the AST variable that this instruction's IR variable refers to, if one exists. - */ - final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } -} - -/** - * An instruction that refers to a field of a class, struct, or union. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * field. For example, it is used for `FieldAddress`, which computes the address of a specific - * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen - * to load from or store to a particular field; in those cases, the memory location being accessed - * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the - * result of a `FieldAddress` instruction. - */ -class FieldInstruction extends Instruction { - Language::Field field; - - FieldInstruction() { field = Raw::getInstructionField(this) } - - final override string getImmediateString() { result = field.toString() } - - /** - * Gets the field that this instruction references. - */ - final Language::Field getField() { result = field } -} - -/** - * An instruction that refers to a function. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * function. For example, it is used for `FunctionAddress`, which returns the address of a specific - * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a - * particular function; in that case, the function being called is specified by the - * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a - * `FunctionAddress` instruction. - */ -class FunctionInstruction extends Instruction { - Language::Function funcSymbol; - - FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } - - final override string getImmediateString() { result = funcSymbol.toString() } - - /** - * Gets the function that this instruction references. - */ - final Language::Function getFunctionSymbol() { result = funcSymbol } -} - -/** - * An instruction whose result is a compile-time constant value. - */ -class ConstantValueInstruction extends Instruction { - string value; - - ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } - - final override string getImmediateString() { result = value } - - /** - * Gets the constant value of this instruction's result. - */ - final string getValue() { result = value } -} - -/** - * An instruction that refers to an argument of a `Call` instruction. - * - * This instruction is used for side effects of a `Call` instruction that read or write memory - * pointed to by one of the arguments of the call. - */ -class IndexedInstruction extends Instruction { - int index; - - IndexedInstruction() { index = Raw::getInstructionIndex(this) } - - final override string getImmediateString() { result = index.toString() } - - /** - * Gets the zero-based index of the argument that this instruction references. - */ - final int getIndex() { result = index } -} - -/** - * An instruction representing the entry point to a function. - * - * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins - * at this instruction. This instruction has no predecessors. - */ -class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } -} - -/** - * An instruction that returns the address of a variable. - * - * This instruction returns the address of a local variable, parameter, static field, - * namespace-scope variable, or global variable. For the address of a non-static field of a class, - * struct, or union, see `FieldAddressInstruction`. - */ -class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } -} - -/** - * An instruction that returns the address of a function. - * - * This instruction returns the address of a function, including non-member functions, static member - * functions, and non-static member functions. - * - * The result has an `IRFunctionAddress` type. - */ -class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } -} - -/** - * An instruction that returns the address of a "virtual" delete function. - * - * This function, which does not actually exist in the source code, is used to - * delete objects of a class with a virtual destructor. In that case the deacllocation - * function is selected at runtime based on the dynamic type of the object. So this - * function dynamically dispatches to the correct deallocation function. - * It also should pass in the required extra arguments to the deallocation function - * which may differ dynamically depending on the type of the object. - */ -class VirtualDeleteFunctionAddressInstruction extends Instruction { - VirtualDeleteFunctionAddressInstruction() { - this.getOpcode() instanceof Opcode::VirtualDeleteFunctionAddress - } -} - -/** - * An instruction that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. - * - * Each parameter of a function will have exactly one `InitializeParameter` instruction that - * initializes that parameter. - */ -class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } - - /** - * Gets the parameter initialized by this instruction. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction initializes the parameter with index `index`, or - * if `index` is `-1` and this instruction initializes `this`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.getIRVariable() instanceof IRThisVariable - } -} - -/** - * An instruction that initializes all memory that existed before this function was called. - * - * This instruction provides a definition for memory that, because it was actually allocated and - * initialized elsewhere, would not otherwise have a definition in this function. - */ -class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } -} - -/** - * An instruction that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. - */ -class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } - - /** - * Gets the parameter initialized by this instruction. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction initializes the memory pointed to by the parameter with - * index `index`, or if `index` is `-1` and this instruction initializes the memory - * pointed to by `this`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.getIRVariable() instanceof IRThisVariable - } -} - -/** - * An instruction that initializes the `this` pointer parameter of the enclosing function. - */ -class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } -} - -/** - * An instruction that computes the address of a non-static field of an object. - */ -class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } - - /** - * Gets the operand that provides the address of the object containing the field. - */ - final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the object containing the field. - */ - final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } -} - -/** - * An instruction that computes the address of the first element of a managed array. - * - * This instruction is used for element access to C# arrays. - */ -class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } - - /** - * Gets the operand that provides the address of the array object. - */ - final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the array object. - */ - final Instruction getArrayObjectAddress() { - result = this.getArrayObjectAddressOperand().getDef() - } -} - -/** - * An instruction that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. - * - * This type of instruction appears when there is an `ErrorExpr` in the AST, - * meaning that the extractor could not understand the expression and therefore - * produced a partial AST. Queries that give alerts when some action is _not_ - * taken may want to ignore any function that contains an `ErrorInstruction`. - */ -class ErrorInstruction extends Instruction { - ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } -} - -/** - * An instruction that returns an uninitialized value. - * - * This instruction is used to provide an initial definition for a stack variable that does not have - * an initializer, or whose initializer only partially initializes the variable. - */ -class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } - - /** - * Gets the variable that is uninitialized. - */ - final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } -} - -/** - * An instruction that has no effect. - * - * This instruction is typically inserted to ensure that a particular AST is associated with at - * least one instruction, even when the AST has no semantic effect. - */ -class NoOpInstruction extends Instruction { - NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } -} - -/** - * An instruction that returns control to the caller of the function. - * - * This instruction represents the normal (non-exception) return from a function, either from an - * explicit `return` statement or from control flow reaching the end of the function's body. - * - * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is - * represented as an initialization of the temporary variable that holds the return value, with - * control then flowing to the common `ReturnInstruction` for that function. Exception: A function - * that never returns will not have a `ReturnInstruction`. - * - * The `ReturnInstruction` for a function will have a control-flow successor edge to a block - * containing the `ExitFunction` instruction for that function. - * - * There are two different return instructions: `ReturnValueInstruction`, for returning a value from - * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a - * `void`-returning function. - */ -class ReturnInstruction extends Instruction { - ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } -} - -/** - * An instruction that returns control to the caller of the function, without returning a value. - */ -class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } -} - -/** - * An instruction that returns control to the caller of the function, including a return value. - */ -class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } - - /** - * Gets the operand that provides the value being returned by the function. - */ - final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that provides the address of the value being returned by the function. - */ - final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value being returned by the function, if an - * exact definition is available. - */ - final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } - - /** - * Gets the instruction whose result provides the address of the value being returned by the function. - */ - final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } -} - -/** - * An instruction that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. - * - * This instruction does not itself return control to the caller. It merely represents the potential - * for a caller to use the memory pointed to by the parameter sometime after the call returns. This - * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility - * that the caller initialized the memory pointed to by the parameter before the call. - */ -class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } - - /** - * Gets the operand that provides the value of the pointed-to memory. - */ - final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value of the pointed-to memory, if an exact - * definition is available. - */ - final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } - - /** - * Gets the operand that provides the address of the pointed-to memory. - */ - final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the pointed-to memory. - */ - final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - - /** - * Gets the parameter for which this instruction reads the final pointed-to value within the - * function. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction is the return indirection for `this`. - */ - final predicate isThisIndirection() { var instanceof IRThisVariable } - - /** - * Holds if this instruction is the return indirection for the parameter with index `index`, or - * if this instruction is the return indirection for `this` and `index` is `-1`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.isThisIndirection() - } -} - -/** - * An instruction that returns a copy of its operand. - * - * There are several different copy instructions, depending on the source and destination of the - * copy operation: - * - `CopyValueInstruction` - Copies a register operand to a register result. - * - `LoadInstruction` - Copies a memory operand to a register result. - * - `StoreInstruction` - Copies a register operand to a memory result. - */ -class CopyInstruction extends Instruction { - CopyInstruction() { this.getOpcode() instanceof CopyOpcode } - - /** - * Gets the operand that provides the input value of the copy. - */ - Operand getSourceValueOperand() { none() } - - /** - * Gets the instruction whose result provides the input value of the copy, if an exact definition - * is available. - */ - final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } -} - -/** - * An instruction that returns a register result containing a copy of its register operand. - */ -class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - - final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * Gets a string describing the location pointed to by the specified address operand. - */ -private string getAddressOperandDescription(AddressOperand operand) { - result = operand.getDef().(VariableAddressInstruction).getIRVariable().toString() - or - not operand.getDef() instanceof VariableAddressInstruction and - result = "?" -} - -/** - * An instruction that returns a register result containing a copy of its memory operand. - */ -class LoadInstruction extends CopyInstruction { - LoadInstruction() { this.getOpcode() instanceof Opcode::Load } - - final override string getImmediateString() { - result = getAddressOperandDescription(this.getSourceAddressOperand()) - } - - /** - * Gets the operand that provides the address of the value being loaded. - */ - final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the value being loaded. - */ - final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - - final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * An instruction that returns a memory result containing a copy of its register operand. - */ -class StoreInstruction extends CopyInstruction { - StoreInstruction() { this.getOpcode() instanceof Opcode::Store } - - final override string getImmediateString() { - result = getAddressOperandDescription(this.getDestinationAddressOperand()) - } - - /** - * Gets the operand that provides the address of the location to which the value will be stored. - */ - final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the location to which the value will - * be stored, if an exact definition is available. - */ - final Instruction getDestinationAddress() { - result = this.getDestinationAddressOperand().getDef() - } - - final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * An instruction that branches to one of two successor instructions based on the value of a Boolean - * operand. - */ -class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } - - /** - * Gets the operand that provides the Boolean condition controlling the branch. - */ - final ConditionOperand getConditionOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the Boolean condition controlling the branch. - */ - final Instruction getCondition() { result = this.getConditionOperand().getDef() } - - /** - * Gets the instruction to which control will flow if the condition is true. - */ - final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } - - /** - * Gets the instruction to which control will flow if the condition is false. - */ - final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } -} - -/** - * An instruction representing the exit point of a function. - * - * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns - * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no - * successors. - */ -class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } -} - -/** - * An instruction whose result is a constant value. - */ -class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } -} - -/** - * An instruction whose result is a constant value of integer or Boolean type. - */ -class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { - exists(IRType resultType | - resultType = this.getResultIRType() and - (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) - ) - } -} - -/** - * An instruction whose result is a constant value of floating-point type. - */ -class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } -} - -/** - * An instruction whose result is the address of a string literal. - */ -class StringConstantInstruction extends VariableInstruction { - override IRStringLiteral var; - - final override string getImmediateString() { - result = Language::getStringLiteralText(this.getValue()) - } - - /** - * Gets the string literal whose address is returned by this instruction. - */ - final Language::StringLiteral getValue() { result = var.getLiteral() } -} - -/** - * An instruction whose result is computed from two operands. - */ -class BinaryInstruction extends Instruction { - BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } - - /** - * Gets the left operand of this binary instruction. - */ - final LeftOperand getLeftOperand() { result = this.getAnOperand() } - - /** - * Gets the right operand of this binary instruction. - */ - final RightOperand getRightOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value of the left operand of this binary - * instruction. - */ - final Instruction getLeft() { result = this.getLeftOperand().getDef() } - - /** - * Gets the instruction whose result provides the value of the right operand of this binary - * instruction. - */ - final Instruction getRight() { result = this.getRightOperand().getDef() } - - /** - * Holds if this instruction's operands are `op1` and `op2`, in either order. - */ - final predicate hasOperands(Operand op1, Operand op2) { - op1 = this.getLeftOperand() and op2 = this.getRightOperand() - or - op1 = this.getRightOperand() and op2 = this.getLeftOperand() - } -} - -/** - * An instruction that computes the result of an arithmetic operation. - */ -class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } -} - -/** - * An instruction that performs an arithmetic operation on two numeric operands. - */ -class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } - -/** - * An instruction whose result is computed by performing an arithmetic operation on a single - * numeric operand. - */ -class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } - -/** - * An instruction that computes the sum of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is - * performed according to IEEE-754. - */ -class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { this.getOpcode() instanceof Opcode::Add } -} - -/** - * An instruction that computes the difference of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed - * according to IEEE-754. - */ -class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { this.getOpcode() instanceof Opcode::Sub } -} - -/** - * An instruction that computes the product of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is - * performed according to IEEE-754. - */ -class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { this.getOpcode() instanceof Opcode::Mul } -} - -/** - * An instruction that computes the quotient of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * division by zero or integer overflow is undefined. Floating-point division is performed according - * to IEEE-754. - */ -class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { this.getOpcode() instanceof Opcode::Div } -} - -/** - * An instruction that computes the remainder of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. The result of - * division by zero or integer overflow is undefined. - */ -class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { this.getOpcode() instanceof Opcode::Rem } -} - -/** - * An instruction that negates a single numeric operand. - * - * The operand must have a numeric type, which will also be the result type. The result of integer - * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation - * is performed according to IEEE-754. - */ -class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } -} - -/** - * An instruction that computes the result of a bitwise operation. - */ -class BitwiseInstruction extends Instruction { - BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } -} - -/** - * An instruction that performs a bitwise operation on two integer operands. - */ -class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } - -/** - * An instruction that performs a bitwise operation on a single integer operand. - */ -class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } - -/** - * An instruction that computes the bitwise "and" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } -} - -/** - * An instruction that computes the bitwise "or" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } -} - -/** - * An instruction that computes the bitwise "xor" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } -} - -/** - * An instruction that shifts its left operand to the left by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. The - * rightmost bits are zero-filled. - */ -class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } -} - -/** - * An instruction that shifts its left operand to the right by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. If the - * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand - * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit - * of the left operand. - */ -class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } -} - -/** - * An instruction that shifts its left operand to the right by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. - * The leftmost bits are zero-filled. - */ -class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction { - UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight } -} - -/** - * An instruction that performs a binary arithmetic operation involving at least one pointer - * operand. - */ -class PointerArithmeticInstruction extends BinaryInstruction { - int elementSize; - - PointerArithmeticInstruction() { - this.getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Raw::getInstructionElementSize(this) - } - - final override string getImmediateString() { result = elementSize.toString() } - - /** - * Gets the size of the elements pointed to by the pointer operands, in bytes. - * - * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer - * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the - * element size to compute the actual number of bytes added to or subtracted from the pointer - * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), - * the result is computed by computing the difference between the two pointer byte addresses, then - * dividing that byte count by the element size. - */ - final int getElementSize() { result = elementSize } -} - -/** - * An instruction that adds or subtracts an integer offset from a pointer. - */ -class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } -} - -/** - * An instruction that adds an integer offset to a pointer. - * - * The result is the byte address computed by adding the value of the right (integer) operand, - * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer - * overflow is undefined. - */ -class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } -} - -/** - * An instruction that subtracts an integer offset from a pointer. - * - * The result is the byte address computed by subtracting the value of the right (integer) operand, - * multiplied by the element size, from the value of the left (pointer) operand. The result of - * pointer underflow is undefined. - */ -class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } -} - -/** - * An instruction that computes the difference between two pointers. - * - * Both operands must have the same pointer type. The result must have an integer type whose size is - * the same as that of the pointer operands. The result is computed by subtracting the byte address - * in the right operand from the byte address in the left operand, and dividing by the element size. - * If the difference in byte addresses is not divisible by the element size, the result is - * undefined. - */ -class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } -} - -/** - * An instruction whose result is computed from a single operand. - */ -class UnaryInstruction extends Instruction { - UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } - - /** - * Gets the sole operand of this instruction. - */ - final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the sole operand of this instruction. - */ - final Instruction getUnary() { result = this.getUnaryOperand().getDef() } -} - -/** - * An instruction that converts the value of its operand to a value of a different type. - */ -class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } -} - -/** - * An instruction that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or - * `as` expression. - */ -class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } -} - -/** - * An instruction that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast - * expression. - */ -class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } -} - -/** - * An instruction that returns the address of the complete object that contains the subobject - * pointed to by its operand. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent `dynamic_cast` in C++, which returns the pointer to - * the most-derived object. - */ -class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } -} - -/** - * An instruction that converts the address of an object to the address of a different subobject of - * the same object, without any type checking at runtime. - */ -class InheritanceConversionInstruction extends UnaryInstruction { - Language::Class baseClass; - Language::Class derivedClass; - - InheritanceConversionInstruction() { - Raw::getInstructionInheritance(this, baseClass, derivedClass) - } - - final override string getImmediateString() { - result = derivedClass.toString() + " : " + baseClass.toString() - } - - /** - * Gets the `ClassDerivation` for the inheritance relationship between - * the base and derived classes. This predicate does not hold if the - * conversion is to an indirect virtual base class. - */ - final Language::ClassDerivation getDerivation() { - result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass - } - - /** - * Gets the base class of the conversion. This will be either a direct - * base class of the derived class, or a virtual base class of the - * derived class. - */ - final Language::Class getBaseClass() { result = baseClass } - - /** - * Gets the derived class of the conversion. - */ - final Language::Class getDerivedClass() { result = derivedClass } -} - -/** - * An instruction that converts from the address of a derived class to the address of a base class. - */ -class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } -} - -/** - * An instruction that converts from the address of a derived class to the address of a direct - * non-virtual base class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { - this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase - } -} - -/** - * An instruction that converts from the address of a derived class to the address of a virtual base - * class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } -} - -/** - * An instruction that converts from the address of a base class to the address of a direct - * non-virtual derived class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } -} - -/** - * An instruction that computes the bitwise complement of its operand. - * - * The operand must have an integer type, which will also be the result type. - */ -class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } -} - -/** - * An instruction that computes the logical complement of its operand. - * - * The operand must have a Boolean type, which will also be the result type. - */ -class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } -} - -/** - * An instruction that compares two numeric operands. - */ -class CompareInstruction extends BinaryInstruction { - CompareInstruction() { this.getOpcode() instanceof CompareOpcode } -} - -/** - * An instruction that returns a `true` result if its operands are equal. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are - * unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } -} - -/** - * An instruction that returns a `true` result if its operands are not equal. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if `left != right` or if the two operands are unordered, and `false` if - * `left == right`. Floating-point comparison is performed according to IEEE-754. - */ -class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } -} - -/** - * An instruction that does a relative comparison of two values, such as `<` or `>=`. - */ -class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } - - /** - * Gets the operand on the "greater" (or "greater-or-equal") side - * of this relational instruction, that is, the side that is larger - * if the overall instruction evaluates to `true`; for example on - * `x <= 20` this is the `20`, and on `y > 0` it is `y`. - */ - Instruction getGreater() { none() } - - /** - * Gets the operand on the "lesser" (or "lesser-or-equal") side - * of this relational instruction, that is, the side that is smaller - * if the overall instruction evaluates to `true`; for example on - * `x <= 20` this is `x`, and on `y > 0` it is the `0`. - */ - Instruction getLesser() { none() } - - /** - * Holds if this relational instruction is strict (is not an "or-equal" instruction). - */ - predicate isStrict() { none() } -} - -/** - * An instruction that returns a `true` result if its left operand is less than its right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - - override Instruction getLesser() { result = this.getLeft() } - - override Instruction getGreater() { result = this.getRight() } - - override predicate isStrict() { any() } -} - -/** - * An instruction that returns a `true` result if its left operand is greater than its right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - - override Instruction getLesser() { result = this.getRight() } - - override Instruction getGreater() { result = this.getLeft() } - - override predicate isStrict() { any() } -} - -/** - * An instruction that returns a `true` result if its left operand is less than or equal to its - * right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - - override Instruction getLesser() { result = this.getLeft() } - - override Instruction getGreater() { result = this.getRight() } - - override predicate isStrict() { none() } -} - -/** - * An instruction that returns a `true` result if its left operand is greater than or equal to its - * right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - - override Instruction getLesser() { result = this.getRight() } - - override Instruction getGreater() { result = this.getLeft() } - - override predicate isStrict() { none() } -} - -/** - * An instruction that branches to one of multiple successor instructions based on the value of an - * integer operand. - * - * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each - * representing the branch that will be taken if the controlling expression is within the range - * specified for that case edge. The range of a case edge must be disjoint from the range of each - * other case edge. - * - * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, - * representing the branch that will be taken if the controlling expression is not within the range - * of any case edge. - */ -class SwitchInstruction extends Instruction { - SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } - - /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } - - /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = this.getExpressionOperand().getDef() } - - /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } - - /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } -} - -/** - * An instruction that calls a function. - */ -class CallInstruction extends Instruction { - CallInstruction() { this.getOpcode() instanceof Opcode::Call } - - final override string getImmediateString() { - result = this.getStaticCallTarget().toString() - or - not exists(this.getStaticCallTarget()) and result = "?" - } - - /** - * Gets the operand the specifies the target function of the call. - */ - final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } - - /** - * Gets the `Instruction` that computes the target function of the call. This is usually a - * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a - * function pointer. - */ - final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } - - /** - * Gets all of the argument operands of the call, including the `this` pointer, if any. - */ - final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } - - /** - * Gets the `Function` that the call targets, if this is statically known. - */ - final Language::Function getStaticCallTarget() { - result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() - } - - /** - * Gets all of the arguments of the call, including the `this` pointer, if any. - */ - final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } - - /** - * Gets the `this` pointer argument operand of the call, if any. - */ - final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } - - /** - * Gets the `this` pointer argument of the call, if any. - */ - final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } - - /** - * Gets the argument operand at the specified index. - */ - pragma[noinline] - final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = this.getAnOperand() and - result.getIndex() = index - } - - /** - * Gets the argument at the specified index. - */ - pragma[noinline] - final Instruction getPositionalArgument(int index) { - result = this.getPositionalArgumentOperand(index).getDef() - } - - /** - * Gets the argument operand at the specified index, or `this` if `index` is `-1`. - */ - pragma[noinline] - final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = this.getPositionalArgumentOperand(index) - or - index = -1 and result = this.getThisArgumentOperand() - } - - /** - * Gets the argument at the specified index, or `this` if `index` is `-1`. - */ - pragma[noinline] - final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } - - /** - * Gets the number of arguments of the call, including the `this` pointer, if any. - */ - final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) } - - /** - * Holds if the result is a side effect for the argument at the specified index, or `this` if - * `index` is `-1`. - * - * This helper predicate makes it easy to join on both of these columns at once, avoiding - * pathological join orders in case the argument index should get joined first. - */ - pragma[noinline] - final SideEffectInstruction getAParameterSideEffect(int index) { - this = result.getPrimaryInstruction() and - index = result.(IndexedInstruction).getIndex() - } -} - -/** - * An instruction representing a side effect of a function call. - */ -class SideEffectInstruction extends Instruction { - SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } - - /** - * Gets the instruction whose execution causes this side effect. - */ - final Instruction getPrimaryInstruction() { - result = Construction::getPrimaryInstructionForSideEffect(this) - } -} - -/** - * An instruction representing the side effect of a function call on any memory that might be - * accessed by that call. - */ -class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } -} - -/** - * An instruction representing the side effect of a function call on any memory - * that might be read by that call. - * - * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the - * call target cannot write to escaped memory. - */ -class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } -} - -/** - * An instruction representing a read side effect of a function call on a - * specific parameter. - */ -class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } - - /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } - - /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } - - /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = this.getAnOperand() } - - /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } -} - -/** - * An instruction representing the read of an indirect parameter within a function call. - */ -class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } -} - -/** - * An instruction representing the read of an indirect buffer parameter within a function call. - */ -class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } -} - -/** - * An instruction representing the read of an indirect buffer parameter within a function call. - */ -class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { - SizedBufferReadSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect - } - - /** - * Gets the operand that holds the number of bytes read from the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes read from the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing a write side effect of a function call on a - * specific parameter. - */ -class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } - - /** - * Get the operand that holds the address of the memory to be written. - */ - final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the memory to be written. - */ - Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } -} - -/** - * An instruction representing the write of an indirect parameter within a function call. - */ -class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - IndirectMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. - */ -class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. - */ -class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - SizedBufferMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect - } - - /** - * Gets the operand that holds the number of bytes written to the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes written to the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing the potential write of an indirect parameter within a function call. - * - * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. - * written. - */ -class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - IndirectMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. - * - * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. - */ -class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. - * - * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. - */ -class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - SizedBufferMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect - } - - /** - * Gets the operand that holds the number of bytes written to the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes written to the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. - */ -class InitializeDynamicAllocationInstruction extends SideEffectInstruction { - InitializeDynamicAllocationInstruction() { - this.getOpcode() instanceof Opcode::InitializeDynamicAllocation - } - - /** - * Gets the operand that represents the address of the allocation this instruction is initializing. - */ - final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the address for the allocation this instruction is initializing. - */ - final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } -} - -/** - * An instruction representing a GNU or MSVC inline assembly statement. - */ -class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } -} - -/** - * An instruction that throws an exception. - */ -class ThrowInstruction extends Instruction { - ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } -} - -/** - * An instruction that throws a new exception. - */ -class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } - - /** - * Gets the address operand of the exception thrown by this instruction. - */ - final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the address of the exception thrown by this instruction. - */ - final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } - - /** - * Gets the operand for the exception thrown by this instruction. - */ - final LoadOperand getExceptionOperand() { result = this.getAnOperand() } - - /** - * Gets the exception thrown by this instruction. - */ - final Instruction getException() { result = this.getExceptionOperand().getDef() } -} - -/** - * An instruction that re-throws the current exception. - */ -class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } -} - -/** - * An instruction that exits the current function by propagating an exception. - */ -class UnwindInstruction extends Instruction { - UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } -} - -/** - * An instruction that starts a `catch` handler. - */ -class CatchInstruction extends Instruction { - CatchInstruction() { this.getOpcode() instanceof CatchOpcode } -} - -/** - * An instruction that catches an exception of a specific type. - */ -class CatchByTypeInstruction extends CatchInstruction { - Language::LanguageType exceptionType; - - CatchByTypeInstruction() { - this.getOpcode() instanceof Opcode::CatchByType and - exceptionType = Raw::getInstructionExceptionType(this) - } - - final override string getImmediateString() { result = exceptionType.toString() } - - /** - * Gets the type of exception to be caught. - */ - final Language::LanguageType getExceptionType() { result = exceptionType } -} - -/** - * An instruction that catches any exception. - */ -class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } -} - -/** - * An instruction that initializes all escaped memory. - */ -class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } -} - -/** - * An instruction that consumes all escaped memory on exit from the function. - */ -class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } -} - -/** - * An instruction representing the choice of one of multiple input values based on control flow. - * - * A `PhiInstruction` is inserted at the beginning of a block whenever two different definitions of - * the same variable reach that block. The `PhiInstruction` will have one operand corresponding to - * each control flow predecessor of the block, with that operand representing the version of the - * variable that flows from that predecessor. The result value of the `PhiInstruction` will be - * a copy of whichever operand corresponds to the actual predecessor that entered the block at - * runtime. - */ -class PhiInstruction extends Instruction { - PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } - - /** - * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. - */ - final PhiInputOperand getAnInputOperand() { result = this.getAnOperand() } - - /** - * Gets an instruction that defines the input to one of the operands of this - * instruction. It's possible for more than one operand to have the same - * defining instruction, so this predicate will have the same number of - * results as `getAnInputOperand()` or fewer. - */ - pragma[noinline] - final Instruction getAnInput() { result = this.getAnInputOperand().getDef() } - - /** - * Gets the input operand representing the value that flows from the specified predecessor block. - */ - final PhiInputOperand getInputOperand(IRBlock predecessorBlock) { - result = this.getAnOperand() and - result.getPredecessorBlock() = predecessorBlock - } -} - -/** - * An instruction representing the effect that a write to a memory may have on potential aliases of - * that memory. - * - * A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The - * `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents - * the previous state of all of the memory that might be aliased by the memory write. The second - * operand, given by `getPartialOperand()`, represents the memory that was actually modified by the - * memory write. The result of the `ChiInstruction` represents the same memory as - * `getTotalOperand()`, updated to include the changes due to the value that was actually stored by - * the memory write. - * - * As an example, suppose that variable `p` and `q` are pointers that may or may not point to the - * same memory: - * ``` - * *p = 5; - * x = *q; - * ``` - * - * The IR would look like: - * ``` - * r1_1 = VariableAddress[p] - * r1_2 = Load r1_1, m0_0 // Load the value of `p` - * r1_3 = Constant[5] - * m1_4 = Store r1_2, r1_3 // Store to `*p` - * m1_5 = ^Chi m0_1, m1_4 // Side effect of the previous Store on aliased memory - * r1_6 = VariableAddress[x] - * r1_7 = VariableAddress[q] - * r1_8 = Load r1_7, m0_2 // Load the value of `q` - * r1_9 = Load r1_8, m1_5 // Load the value of `*q` - * m1_10 = Store r1_6, r1_9 // Store to x - * ``` - * - * Note the `Chi` instruction after the store to `*p`. The indicates that the previous contents of - * aliased memory (`m0_1`) are merged with the new value written by the store (`m1_4`), producing a - * new version of aliased memory (`m1_5`). On the subsequent load from `*q`, the source operand of - * `*q` is `m1_5`, indicating that the store to `*p` may (or may not) have updated the memory - * pointed to by `q`. - * - * For more information about how `Chi` instructions are used to model memory side effects, see - * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. - */ -class ChiInstruction extends Instruction { - ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } - - /** - * Gets the operand that represents the previous state of all memory that might be aliased by the - * memory write. - */ - final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that represents the previous state of all memory that might be aliased by the - * memory write. - */ - final Instruction getTotal() { result = this.getTotalOperand().getDef() } - - /** - * Gets the operand that represents the new value written by the memory write. - */ - final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that represents the new value written by the memory write. - */ - final Instruction getPartial() { result = this.getPartialOperand().getDef() } - - /** - * Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`. - * This means that the `ChiPartialOperand` will not override the entire memory associated with the - * `ChiTotalOperand`. - */ - final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) } -} - -/** - * An instruction representing unreachable code. - * - * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` - * or `Switch` instruction where that particular edge is infeasible. - */ -class UnreachedInstruction extends Instruction { - UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } -} - -/** - * An instruction representing a built-in operation. - * - * This is used to represent a variety of intrinsic operations provided by the compiler - * implementation, such as vector arithmetic. - */ -class BuiltInOperationInstruction extends Instruction { - Language::BuiltInOperation operation; - - BuiltInOperationInstruction() { - this.getOpcode() instanceof BuiltInOperationOpcode and - operation = Raw::getInstructionBuiltInOperation(this) - } - - /** - * Gets the language-specific `BuiltInOperation` object that specifies the operation that is - * performed by this instruction. - */ - final Language::BuiltInOperation getBuiltInOperation() { result = operation } -} - -/** - * An instruction representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. - */ -class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - - final override string getImmediateString() { result = this.getBuiltInOperation().toString() } -} - -/** - * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. - * - * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` - * parameter. The result is a `va_list` that initially refers to the first argument that was passed - * to the `...` parameter. - */ -class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } -} - -/** - * An instruction that cleans up a `va_list` after it is no longer in use. - * - * The operand specifies the address of the `va_list` to clean up. This instruction does not return - * a result. - */ -class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } -} - -/** - * An instruction that returns the address of the argument currently pointed to by a `va_list`. - * - * The operand is the `va_list` that points to the argument. The result is the address of the - * argument. - */ -class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } -} - -/** - * An instruction that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. - * - * The operand is the current `va_list`. The result is an updated `va_list` that points to the next - * argument of the `...` parameter. - */ -class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } -} - -/** - * An instruction that allocates a new object on the managed heap. - * - * This instruction is used to represent the allocation of a new object in C# using the `new` - * expression. This instruction does not invoke a constructor for the object. Instead, there will be - * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the - * result of the `NewObj` as the `this` argument. - * - * The result is the address of the newly allocated object. - */ -class NewObjInstruction extends Instruction { - NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll deleted file mode 100644 index c1743acdbae..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ /dev/null @@ -1,499 +0,0 @@ -/** - * Provides classes that represent the input values of IR instructions. - */ - -private import internal.IRInternal -private import Instruction -private import IRBlock -private import internal.OperandImports as Imports -private import Imports::MemoryAccessKind -private import Imports::IRType -private import Imports::Overlap -private import Imports::OperandTag -private import Imports::TOperand -private import internal.OperandInternal - -/** - * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches - * of `TOperand` that are used in this stage. - */ -private class TStageOperand = - TRegisterOperand or TNonSsaMemoryOperand or TPhiOperand or TChiOperand; - -/** - * A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as - * opposed to testing `not loc isntanceof UnknownLocation` - */ -private class KnownLocation extends Language::Location { - KnownLocation() { not this instanceof Language::UnknownLocation } -} - -/** - * An operand of an `Instruction`. The operand represents a use of the result of one instruction - * (the defining instruction) in another instruction (the use instruction) - */ -class Operand extends TStageOperand { - cached - Operand() { - // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) - or - exists(Instruction use | this = nonSsaMemoryOperand(use, _)) - or - exists(Instruction use, Instruction def, IRBlock predecessorBlock | - this = phiOperand(use, def, predecessorBlock, _) or - this = reusedPhiOperand(use, def, predecessorBlock, _) - ) - or - this = chiOperand(_, _) - } - - /** Gets a textual representation of this element. */ - string toString() { result = "Operand" } - - /** - * Gets the location of the source code for this operand. - * By default this is where the operand is used, but some subclasses may override this - * using `getAnyDef()` if it makes more sense. - */ - Language::Location getLocation() { result = this.getUse().getLocation() } - - /** - * Gets the function that contains this operand. - */ - final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } - - /** - * Gets the `Instruction` that consumes this operand. - */ - Instruction getUse() { none() } - - /** - * Gets the `Instruction` whose result is the value of the operand. Unlike - * `getDef`, this also has a result when `isDefinitionInexact` holds, which - * means that the resulting instruction may only _partially_ or _potentially_ - * be the value of this operand. - */ - Instruction getAnyDef() { none() } - - /** - * Gets the `Instruction` whose result is the value of the operand. Unlike - * `getAnyDef`, this also has no result when `isDefinitionInexact` holds, - * which means that the resulting instruction must always be exactly the be - * the value of this operand. - */ - final Instruction getDef() { - result = this.getAnyDef() and - this.getDefinitionOverlap() instanceof MustExactlyOverlap - } - - /** - * Gets the overlap relationship between the operand's definition and its use. - */ - Overlap getDefinitionOverlap() { none() } - - /** - * Holds if the result of the definition instruction does not exactly overlap this use. - */ - final predicate isDefinitionInexact() { - not this.getDefinitionOverlap() instanceof MustExactlyOverlap - } - - /** - * Gets a prefix to use when dumping the operand in an operand list. - */ - string getDumpLabel() { result = "" } - - /** - * Gets a string that uniquely identifies this operand on its use instruction. - */ - string getDumpId() { result = "" } - - /** - * Gets a string describing this operand, suitable for display in IR dumps. This consists of the - * result ID of the instruction consumed by the operand, plus a label identifying the operand - * kind. - * - * For example: `this:r3_5` - */ - final string getDumpString() { - result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() - } - - /** - * Gets a string containing the identifier of the definition of this use, or `m?` if the - * definition is not modeled in SSA. - */ - private string getDefinitionId() { - result = this.getAnyDef().getResultId() - or - not exists(this.getAnyDef()) and result = "m?" - } - - /** - * Gets a string prefix to prepend to the operand's definition ID in an IR dump, specifying whether the operand is - * an exact or inexact use of its definition. For an inexact use, the prefix is "~". For an exact use, the prefix is - * the empty string. - */ - private string getInexactSpecifier() { - if this.isDefinitionInexact() then result = "~" else result = "" - } - - /** - * Get the order in which the operand should be sorted in the operand list. - */ - int getDumpSortOrder() { result = -1 } - - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } - - /** - * Gets the language-neutral type of the value consumed by this operand. This is usually the same - * as the result type of the definition instruction consumed by this operand. For register - * operands, this is always the case. For some memory operands, the operand type may be different - * from the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final IRType getIRType() { result = this.getLanguageType().getIRType() } - - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { this.getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { this.getLanguageType().hasType(_, true) } - - /** - * Gets the size of the value consumed by this operand, in bytes. If the operand does not have - * a known constant size, this predicate does not hold. - */ - final int getSize() { result = this.getLanguageType().getByteSize() } -} - -/** - * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). - */ -class MemoryOperand extends Operand { - cached - MemoryOperand() { - this instanceof TNonSsaMemoryOperand or - this instanceof TPhiOperand or - this instanceof TChiOperand - } - - /** - * Gets the kind of memory access performed by the operand. - */ - MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } - - /** - * Holds if the memory access performed by this operand will not always read from every bit in the - * memory location. This is most commonly used for memory accesses that may or may not actually - * occur depending on runtime state (for example, the write side effect of an output parameter - * that is not written to on all paths), or for accesses where the memory location is a - * conservative estimate of the memory that might actually be accessed at runtime (for example, - * the global side effects of a function call). - */ - predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } - - /** - * Returns the operand that holds the memory address from which the current operand loads its - * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` - * is `r1`. - */ - final AddressOperand getAddressOperand() { - this.getMemoryAccess().usesAddressOperand() and - result.getUse() = this.getUse() - } -} - -/** - * An operand that is not an operand of a `PhiInstruction`. - */ -class NonPhiOperand extends Operand { - Instruction useInstr; - OperandTag tag; - - NonPhiOperand() { - this = registerOperand(useInstr, tag, _) or - this = nonSsaMemoryOperand(useInstr, tag) or - this = chiOperand(useInstr, tag) - } - - final override Instruction getUse() { result = useInstr } - - final override string getDumpLabel() { result = tag.getLabel() } - - final override string getDumpId() { result = tag.getId() } - - final override int getDumpSortOrder() { result = tag.getSortOrder() } - - /** - * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. - */ - final OperandTag getOperandTag() { result = tag } -} - -/** - * An operand that consumes a register (non-memory) result. - */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { - override RegisterOperandTag tag; - Instruction defInstr; - - cached - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } - - final override string toString() { result = tag.toString() } - - // most `RegisterOperands` have a more meaningful location at the definition - // the only exception are specific cases of `ThisArgumentOperand` - override Language::Location getLocation() { result = this.getAnyDef().getLocation() } - - final override Instruction getAnyDef() { result = defInstr } - - final override Overlap getDefinitionOverlap() { - // All register results overlap exactly with their uses. - result instanceof MustExactlyOverlap - } -} - -/** - * A memory operand other than the operand of a `Phi` instruction. - */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { - override MemoryOperandTag tag; - - cached - NonPhiMemoryOperand() { - this = nonSsaMemoryOperand(useInstr, tag) - or - this = chiOperand(useInstr, tag) - } - - final override string toString() { result = tag.toString() } - - final override Instruction getAnyDef() { - result = unique(Instruction defInstr | this.hasDefinition(defInstr, _)) - } - - final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } - - pragma[noinline] - private predicate hasDefinition(Instruction defInstr, Overlap overlap) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - } - - /** - * Holds if the operand totally overlaps with its definition and consumes the - * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. - */ - predicate getUsedInterval(int startBitOffset, int endBitOffset) { - Construction::getUsedInterval(this, startBitOffset, endBitOffset) - } -} - -/** - * A memory operand whose type may be different from the type of the result of its definition. - */ -class TypedOperand extends NonPhiMemoryOperand { - override TypedOperandTag tag; - - final override Language::LanguageType getLanguageType() { - result = Construction::getInstructionOperandType(useInstr, tag) - } -} - -/** - * The address operand of an instruction that loads or stores a value from - * memory (e.g. `Load`, `Store`). - */ -class AddressOperand extends RegisterOperand { - override AddressOperandTag tag; -} - -/** - * The buffer size operand of an instruction that represents a read or write of - * a buffer. - */ -class BufferSizeOperand extends RegisterOperand { - override BufferSizeOperandTag tag; -} - -/** - * The source value operand of an instruction that loads a value from memory (e.g. `Load`, - * `ReturnValue`, `ThrowValue`). - */ -class LoadOperand extends TypedOperand { - override LoadOperandTag tag; -} - -/** - * The source value operand of a `Store` instruction. - */ -class StoreValueOperand extends RegisterOperand { - override StoreValueOperandTag tag; -} - -/** - * The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`). - */ -class UnaryOperand extends RegisterOperand { - override UnaryOperandTag tag; -} - -/** - * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). - */ -class LeftOperand extends RegisterOperand { - override LeftOperandTag tag; -} - -/** - * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). - */ -class RightOperand extends RegisterOperand { - override RightOperandTag tag; -} - -/** - * The condition operand of a `ConditionalBranch` or `Switch` instruction. - */ -class ConditionOperand extends RegisterOperand { - override ConditionOperandTag tag; -} - -/** - * The operand representing the target function of an `Call` instruction. - */ -class CallTargetOperand extends RegisterOperand { - override CallTargetOperandTag tag; -} - -/** - * An operand representing an argument to a function call. This includes both - * positional arguments (represented by `PositionalArgumentOperand`) and the - * implicit `this` argument, if any (represented by `ThisArgumentOperand`). - */ -class ArgumentOperand extends RegisterOperand { - override ArgumentOperandTag tag; - - /** Gets the `CallInstruction` for which this is an argument. */ - CallInstruction getCall() { result.getAnArgumentOperand() = this } -} - -/** - * An operand representing the implicit `this` argument to a member function - * call. - */ -class ThisArgumentOperand extends ArgumentOperand { - override ThisArgumentOperandTag tag; - - // in most cases the def location makes more sense, but in some corner cases it - // has an unknown location: in those cases we fall back to the use location - override Language::Location getLocation() { - if this.getAnyDef().getLocation() instanceof KnownLocation - then result = this.getAnyDef().getLocation() - else result = this.getUse().getLocation() - } -} - -/** - * An operand representing an argument to a function call. - */ -class PositionalArgumentOperand extends ArgumentOperand { - override PositionalArgumentOperandTag tag; - - /** - * Gets the zero-based index of the argument. - */ - final int getIndex() { result = tag.getArgIndex() } -} - -/** - * An operand representing memory read as a side effect of evaluating another instruction. - */ -class SideEffectOperand extends TypedOperand { - override SideEffectOperandTag tag; -} - -/** - * An operand of a `PhiInstruction`. - */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { - PhiInstruction useInstr; - Instruction defInstr; - IRBlock predecessorBlock; - Overlap overlap; - - cached - PhiInputOperand() { - this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) - or - this = reusedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) - } - - override string toString() { result = "Phi" } - - final override PhiInstruction getUse() { result = useInstr } - - final override Instruction getAnyDef() { result = defInstr } - - final override Overlap getDefinitionOverlap() { result = overlap } - - final override int getDumpSortOrder() { - result = 11 + this.getPredecessorBlock().getDisplayIndex() - } - - final override string getDumpLabel() { - result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" - } - - final override string getDumpId() { - result = this.getPredecessorBlock().getDisplayIndex().toString() - } - - /** - * Gets the predecessor block from which this value comes. - */ - final IRBlock getPredecessorBlock() { result = predecessorBlock } - - final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess } -} - -/** - * The total operand of a Chi node, representing the previous value of the memory. - */ -class ChiTotalOperand extends NonPhiMemoryOperand { - override ChiTotalOperandTag tag; - - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } -} - -/** - * The partial operand of a Chi node, representing the value being written to part of the memory. - */ -class ChiPartialOperand extends NonPhiMemoryOperand { - override ChiPartialOperandTag tag; - - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql deleted file mode 100644 index ac77496f283..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Print Raw IR - * @description Outputs a representation of the Raw IR graph - * @id cs/print-raw-ir - * @kind graph - */ - -import PrintIR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll deleted file mode 100644 index c4b18d9cb61..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll +++ /dev/null @@ -1,342 +0,0 @@ -/** - * Outputs a representation of the IR as a control flow graph. - * - * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small - * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintIR.qll`, extends - * `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations - * to dump. - */ - -private import internal.IRInternal -private import IR -private import internal.PrintIRImports as Imports -import Imports::IRConfiguration - -private newtype TPrintIRConfiguration = MkPrintIRConfiguration() - -/** - * The query can extend this class to control which declarations are printed. - */ -class PrintIRConfiguration extends TPrintIRConfiguration { - /** Gets a textual representation of this configuration. */ - string toString() { result = "PrintIRConfiguration" } - - /** - * Holds if the IR for `func` should be printed. By default, holds for all - * functions, global and namespace variables, and static local variables. - */ - predicate shouldPrintDeclaration(Language::Declaration decl) { any() } -} - -/** - * Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped. - */ -private class FilteredIRConfiguration extends IRConfiguration { - override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { - shouldPrintDeclaration(func) - } -} - -private predicate shouldPrintDeclaration(Language::Declaration decl) { - exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl)) -} - -private predicate shouldPrintInstruction(Instruction i) { - exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i)) -} - -private predicate shouldPrintOperand(Operand operand) { - exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand)) -} - -private string getAdditionalInstructionProperty(Instruction instr, string key) { - exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key)) -} - -private string getAdditionalBlockProperty(IRBlock block, string key) { - exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) -} - -/** - * Gets the properties of an operand from any active property providers. - */ -private string getAdditionalOperandProperty(Operand operand, string key) { - exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) -} - -/** - * Gets a string listing the properties of the operand and their corresponding values. If the - * operand has no properties, this predicate has no result. - */ -private string getOperandPropertyListString(Operand operand) { - result = - strictconcat(string key, string value | - value = getAdditionalOperandProperty(operand, key) - | - key + ":" + value, ", " - ) -} - -/** - * Gets a string listing the properties of the operand and their corresponding values. The list is - * surrounded by curly braces. If the operand has no properties, this predicate returns an empty - * string. - */ -private string getOperandPropertyString(Operand operand) { - result = "{" + getOperandPropertyListString(operand) + "}" - or - not exists(getOperandPropertyListString(operand)) and result = "" -} - -private newtype TPrintableIRNode = - TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or - TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or - TPrintableInstruction(Instruction instr) { - shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction()) - } - -/** - * A node to be emitted in the IR graph. - */ -abstract private class PrintableIRNode extends TPrintableIRNode { - abstract string toString(); - - /** - * Gets the location to be emitted for the node. - */ - abstract Language::Location getLocation(); - - /** - * Gets the label to be emitted for the node. - */ - abstract string getLabel(); - - /** - * Gets the order in which the node appears in its parent node. - */ - abstract int getOrder(); - - /** - * Gets the parent of this node. - */ - abstract PrintableIRNode getParent(); - - /** - * Gets the kind of graph represented by this node ("graph" or "tree"). - */ - string getGraphKind() { none() } - - /** - * Holds if this node should always be rendered as text, even in a graphical - * viewer. - */ - predicate forceText() { none() } - - /** - * Gets the value of the node property with the specified key. - */ - string getProperty(string key) { - key = "semmle.label" and result = this.getLabel() - or - key = "semmle.order" and result = this.getOrder().toString() - or - key = "semmle.graphKind" and result = this.getGraphKind() - or - key = "semmle.forceText" and this.forceText() and result = "true" - } -} - -/** - * An IR graph node representing a `IRFunction` object. - */ -private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { - IRFunction irFunc; - - PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } - - override string toString() { result = irFunc.toString() } - - override Language::Location getLocation() { result = irFunc.getLocation() } - - override string getLabel() { - result = Imports::LanguageDebug::getIdentityString(irFunc.getFunction()) - } - - override int getOrder() { - this = - rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location | - location = orderedFunc.getIRFunction().getLocation() - | - orderedFunc - order by - location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), - orderedFunc.getLabel() - ) - } - - final override PrintableIRNode getParent() { none() } - - final IRFunction getIRFunction() { result = irFunc } -} - -/** - * An IR graph node representing an `IRBlock` object. - */ -private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { - IRBlock block; - - PrintableIRBlock() { this = TPrintableIRBlock(block) } - - override string toString() { result = this.getLabel() } - - override Language::Location getLocation() { result = block.getLocation() } - - override string getLabel() { result = "Block " + block.getDisplayIndex().toString() } - - override int getOrder() { result = block.getDisplayIndex() } - - final override string getGraphKind() { result = "tree" } - - final override predicate forceText() { any() } - - final override PrintableIRFunction getParent() { - result.getIRFunction() = block.getEnclosingIRFunction() - } - - override string getProperty(string key) { - result = PrintableIRNode.super.getProperty(key) or - result = getAdditionalBlockProperty(block, key) - } - - final IRBlock getBlock() { result = block } -} - -/** - * An IR graph node representing an `Instruction`. - */ -private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { - Instruction instr; - - PrintableInstruction() { this = TPrintableInstruction(instr) } - - override string toString() { result = instr.toString() } - - override Language::Location getLocation() { result = instr.getLocation() } - - override string getLabel() { - exists(IRBlock block | - instr = block.getAnInstruction() and - exists( - string resultString, string operationString, string operandsString, int resultWidth, - int operationWidth - | - resultString = instr.getResultString() and - operationString = instr.getOperationString() and - operandsString = this.getOperandsString() and - columnWidths(block, resultWidth, operationWidth) and - result = - resultString + getPaddingString(resultWidth - resultString.length()) + " = " + - operationString + getPaddingString(operationWidth - operationString.length()) + " : " + - operandsString - ) - ) - } - - override int getOrder() { result = instr.getDisplayIndexInBlock() } - - final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() } - - final Instruction getInstruction() { result = instr } - - override string getProperty(string key) { - result = PrintableIRNode.super.getProperty(key) or - result = getAdditionalInstructionProperty(instr, key) - } - - /** - * Gets the string representation of the operand list. This is the same as - * `Instruction::getOperandsString()`, except that each operand is annotated with any properties - * provided by active `IRPropertyProvider` instances. - */ - private string getOperandsString() { - result = - concat(Operand operand | - operand = instr.getAnOperand() and - shouldPrintOperand(operand) - | - operand.getDumpString() + getOperandPropertyString(operand), ", " - order by - operand.getDumpSortOrder() - ) - } -} - -private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { - resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and - operationWidth = - max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length()) -} - -private int maxColumnWidth() { - result = - max(Instruction instr, int width | - width = instr.getResultString().length() or - width = instr.getOperationString().length() or - width = instr.getOperandsString().length() - | - width - ) -} - -private string getPaddingString(int n) { - n = 0 and result = "" - or - n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " -} - -/** - * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. - */ -query predicate nodes(PrintableIRNode node, string key, string value) { - value = node.getProperty(key) -} - -private int getSuccessorIndex(IRBlock pred, IRBlock succ) { - succ = - rank[result + 1](IRBlock aSucc, EdgeKind kind | - aSucc = pred.getSuccessor(kind) - | - aSucc order by kind.toString() - ) -} - -/** - * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` - * has the given `value`. - */ -query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | - predBlock = pred.getBlock() and - succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and - ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() - ) - or - key = "semmle.order" and - value = getSuccessorIndex(predBlock, succBlock).toString() - ) - ) -} - -/** - * Holds if `parent` is the parent node of `child` in the output graph. - */ -query predicate parents(PrintableIRNode child, PrintableIRNode parent) { - parent = child.getParent() -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll deleted file mode 100644 index aac2e679a97..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll +++ /dev/null @@ -1,62 +0,0 @@ -private import internal.ConstantAnalysisInternal -private import experimental.ir.internal.IntegerPartial -private import IR - -language[monotonicAggregates] -int getConstantValue(Instruction instr) { - result = instr.(IntegerConstantInstruction).getValue().toInt() - or - result = getBinaryInstructionValue(instr) - or - result = neg(getConstantValue(instr.(NegateInstruction).getUnary())) - or - result = getConstantValue(instr.(CopyInstruction).getSourceValue()) - or - exists(PhiInstruction phi | - phi = instr and - result = max(Instruction def | def = phi.getAnInput() | getConstantValueToPhi(def)) and - result = min(Instruction def | def = phi.getAnInput() | getConstantValueToPhi(def)) - ) -} - -pragma[noinline] -int getConstantValueToPhi(Instruction def) { - exists(PhiInstruction phi | - result = getConstantValue(def) and - def = phi.getAnInput() - ) -} - -pragma[noinline] -private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) { - left = getConstantValue(instr.getLeft()) and - right = getConstantValue(instr.getRight()) -} - -pragma[noinline] -private int getBinaryInstructionValue(BinaryInstruction instr) { - exists(int left, int right | - binaryInstructionOperands(instr, left, right) and - ( - instr instanceof AddInstruction and result = add(left, right) - or - instr instanceof SubInstruction and result = sub(left, right) - or - instr instanceof MulInstruction and result = mul(left, right) - or - instr instanceof DivInstruction and result = div(left, right) - or - instr instanceof CompareEQInstruction and result = compareEQ(left, right) - or - instr instanceof CompareNEInstruction and result = compareNE(left, right) - or - instr instanceof CompareLTInstruction and result = compareLT(left, right) - or - instr instanceof CompareGTInstruction and result = compareGT(left, right) - or - instr instanceof CompareLEInstruction and result = compareLE(left, right) - or - instr instanceof CompareGEInstruction and result = compareGE(left, right) - ) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll deleted file mode 100644 index 53f9295be4f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll +++ /dev/null @@ -1,11 +0,0 @@ -private import internal.ConstantAnalysisInternal -private import experimental.ir.internal.IntegerConstant -private import ConstantAnalysis -import IR - -private class ConstantAnalysisPropertyProvider extends IRPropertyProvider { - override string getInstructionProperty(Instruction instr, string key) { - key = "ConstantValue" and - result = getValue(getConstantValue(instr)).toString() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index 6e2340af7ea..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll deleted file mode 100644 index a7fb1b3c07e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll +++ /dev/null @@ -1,17 +0,0 @@ -private import internal.ValueNumberingImports -private import ValueNumbering - -/** - * Provides additional information about value numbering in IR dumps. - */ -class ValueNumberPropertyProvider extends IRPropertyProvider { - override string getInstructionProperty(Instruction instr, string key) { - exists(ValueNumber vn | - vn = valueNumber(instr) and - key = "valnum" and - if strictcount(vn.getAnInstruction()) > 1 - then result = vn.getDebugString() - else result = "unique" - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll deleted file mode 100644 index 2a46e16c52f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll +++ /dev/null @@ -1,90 +0,0 @@ -private import internal.ValueNumberingInternal -private import internal.ValueNumberingImports - -/** - * The value number assigned to a particular set of instructions that produce equivalent results. - */ -class ValueNumber extends TValueNumber { - final string toString() { result = "GVN" } - - final string getDebugString() { - result = strictconcat(this.getAnInstruction().getResultId(), ", ") - } - - final Language::Location getLocation() { - if - exists(Instruction i | - i = this.getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation - ) - then - result = - min(Language::Location l | - l = this.getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation - | - l - order by - l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), - l.getEndColumn() - ) - else result instanceof Language::UnknownDefaultLocation - } - - /** - * Gets the instructions that have been assigned this value number. This will always produce at - * least one result. - */ - final Instruction getAnInstruction() { this = valueNumber(result) } - - /** - * Gets one of the instructions that was assigned this value number. The chosen instruction is - * deterministic but arbitrary. Intended for use only in debugging. - */ - final Instruction getExampleInstruction() { - result = - min(Instruction instr | - instr = this.getAnInstruction() - | - instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() - ) - } - - /** - * Gets an `Operand` whose definition is exact and has this value number. - */ - final Operand getAUse() { this = valueNumber(result.getDef()) } - - final string getKind() { - this instanceof TVariableAddressValueNumber and result = "VariableAddress" - or - this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" - or - this instanceof TConstantValueNumber and result = "Constant" - or - this instanceof TStringConstantValueNumber and result = "StringConstant" - or - this instanceof TFieldAddressValueNumber and result = "FieldAddress" - or - this instanceof TBinaryValueNumber and result = "Binary" - or - this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic" - or - this instanceof TUnaryValueNumber and result = "Unary" - or - this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion" - or - this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap" - or - this instanceof TUniqueValueNumber and result = "Unique" - } -} - -/** - * Gets the value number assigned to `instr`, if any. Returns at most one result. - */ -ValueNumber valueNumber(Instruction instr) { result = tvalueNumber(instr) } - -/** - * Gets the value number assigned to the exact definition of `op`, if any. - * Returns at most one result. - */ -ValueNumber valueNumberOfOperand(Operand op) { result = tvalueNumberOfOperand(op) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 34bd754692d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.internal.Overlap -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll deleted file mode 100644 index ec003891774..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ /dev/null @@ -1,356 +0,0 @@ -private import ValueNumberingImports - -newtype TValueNumber = - TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { - variableAddressValueNumber(_, irFunc, ast) - } or - TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { - initializeParameterValueNumber(_, irFunc, var) - } or - TConstantValueNumber(IRFunction irFunc, IRType type, string value) { - constantValueNumber(_, irFunc, type, value) - } or - TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { - stringConstantValueNumber(_, irFunc, type, value) - } or - TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { - fieldAddressValueNumber(_, irFunc, field, objectAddress) - } or - TBinaryValueNumber( - IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand - ) { - binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand) - } or - TPointerArithmeticValueNumber( - IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand, - TValueNumber rightOperand - ) { - pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand) - } or - TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) { - unaryValueNumber(_, irFunc, opcode, operand) - } or - TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - TValueNumber operand - ) { - inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) - } or - TLoadTotalOverlapValueNumber( - IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand - ) { - loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand) - } or - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - -/** - * A `CopyInstruction` whose source operand's value is congruent to the definition of that source - * operand. - * For example: - * ``` - * Point p = { 1, 2 }; - * Point q = p; - * int a = p.x; - * ``` - * The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that - * definition because it accesses the exact same memory. - * The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not - * congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`. - */ -class CongruentCopyInstruction extends CopyInstruction { - CongruentCopyInstruction() { - this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap - } -} - -class LoadTotalOverlapInstruction extends LoadInstruction { - LoadTotalOverlapInstruction() { - this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap - } -} - -/** - * Holds if this library knows how to assign a value number to the specified instruction, other than - * a `unique` value number that is never shared by multiple instructions. - */ -private predicate numberableInstruction(Instruction instr) { - instr instanceof VariableAddressInstruction - or - instr instanceof InitializeParameterInstruction - or - instr instanceof ConstantInstruction - or - instr instanceof StringConstantInstruction - or - instr instanceof FieldAddressInstruction - or - instr instanceof BinaryInstruction - or - instr instanceof UnaryInstruction and not instr instanceof CopyInstruction - or - instr instanceof PointerArithmeticInstruction - or - instr instanceof CongruentCopyInstruction - or - instr instanceof LoadTotalOverlapInstruction -} - -private predicate filteredNumberableInstruction(Instruction instr) { - // count rather than strictcount to handle missing AST elements - // separate instanceof and inline casts to avoid failed casts with a count of 0 - instr instanceof VariableAddressInstruction and - count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1 - or - instr instanceof ConstantInstruction and - count(instr.getResultIRType()) != 1 - or - instr instanceof FieldAddressInstruction and - count(instr.(FieldAddressInstruction).getField()) != 1 - or - instr instanceof InheritanceConversionInstruction and - ( - count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or - count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1 - ) -} - -private predicate variableAddressValueNumber( - VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast -) { - instr.getEnclosingIRFunction() = irFunc and - // The underlying AST element is used as value-numbering key instead of the - // `IRVariable` to work around a problem where a variable or expression with - // multiple types gives rise to multiple `IRVariable`s. - unique( | | instr.getIRVariable().getAst()) = ast -} - -private predicate initializeParameterValueNumber( - InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var -) { - instr.getEnclosingIRFunction() = irFunc and - // The underlying AST element is used as value-numbering key instead of the - // `IRVariable` to work around a problem where a variable or expression with - // multiple types gives rise to multiple `IRVariable`s. - instr.getIRVariable().getAst() = var -} - -private predicate constantValueNumber( - ConstantInstruction instr, IRFunction irFunc, IRType type, string value -) { - instr.getEnclosingIRFunction() = irFunc and - unique( | | instr.getResultIRType()) = type and - instr.getValue() = value -} - -private predicate stringConstantValueNumber( - StringConstantInstruction instr, IRFunction irFunc, IRType type, string value -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and - instr.getValue().getValue() = value -} - -private predicate fieldAddressValueNumber( - FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, - TValueNumber objectAddress -) { - instr.getEnclosingIRFunction() = irFunc and - unique( | | instr.getField()) = field and - tvalueNumber(instr.getObjectAddress()) = objectAddress -} - -pragma[nomagic] -private predicate binaryValueNumber0( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, boolean isLeft, - TValueNumber valueNumber -) { - not instr instanceof PointerArithmeticInstruction and - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - ( - isLeft = true and - tvalueNumber(instr.getLeft()) = valueNumber - or - isLeft = false and - tvalueNumber(instr.getRight()) = valueNumber - ) -} - -private predicate binaryValueNumber( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, - TValueNumber rightOperand -) { - binaryValueNumber0(instr, irFunc, opcode, true, leftOperand) and - binaryValueNumber0(instr, irFunc, opcode, false, rightOperand) -} - -pragma[nomagic] -private predicate pointerArithmeticValueNumber0( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, - boolean isLeft, TValueNumber valueNumber -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - instr.getElementSize() = elementSize and - ( - isLeft = true and - tvalueNumber(instr.getLeft()) = valueNumber - or - isLeft = false and - tvalueNumber(instr.getRight()) = valueNumber - ) -} - -private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, - TValueNumber leftOperand, TValueNumber rightOperand -) { - pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, true, leftOperand) and - pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, false, rightOperand) -} - -private predicate unaryValueNumber( - UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand -) { - instr.getEnclosingIRFunction() = irFunc and - not instr instanceof InheritanceConversionInstruction and - not instr instanceof CopyInstruction and - not instr instanceof FieldAddressInstruction and - instr.getOpcode() = opcode and - tvalueNumber(instr.getUnary()) = operand -} - -private predicate inheritanceConversionValueNumber( - InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, - Language::Class baseClass, Language::Class derivedClass, TValueNumber operand -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - tvalueNumber(instr.getUnary()) = operand and - unique( | | instr.getBaseClass()) = baseClass and - unique( | | instr.getDerivedClass()) = derivedClass -} - -pragma[nomagic] -private predicate loadTotalOverlapValueNumber0( - LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber, - boolean isAddress -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and - ( - isAddress = true and - tvalueNumberOfOperand(instr.getSourceAddressOperand()) = valueNumber - or - isAddress = false and - tvalueNumber(instr.getSourceValueOperand().getAnyDef()) = valueNumber - ) -} - -private predicate loadTotalOverlapValueNumber( - LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand, - TValueNumber operand -) { - loadTotalOverlapValueNumber0(instr, irFunc, type, operand, true) and - loadTotalOverlapValueNumber0(instr, irFunc, type, memOperand, false) -} - -/** - * Holds if `instr` should be assigned a unique value number because this library does not know how - * to determine if two instances of that instruction are equivalent. - */ -private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc and - not instr.getResultIRType() instanceof IRVoidType and - ( - not numberableInstruction(instr) - or - filteredNumberableInstruction(instr) - ) -} - -/** - * Gets the value number assigned to `instr`, if any. Returns at most one result. - */ -cached -TValueNumber tvalueNumber(Instruction instr) { - result = nonUniqueValueNumber(instr) - or - exists(IRFunction irFunc | - uniqueValueNumber(instr, irFunc) and - result = TUniqueValueNumber(irFunc, instr) - ) -} - -/** - * Gets the value number assigned to the exact definition of `op`, if any. - * Returns at most one result. - */ -TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) } - -/** - * Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique - * value number. - */ -private TValueNumber nonUniqueValueNumber(Instruction instr) { - exists(IRFunction irFunc | - irFunc = instr.getEnclosingIRFunction() and - ( - exists(Language::AST ast | - variableAddressValueNumber(instr, irFunc, ast) and - result = TVariableAddressValueNumber(irFunc, ast) - ) - or - exists(Language::AST var | - initializeParameterValueNumber(instr, irFunc, var) and - result = TInitializeParameterValueNumber(irFunc, var) - ) - or - exists(string value, IRType type | - constantValueNumber(instr, irFunc, type, value) and - result = TConstantValueNumber(irFunc, type, value) - ) - or - exists(IRType type, string value | - stringConstantValueNumber(instr, irFunc, type, value) and - result = TStringConstantValueNumber(irFunc, type, value) - ) - or - exists(Language::Field field, TValueNumber objectAddress | - fieldAddressValueNumber(instr, irFunc, field, objectAddress) and - result = TFieldAddressValueNumber(irFunc, field, objectAddress) - ) - or - exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand | - binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and - result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand) - ) - or - exists(Opcode opcode, TValueNumber operand | - unaryValueNumber(instr, irFunc, opcode, operand) and - result = TUnaryValueNumber(irFunc, opcode, operand) - ) - or - exists( - Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand - | - inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and - result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) - ) - or - exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand | - pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and - result = - TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand) - ) - or - exists(IRType type, TValueNumber memOperand, TValueNumber operand | - loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and - result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand) - ) - or - // The value number of a copy is just the value number of its source value. - result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll deleted file mode 100644 index c80761a68cf..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConsistencyImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConsistencyImports.qll deleted file mode 100644 index f43546fe76d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConsistencyImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguageDebug as LanguageDebug diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll deleted file mode 100644 index 5811f2ff946..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll +++ /dev/null @@ -1,435 +0,0 @@ -import csharp -import experimental.ir.implementation.raw.IR -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.implementation.internal.IRFunctionBase -private import experimental.ir.implementation.internal.TInstruction -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.Overlap -private import experimental.ir.internal.TempVariableTag -private import InstructionTag -private import TranslatedCondition -private import TranslatedElement -private import TranslatedExpr -private import TranslatedStmt -private import desugar.Foreach -private import TranslatedFunction -private import experimental.ir.internal.IRCSharpLanguage as Language - -TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(result, _) -} - -InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, result) -} - -pragma[noinline] -private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag -) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) -} - -class TStageInstruction = TRawInstruction; - -/** - * Provides the portion of the parameterized IR interface that is used to construct the initial - * "raw" stage of the IR. The other stages of the IR do not expose these predicates. - */ -cached -module Raw { - class InstructionTag1 = TranslatedElement; - - class InstructionTag2 = InstructionTag; - - cached - predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) } - - cached - predicate varHasIRFunc(Field field) { none() } - - cached - predicate hasInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } - - cached - predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { - getTranslatedFunction(callable).hasUserVariable(var, type) - } - - cached - predicate hasTempVariable( - Callable callable, Language::AST ast, TempVariableTag tag, CSharpType type - ) { - exists(TranslatedElement element | - element.getAst() = ast and - callable = element.getFunction() and - element.hasTempVariable(tag, type) - ) - } - - cached - predicate hasStringLiteral( - Callable callable, Language::AST ast, CSharpType type, StringLiteral literal - ) { - literal = ast and - literal.getEnclosingCallable() = callable and - getTypeForPRValue(literal.getType()) = type - } - - cached - predicate hasDynamicInitializationFlag(Callable callable, Language::Variable var, CSharpType type) { - none() - } - - cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { - exists(TranslatedExpr translatedExpr | - translatedExpr = getTranslatedExpr(result) and - instruction = translatedExpr.getResult() - ) - } - - cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - exists(Expr converted, TranslatedExpr translatedExpr | result = converted.stripCasts() | - translatedExpr = getTranslatedExpr(converted) and - instruction = translatedExpr.getResult() - ) - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and - ( - result = element.getInstructionVariable(tag) or - result.(IRStringLiteral).getAst() = element.getInstructionStringLiteral(tag) - ) - ) - } - - cached - Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) - } - - cached - int getInstructionIndex(Instruction instruction) { none() } - - cached - Callable getInstructionFunction(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionFunction(getInstructionTag(instruction)) - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionConstantValue(getInstructionTag(instruction)) - } - - cached - CSharpType getInstructionExceptionType(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionExceptionType(getInstructionTag(instruction)) - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { - getInstructionTranslatedElement(instruction) - .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) - } - - cached - int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } -} - -import Cached - -cached -private module Cached { - cached - predicate getInstructionOpcode(Opcode opcode, TRawInstruction instr) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instr, element, tag) and - element.hasInstruction(opcode, tag, _) - ) - } - - cached - IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) { - result.getFunction() = getInstructionTranslatedElement(instr).getFunction() - } - - cached - predicate hasInstruction(TRawInstruction instr) { any() } - - cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - - cached - Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) - } - - cached - Instruction getMemoryOperandDefinition( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - overlap instanceof MustTotallyOverlap and - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) - } - - /** Gets a non-phi instruction that defines an operand of `instr`. */ - private Instruction getNonPhiOperandDef(Instruction instr) { - result = getRegisterOperandDefinition(instr, _) - or - result = getMemoryOperandDefinition(instr, _, _) - } - - /** - * Holds if the operand totally overlaps with its definition and consumes the - * bit range `[startBitOffset, endBitOffset)`. - */ - cached - predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() } - - cached - predicate chiOnlyPartiallyUpdatesLocation(ChiInstruction chi) { none() } - - /** - * Holds if `instr` is part of a cycle in the operand graph that doesn't go - * through a phi instruction and therefore should be impossible. - * - * If such cycles are present, either due to a programming error in the IR - * generation or due to a malformed database, it can cause infinite loops in - * analyses that assume a cycle-free graph of non-phi operands. Therefore it's - * better to remove these operands than to leave cycles in the operand graph. - */ - pragma[noopt] - cached - predicate isInCycle(Instruction instr) { - instr instanceof Instruction and - getNonPhiOperandDef+(instr) = instr - } - - cached - CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { - // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as - // the result type of the load. - if instruction instanceof LoadInstruction - then result = instruction.(LoadInstruction).getResultLanguageType() - else - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperandType(getInstructionTag(instruction), tag) - } - - cached - Instruction getPhiOperandDefinition( - PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap - ) { - none() - } - - cached - Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } - - cached - Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionSuccessor(getInstructionTag(instruction), kind) - } - - // This predicate has pragma[noopt] because otherwise the `getAChild*` calls - // get joined too early. The join order for the loop cases goes like this: - // - Find all loops of that type (tens of thousands). - // - Find all edges into the start of the loop (x 2). - // - Restrict to edges that originate within the loop (/ 2). - pragma[noopt] - cached - Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { - // While loop: - // Any edge from within the body of the loop to the condition of the loop - // is a back edge. This includes edges from `continue` and the fall-through - // edge(s) after the last instruction(s) in the body. - exists(TranslatedWhileStmt s | - s instanceof TranslatedWhileStmt and - result = s.getFirstConditionInstruction() and - exists(TranslatedElement inBody, InstructionTag tag | - result = inBody.getInstructionSuccessor(tag, kind) and - exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and - instruction = inBody.getInstruction(tag) - ) - ) - or - // Compiler generated foreach while loop: - // Same as above - exists(TranslatedForeachWhile s | - result = s.getFirstInstruction() and - exists(TranslatedElement inBody, InstructionTag tag | - result = inBody.getInstructionSuccessor(tag, kind) and - exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and - instruction = inBody.getInstruction(tag) - ) - ) - or - // Do-while loop: - // The back edge should be the edge(s) from the condition to the - // body. This ensures that it's the back edge that will be pruned in a `do - // { ... } while (0)` statement. Note that all `continue` statements in a - // do-while loop produce forward edges. - exists(TranslatedDoStmt s | - s instanceof TranslatedDoStmt and - exists(TranslatedStmt body | body = s.getBody() | result = body.getFirstInstruction()) and - exists(TranslatedElement inCondition, InstructionTag tag | - result = inCondition.getInstructionSuccessor(tag, kind) and - exists(TranslatedElement condition | condition = s.getCondition() | - inCondition = condition.getAChild*() - ) and - instruction = inCondition.getInstruction(tag) - ) - ) - or - // For loop: - // Any edge from within the body or update of the loop to the condition of - // the loop is a back edge. When there is no loop update expression, this - // includes edges from `continue` and the fall-through edge(s) after the - // last instruction(s) in the body. A for loop may not have a condition, in - // which case `getFirstConditionInstruction` returns the body instead. - exists(TranslatedForStmt s | - s instanceof TranslatedForStmt and - result = s.getFirstConditionInstruction() and - exists(TranslatedElement inLoop, InstructionTag tag | - result = inLoop.getInstructionSuccessor(tag, kind) and - exists(TranslatedElement bodyOrUpdate | - bodyOrUpdate = s.getBody() - or - bodyOrUpdate = s.getUpdate(_) - | - inLoop = bodyOrUpdate.getAChild*() - ) and - instruction = inLoop.getInstruction(tag) - ) - ) - or - // Goto statement: - // As a conservative approximation, any edge out of `goto` is a back edge - // unless it goes strictly forward in the program text. A `goto` whose - // source and target are both inside a macro will be seen as having the - // same location for source and target, so we conservatively assume that - // such a `goto` creates a back edge. - exists(TranslatedElement s, GotoStmt goto | - goto instanceof GotoStmt and - not isStrictlyForwardGoto(goto) and - goto = s.getAst() and - exists(InstructionTag tag | - result = s.getInstructionSuccessor(tag, kind) and - instruction = s.getInstruction(tag) - ) - ) - } - - /** Holds if `goto` jumps strictly forward in the program text. */ - private predicate isStrictlyForwardGoto(GotoLabelStmt goto) { - goto.getLocation().getFile() = goto.getTarget().getLocation().getFile() and - goto.getLocation().getEndLine() < goto.getTarget().getLocation().getStartLine() - } - - cached - Language::AST getInstructionAst(Instruction instruction) { - result = getInstructionTranslatedElement(instruction).getAst() - } - - cached - CSharpType getInstructionResultType(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), result) - } - - cached - ArrayAccess getInstructionArrayAccess(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionArrayAccess(getInstructionTag(instruction)) - } - - cached - int getInstructionResultSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionResultSize(tag) - ) - } - - cached - Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getPrimaryInstructionForSideEffect(tag) - ) - } -} - -predicate hasUnreachedInstruction(IRFunction func) { none() } - -import CachedForDebugging - -cached -private module CachedForDebugging { - cached - string getTempVariableUniqueId(IRTempVariable var) { - exists(TranslatedElement element | - var = element.getTempVariable(_) and - result = element.getId().toString() + ":" + getTempVariableTagId(var.getTag()) - ) - } - - cached - predicate instructionHasSortKeys(Instruction instruction, int key1, int key2) { - key1 = getInstructionTranslatedElement(instruction).getId() and - getInstructionTag(instruction) = - rank[key2](InstructionTag tag, string tagId | - tagId = getInstructionTagId(tag) - | - tag order by tagId - ) - } - - cached - string getInstructionUniqueId(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction).getId() + ":" + - getInstructionTagId(getInstructionTag(instruction)) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll deleted file mode 100644 index 4e9a7d9f3ae..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll deleted file mode 100644 index 14dad7400b2..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll deleted file mode 100644 index e44184dd76c..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll +++ /dev/null @@ -1,4 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import IRConstruction as Construction -import experimental.ir.implementation.IRConfiguration as IRConfiguration -import IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll deleted file mode 100644 index bdb4377cbdc..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.TempVariableTag as TempVariableTag -import experimental.ir.internal.IRUtilities as IRUtilities -import experimental.ir.internal.TempVariableTag as TTempVariableTag -import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll deleted file mode 100644 index 4bcd2e127c1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind -import experimental.ir.implementation.Opcode as Opcode -import experimental.ir.implementation.internal.OperandTag as OperandTag -import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll deleted file mode 100644 index 3ec2d846254..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll +++ /dev/null @@ -1,204 +0,0 @@ -import csharp -import experimental.ir.Util - -private predicate elementIsInitialized(int elementIndex) { - exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex)) -} - -newtype TInstructionTag = - OnlyInstructionTag() or // Single instruction (not including implicit Load) - InitializeThisTag() or - InitializerVariableAddressTag() or - InitializerLoadStringTag() or - InitializerStoreTag() or - ZeroPadStringConstantTag() or - ZeroPadStringElementIndexTag() or - ZeroPadStringElementAddressTag() or - ZeroPadStringStoreTag() or - AssignOperationLoadTag() or - AssignOperationConvertLeftTag() or - AssignOperationOpTag() or - AssignmentConvertRightTag() or - AssignOperationConvertResultTag() or - AssignmentStoreTag() or - CrementLoadTag() or - CrementConstantTag() or - CrementOpTag() or - CrementStoreTag() or - EnterFunctionTag() or - ReturnValueAddressTag() or - ReturnTag() or - ExitFunctionTag() or - AliasedDefinitionTag() or - AliasedUseTag() or - SwitchBranchTag() or - CallTargetTag() or - CallTag() or - CallSideEffectTag() or - AllocationSizeTag() or - AllocationElementSizeTag() or - AllocationExtentConvertTag() or - ValueConditionConditionalBranchTag() or - ConditionValueTrueTempAddressTag() or - ConditionValueTrueConstantTag() or - ConditionValueTrueStoreTag() or - ConditionValueFalseTempAddressTag() or - ConditionValueFalseConstantTag() or - ConditionValueFalseStoreTag() or - ConditionValueResultTempAddressTag() or - ConditionValueResultLoadTag() or - BoolConversionConstantTag() or - BoolConversionCompareTag() or - LoadTag() or // Implicit load due to lvalue-to-rvalue conversion - AddressTag() or - CatchTag() or - ThrowTag() or - UnwindTag() or - InitializerUninitializedTag() or - InitializerElementIndexTag(int elementIndex) { elementIsInitialized(elementIndex) } or - InitializerElementAddressTag(int elementIndex) { elementIsInitialized(elementIndex) } or - InitializerElementDefaultValueTag(int elementIndex) { elementIsInitialized(elementIndex) } or - InitializerElementDefaultValueStoreTag(int elementIndex) { elementIsInitialized(elementIndex) } or - // Added for C# - NewObjTag() or - // TODO: remove the need for indexing - PointerAddTag(int index) { index in [0 .. 255] } or - ElementsAddressTag(int index) { index in [0 .. 255] } or - ConvertTag() or - GeneratedNeqTag() or - GeneratedConstantTag() or - GeneratedBranchTag() - -class InstructionTag extends TInstructionTag { - final string toString() { result = "Tag" } -} - -/** - * Gets a unique string for the instruction tag. Primarily used for generating - * instruction IDs to ensure stable IR dumps. - */ -string getInstructionTagId(TInstructionTag tag) { - tag = OnlyInstructionTag() and result = "Only" // Single instruction (not including implicit Load) - or - tag = InitializerVariableAddressTag() and result = "InitVarAddr" - or - tag = InitializerLoadStringTag() and result = "InitLoadStr" - or - tag = InitializerStoreTag() and result = "InitStore" - or - tag = InitializerUninitializedTag() and result = "InitUninit" - or - tag = ZeroPadStringConstantTag() and result = "ZeroPadConst" - or - tag = ZeroPadStringElementIndexTag() and result = "ZeroPadElemIndex" - or - tag = ZeroPadStringElementAddressTag() and result = "ZeroPadElemAddr" - or - tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" - or - tag = AssignOperationLoadTag() and result = "AssignOpLoad" - or - tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" - or - tag = AssignmentConvertRightTag() and result = "AssignConvRight" - or - tag = AssignOperationOpTag() and result = "AssignOpOp" - or - tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" - or - tag = AssignmentStoreTag() and result = "AssignStore" - or - tag = CrementLoadTag() and result = "CrementLoad" - or - tag = CrementConstantTag() and result = "CrementConst" - or - tag = CrementOpTag() and result = "CrementOp" - or - tag = CrementStoreTag() and result = "CrementStore" - or - tag = EnterFunctionTag() and result = "EnterFunc" - or - tag = ReturnValueAddressTag() and result = "RetValAddr" - or - tag = ReturnTag() and result = "Ret" - or - tag = ExitFunctionTag() and result = "ExitFunc" - or - tag = AliasedDefinitionTag() and result = "AliasedDef" - or - tag = AliasedUseTag() and result = "AliasedUse" - or - tag = SwitchBranchTag() and result = "SwitchBranch" - or - tag = CallTargetTag() and result = "CallTarget" - or - tag = CallTag() and result = "Call" - or - tag = CallSideEffectTag() and result = "CallSideEffect" - or - tag = AllocationSizeTag() and result = "AllocSize" - or - tag = AllocationElementSizeTag() and result = "AllocElemSize" - or - tag = AllocationExtentConvertTag() and result = "AllocExtConv" - or - tag = ValueConditionConditionalBranchTag() and result = "ValCondCondBranch" - or - tag = ConditionValueTrueTempAddressTag() and result = "CondValTrueTempAddr" - or - tag = ConditionValueTrueConstantTag() and result = "CondValTrueConst" - or - tag = ConditionValueTrueStoreTag() and result = "CondValTrueStore" - or - tag = ConditionValueFalseTempAddressTag() and result = "CondValFalseTempAddr" - or - tag = ConditionValueFalseConstantTag() and result = "CondValFalseConst" - or - tag = ConditionValueFalseStoreTag() and result = "CondValFalseStore" - or - tag = ConditionValueResultTempAddressTag() and result = "CondValResTempAddr" - or - tag = ConditionValueResultLoadTag() and result = "CondValResLoad" - or - tag = BoolConversionConstantTag() and result = "BoolConvConst" - or - tag = BoolConversionCompareTag() and result = "BoolConvComp" - or - tag = LoadTag() and result = "Load" // Implicit load due to lvalue-to-rvalue conversion - or - tag = CatchTag() and result = "Catch" - or - tag = ThrowTag() and result = "Throw" - or - tag = UnwindTag() and result = "Unwind" - or - // Added for C# - tag = NewObjTag() and result = "NewObj" - or - tag = ElementsAddressTag(_) and result = "ElementsAddress" - or - tag = PointerAddTag(_) and result = "PointerAdd" - or - tag = ConvertTag() and result = "Convert" - or - tag = GeneratedNeqTag() and result = "GeneratedNEQTag" - or - tag = GeneratedConstantTag() and result = "GeneratedConstantTag" - or - tag = GeneratedBranchTag() and result = "GeneratedBranchTag" - or - tag = AddressTag() and result = "AddressTag" - or - exists(int index, string tagName | - ( - tag = InitializerElementIndexTag(index) and tagName = "InitElemIndex" - or - tag = InitializerElementAddressTag(index) and tagName = "InitElemAddr" - or - tag = InitializerElementDefaultValueTag(index) and tagName = "InitElemDefVal" - or - tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore" - ) and - result = tagName + "(" + index + ")" - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll deleted file mode 100644 index 65676caf724..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.internal.Overlap as Overlap -import experimental.ir.implementation.internal.OperandTag as OperandTag -import experimental.ir.implementation.internal.TOperand as TOperand diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll deleted file mode 100644 index 771aeb9033c..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -private import experimental.ir.implementation.internal.TOperand -import RawOperands diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll deleted file mode 100644 index 0c5337d57de..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.IRConfiguration as IRConfiguration -import experimental.ir.internal.IRCSharpLanguageDebug as LanguageDebug diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll deleted file mode 100644 index e131a26be65..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll +++ /dev/null @@ -1,102 +0,0 @@ -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import InstructionTag -private import TranslatedElement -private import TranslatedExpr -private import TranslatedInitialization -private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase -private import experimental.ir.internal.IRCSharpLanguage as Language - -/** - * The IR translation of a call to a function. The function can be a normal function - * (e.g. `MethodCall`) or a constructor call (e.g. `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). - */ -abstract class TranslatedCall extends TranslatedExpr, TranslatedCallBase { - final override Instruction getResult() { result = TranslatedCallBase.super.getResult() } -} - -/** - * Represents the IR translation of a direct function call. The call can be one of the following: - * `MethodCall`, `LocalFunctionCall`, `AccessorCall`, `OperatorCall`. - * Note that `DelegateCall`s are not treated here since they need to be desugared. - */ -class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall { - override Call expr; - - TranslatedFunctionCall() { - expr instanceof MethodCall or - expr instanceof LocalFunctionCall or - expr instanceof AccessorCall or - expr instanceof OperatorCall - } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and result = expr.getTarget() - } - - override TranslatedExpr getArgument(int index) { - result = getTranslatedExpr(expr.getArgument(index)) - } - - override TranslatedExpr getQualifier() { - expr instanceof QualifiableExpr and - result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier()) - } - - override Instruction getQualifierResult() { - // since `ElementInitializer`s do not have a qualifier, the qualifier's result is retrieved - // from the enclosing initialization context - if expr.getParent() instanceof CollectionInitializer - then result = getTranslatedExpr(expr.getParent()).(InitializationContext).getTargetAddress() - else result = this.getQualifier().getResult() - } - - override Type getCallResultType() { result = expr.getTarget().getReturnType() } - - override predicate hasReadSideEffect() { - not expr.getTarget().(SideEffectFunction).neverReadsMemory() - } - - override predicate hasWriteSideEffect() { - not expr.getTarget().(SideEffectFunction).neverWritesMemory() - } -} - -/** - * Represents the IR translation of a call to a constructor or to a constructor initializer. - * The qualifier of the call is obtained from the constructor call context. - * Note that `DelegateCreation` is not present here, since the call to a delegate constructor is - * compiler generated. - */ -class TranslatedConstructorCall extends TranslatedNonConstantExpr, TranslatedCall { - override Call expr; - - TranslatedConstructorCall() { - expr instanceof ObjectCreation or - expr instanceof ConstructorInitializer - } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and result = expr.getTarget() - } - - override TranslatedExpr getArgument(int index) { - result = getTranslatedExpr(expr.getArgument(index)) - } - - // The qualifier for a constructor call has already been generated - // (the `NewObj` instruction) - override TranslatedExpr getQualifier() { none() } - - override Type getCallResultType() { result instanceof VoidType } - - override Instruction getQualifierResult() { - exists(ConstructorCallContext context | - context = this.getParent() and - result = context.getReceiver() - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll deleted file mode 100644 index afe98fdb410..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll +++ /dev/null @@ -1,164 +0,0 @@ -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import InstructionTag -private import TranslatedElement -private import TranslatedExpr -private import common.TranslatedConditionBase -private import experimental.ir.internal.IRCSharpLanguage as Language - -TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr } - -abstract class TranslatedCondition extends ConditionBase { - Expr expr; - - final override string toString() { result = expr.toString() } - - final override Language::AST getAst() { result = expr } - - final Expr getExpr() { result = expr } - - final override Callable getFunction() { result = expr.getEnclosingCallable() } - - final Type getResultType() { result = expr.getType() } -} - -abstract class TranslatedFlexibleCondition extends TranslatedCondition, ConditionContext, - TTranslatedFlexibleCondition -{ - TranslatedFlexibleCondition() { this = TTranslatedFlexibleCondition(expr) } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - final override Instruction getFirstInstruction() { - result = this.getOperand().getFirstInstruction() - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - final override Instruction getChildSuccessor(TranslatedElement child) { none() } - - abstract TranslatedCondition getOperand(); -} - -class TranslatedParenthesisCondition extends TranslatedFlexibleCondition { - override ParenthesizedExpr expr; - - final override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getOperand() and - result = this.getConditionContext().getChildTrueSuccessor(this) - } - - final override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getOperand() and - result = this.getConditionContext().getChildFalseSuccessor(this) - } - - final override TranslatedCondition getOperand() { - result = getTranslatedCondition(expr.getExpr()) - } -} - -class TranslatedNotCondition extends TranslatedFlexibleCondition { - override LogicalNotExpr expr; - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getOperand() and - result = this.getConditionContext().getChildFalseSuccessor(this) - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getOperand() and - result = this.getConditionContext().getChildTrueSuccessor(this) - } - - override TranslatedCondition getOperand() { result = getTranslatedCondition(expr.getOperand()) } -} - -abstract class TranslatedNativeCondition extends TranslatedCondition, TTranslatedNativeCondition { - TranslatedNativeCondition() { this = TTranslatedNativeCondition(expr) } - - final override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeCondition, ConditionContext { - override BinaryLogicalOperation expr; - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getLeftOperand() - or - id = 1 and result = this.getRightOperand() - } - - final override Instruction getFirstInstruction() { - result = this.getLeftOperand().getFirstInstruction() - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - final TranslatedCondition getLeftOperand() { - result = getTranslatedCondition(expr.getLeftOperand()) - } - - final TranslatedCondition getRightOperand() { - result = getTranslatedCondition(expr.getRightOperand()) - } - - final TranslatedCondition getAnOperand() { - result = this.getLeftOperand() or - result = this.getRightOperand() - } -} - -class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation { - TranslatedLogicalAndExpr() { expr instanceof LogicalAndExpr } - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getLeftOperand() and - result = this.getRightOperand().getFirstInstruction() - or - child = this.getRightOperand() and - result = this.getConditionContext().getChildTrueSuccessor(this) - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getAnOperand() and - result = this.getConditionContext().getChildFalseSuccessor(this) - } -} - -class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation { - override LogicalOrExpr expr; - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getAnOperand() and - result = this.getConditionContext().getChildTrueSuccessor(this) - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getLeftOperand() and - result = this.getRightOperand().getFirstInstruction() - or - child = this.getRightOperand() and - result = this.getConditionContext().getChildFalseSuccessor(this) - } -} - -class TranslatedValueCondition extends TranslatedCondition, ValueConditionBase, - TTranslatedValueCondition -{ - TranslatedValueCondition() { this = TTranslatedValueCondition(expr) } - - override TranslatedExpr getValueExpr() { result = getTranslatedExpr(expr) } - - override Instruction valueExprResult() { result = this.getValueExpr().getResult() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll deleted file mode 100644 index 23242c75c74..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ /dev/null @@ -1,76 +0,0 @@ -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.internal.IRUtilities -private import experimental.ir.implementation.internal.OperandTag -private import InstructionTag -private import TranslatedElement -private import TranslatedExpr -private import TranslatedInitialization -private import experimental.ir.internal.IRCSharpLanguage as Language -private import common.TranslatedDeclarationBase - -/** - * Gets the `TranslatedDeclaration` that represents the declaration - * `entry`. - */ -TranslatedLocalDeclaration getTranslatedLocalDeclaration(LocalVariableDeclExpr declExpr) { - result.getAst() = declExpr -} - -/** - * Represents the IR translation of a declaration within the body of a function. - */ -abstract class TranslatedLocalDeclaration extends TranslatedElement, TTranslatedDeclaration { - LocalVariableDeclExpr expr; - - TranslatedLocalDeclaration() { this = TTranslatedDeclaration(expr) } - - final override Callable getFunction() { result = expr.getEnclosingCallable() } - - final override string toString() { result = expr.toString() } - - final override Language::AST getAst() { result = expr } -} - -/** - * Represents the IR translation of the declaration of a local variable, - * including its initialization, if any. - */ -class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, - LocalVariableDeclarationBase, InitializationContext -{ - LocalVariable var; - - TranslatedLocalVariableDeclaration() { var = expr.getVariable() } - - override Instruction getTargetAddress() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override LocalVariable getDeclVar() { result = var } - - override Type getVarType() { result = getVariableType(this.getDeclVar()) } - - override Type getTargetType() { result = getVariableType(var) } - - override IRVariable getInstructionVariable(InstructionTag tag) { - ( - tag = InitializerVariableAddressTag() - or - this.hasUninitializedInstruction() and tag = InitializerStoreTag() - ) and - result = getIRUserVariable(this.getFunction(), this.getDeclVar()) - } - - override TranslatedInitialization getInitialization() { - // First complex initializations - if var.getInitializer() instanceof ArrayCreation - then result = getTranslatedInitialization(var.getInitializer().(ArrayCreation).getInitializer()) - else - if var.getInitializer() instanceof ObjectCreation - then result = getTranslatedInitialization(var.getInitializer()) - else - // then the simple variable initialization - result = getTranslatedInitialization(var.getInitializer()) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll deleted file mode 100644 index c314d79e3ea..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ /dev/null @@ -1,569 +0,0 @@ -import csharp -import experimental.ir.implementation.raw.IR -private import experimental.ir.IRConfiguration -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.TempVariableTag -private import InstructionTag -private import TranslatedCondition -private import TranslatedFunction -private import TranslatedStmt -private import IRConstruction -private import experimental.ir.internal.IRCSharpLanguage as Language -private import desugar.Foreach -private import desugar.Delegate -private import desugar.Lock - -ArrayType getArrayOfDim(int dim, Type type) { - result.getRank() = dim and - result.getElementType() = type -} - -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAst() = ast and - result.getTag() = tag -} - -private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) { - generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1] - or - generatedBy instanceof LockStmt and nth in [0 .. LockElements::noGeneratedElements() - 1] - or - generatedBy instanceof DelegateCreation and - nth in [0 .. DelegateElements::noGeneratedElements(generatedBy) - 1] - or - generatedBy instanceof DelegateCall and - nth in [0 .. DelegateElements::noGeneratedElements(generatedBy) - 1] -} - -/** - * Gets the "real" parent of `expr`. This predicate treats conversions as if - * they were explicit nodes in the expression tree, rather than as implicit - * nodes as in the regular AST representation. - */ -private Element getRealParent(Expr expr) { result = expr.getParent() } - -/** - * Holds if `expr` is a constant of a type that can be replaced directly with - * its value in the IR. This does not include address constants as we have no - * means to express those as QL values. - */ -predicate isIRConstant(Expr expr) { exists(expr.getValue()) } - -// Pulled out for performance. See -// https://github.com/github/codeql-coreql-team/issues/1044. -private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) } - -/** - * Holds if `expr` should be ignored for the purposes of IR generation due to - * some property of `expr` or one of its ancestors. - */ -private predicate ignoreExprAndDescendants(Expr expr) { - // Ignore parentless expressions - isOrphan(expr) - or - // Ignore the constants in SwitchCase, since their values are embedded in the - // CaseEdge. - getRealParent(expr) instanceof CaseStmt - or - // Ignore descendants of constant expressions, since we'll just substitute the - // constant value. - isIRConstant(getRealParent(expr)) - or - // Ignore the local declaration done by a `ForeachStmt` - // since we desugar it - expr instanceof LocalVariableDeclExpr and - expr.getParent() instanceof ForeachStmt - or - // recursive case - ignoreExprAndDescendants(getRealParent(expr)) and - // The two children of an `AssignOperation` should not be ignored, but since they are also - // descendants of an orphan node (the expanded form of the `AssignOperation` is also retrieved by - // the extractor, which is rooted in an AST node without parents) they would be - not expr.getParent() instanceof AssignOperation -} - -/** - * Holds if `expr` (not including its descendants) should be ignored for the - * purposes of IR generation. - */ -private predicate ignoreExprOnly(Expr expr) { - not translateFunction(expr.getEnclosingCallable()) - or - // Ignore size of arrays when translating - expr.getParent() instanceof ArrayCreation and expr.hasValue() - or - // Ignore the child expression of a goto case stmt - expr.getParent() instanceof GotoCaseStmt - or - // Ignore the expression (that is not a declaration) - // that appears in a using block - expr.getParent().(UsingBlockStmt).getExpr() = expr - or - // Ignore the `ThisAccess` when it is used as the qualifier for - // a callable access (e.g. when a member callable is passed as a - // parameter for a delegate creation expression) - expr instanceof ThisAccess and - expr.getParent() instanceof CallableAccess -} - -/** - * Holds if `expr` should be ignored for the purposes of IR generation. - */ -private predicate ignoreExpr(Expr expr) { - ignoreExprOnly(expr) or - ignoreExprAndDescendants(expr) -} - -/** - * Holds if `func` should be translated to IR. - */ -private predicate translateFunction(Callable callable) { - // not isInvalidFunction(callable) - exists(callable.getEntryPoint()) and - callable.fromSource() and - exists(IRConfiguration config | config.shouldCreateIRForFunction(callable)) -} - -/** - * Holds if `stmt` should be translated to IR. - */ -private predicate translateStmt(Stmt stmt) { translateFunction(stmt.getEnclosingCallable()) } - -/** - * Holds if `expr` is most naturally evaluated as control flow, rather than as - * a value. - */ -private predicate isNativeCondition(Expr expr) { - expr instanceof BinaryLogicalOperation and - not isIRConstant(expr) -} - -/** - * Holds if `expr` can be evaluated as either a condition or a value expression, - * depending on context. - */ -private predicate isFlexibleCondition(Expr expr) { - ( - expr instanceof ParenthesizedExpr or - expr instanceof LogicalNotExpr - ) and - usedAsCondition(expr) and - not isIRConstant(expr) -} - -/** - * Holds if `expr` is used in a condition context, i.e. the Boolean result of - * the expression is directly used to determine control flow. - */ -private predicate usedAsCondition(Expr expr) { - exists(BinaryLogicalOperation op | - op.getLeftOperand() = expr or - op.getRightOperand() = expr - ) - or - exists(LoopStmt loop | loop.getCondition() = expr) - or - exists(IfStmt ifStmt | ifStmt.getCondition() = expr) - or - exists(ConditionalExpr condExpr | condExpr.getCondition() = expr) - or - exists(LogicalNotExpr notExpr | - notExpr.getOperand() = expr and - usedAsCondition(notExpr) - ) - or - exists(ParenthesizedExpr paren | - paren.getExpr() = expr and - usedAsCondition(paren) - ) -} - -/** - * Holds if we should have a `Load` instruction for `expr` when generating the IR. - */ -private predicate mayNeedLoad(Expr expr) { - expr instanceof AssignableRead - or - // We need an extra load for the `PointerIndirectionExpr` - expr instanceof PointerIndirectionExpr and - // If the dereferencing happens on the lhs of an - // assignment we shouldn't have a load instruction - not exists(Assignment a | a.getLValue() = expr) -} - -predicate needsLoad(Expr expr) { - mayNeedLoad(expr) and - not ignoreLoad(expr) -} - -/** - * Holds if we should ignore the `Load` instruction for `expr` when generating IR. - */ -private predicate ignoreLoad(Expr expr) { - // No load needed for the qualifier of an array access, - // since we use the instruction `ElementsAddress` - // to get the address of the first element in an array - expr = any(ArrayAccess aa).getQualifier() - or - // Indexer calls returns a reference or a value, - // no need to load it - expr instanceof IndexerCall - or - // No load is needed for the lvalue in an assignment such as: - // Eg. `Object obj = oldObj`; - expr = any(Assignment a).getLValue() and - expr.getType() instanceof RefType - or - // Since the loads for a crement operation is handled by the translation - // of the operation, we ignore the load here - expr.getParent() instanceof MutatorOperation - or - // The `&` operator does not need a load, since the - // address is the final value of the expression - expr.getParent() instanceof AddressOfExpr - or - // A property access does not need a load since it is a call - expr instanceof PropertyAccess - or - // If expr is a variable access used as the qualifier for a field access and - // its target variable is a value type variable, - // ignore the load since the address of a variable that is a value type is - // given by a single `VariableAddress` instruction. - expr = any(FieldAccess fa).getQualifier() and - expr = - any(VariableAccess va | - va.getType().isValueType() and - not va.getTarget() = any(Parameter p | p.isOutOrRef() or p.isIn()) - ) - or - // If expr is passed as an `out,`ref` or `in` argument, - // no load should take place since we pass the address, not the - // value of the variable - expr.(AssignableAccess).isOutOrRefArgument() - or - expr.(AssignableAccess).isInArgument() -} - -newtype TTranslatedElement = - // An expression that is not being consumed as a condition - TTranslatedValueExpr(Expr expr) { - not ignoreExpr(expr) and - not isNativeCondition(expr) and - not isFlexibleCondition(expr) - } or - // A creation expression - TTranslatedCreationExpr(Expr expr) { - not ignoreExpr(expr) and - (expr instanceof ObjectCreation or expr instanceof DelegateCreation) - } or - // A separate element to handle the lvalue-to-rvalue conversion step of an - // expression. - TTranslatedLoad(Expr expr) { - not ignoreExpr(expr) and - needsLoad(expr) - } or - // An expression most naturally translated as control flow. - TTranslatedNativeCondition(Expr expr) { - not ignoreExpr(expr) and - isNativeCondition(expr) - } or - // An expression that can best be translated as control flow given the context - // in which it is used. - TTranslatedFlexibleCondition(Expr expr) { - not ignoreExpr(expr) and - isFlexibleCondition(expr) - } or - // An expression that is not naturally translated as control flow, but is - // consumed in a condition context. This element adapts the original element - // to the condition context. - TTranslatedValueCondition(Expr expr) { - not ignoreExpr(expr) and - not isNativeCondition(expr) and - not isFlexibleCondition(expr) and - usedAsCondition(expr) - } or - // An expression that is naturally translated as control flow, but is used in - // a context where a simple value is expected. This element adapts the - // original condition to the value context. - TTranslatedConditionValue(Expr expr) { - not ignoreExpr(expr) and - isNativeCondition(expr) and - not usedAsCondition(expr) - } or - // An expression used as an initializer. - TTranslatedInitialization(Expr expr) { - not ignoreExpr(expr) and - ( - // Because of their implementation in C#, - // we deal with all the types of initialization separately. - // First only simple local variable initialization (ie. `int x = 0`) - exists(LocalVariableDeclAndInitExpr lvInit | lvInit.getInitializer() = expr) - or - // Then treat more complex ones - expr instanceof ArrayInitializer - or - expr instanceof ObjectInitializer - or - expr = any(ThrowElement throwElement).getExpr() - or - expr = any(CollectionInitializer colInit).getAnElementInitializer() - or - expr = any(ReturnStmt returnStmt).getExpr() - or - expr = any(ArrayInitializer arrInit).getAnElement() - ) - } or - // The initialization of an array element via a member of an initializer list. - TTranslatedExplicitElementInitialization(ArrayInitializer initList, int elementIndex) { - not ignoreExpr(initList) and - exists(initList.getElement(elementIndex)) - } or - // The initialization of a base class from within a constructor. - TTranslatedConstructorInitializer(ConstructorInitializer init) { not ignoreExpr(init) } or - // A statement - TTranslatedStmt(Stmt stmt) { translateStmt(stmt) } or - // A function - TTranslatedFunction(Callable callable) { translateFunction(callable) } or - // A function parameter - TTranslatedParameter(Parameter param) { - exists(Callable func | - func = param.getCallable() and - translateFunction(func) - ) - } or - // A local declaration - TTranslatedDeclaration(LocalVariableDeclExpr entry) { - // foreach var decl and init is treated separately, - // because foreach needs desugaring - not ignoreExprAndDescendants(entry) - } or - // A compiler generated element, generated by `generatedBy` during the - // desugaring process - TTranslatedCompilerGeneratedElement(Element generatedBy, int index) { - canCreateCompilerGeneratedElement(generatedBy, index) - } - -/** - * Represents an AST node for which IR needs to be generated. - * - * In most cases, there is a single `TranslatedElement` for each AST node. - * However, when a single AST node performs two separable operations (e.g. - * a `VariableAccess` that is also a load), there may be multiple - * `TranslatedElement` nodes for a single AST node. - */ -abstract class TranslatedElement extends TTranslatedElement { - abstract string toString(); - - /** - * Gets the AST node being translated. - */ - abstract Language::AST getAst(); - - /** - * Get the first instruction to be executed in the evaluation of this element. - */ - abstract Instruction getFirstInstruction(); - - /** - * Get the immediate child elements of this element. - */ - final TranslatedElement getAChild() { result = this.getChild(_) } - - /** - * Gets the immediate child element of this element. The `id` is unique - * among all children of this element, but the values are not necessarily - * consecutive. - */ - abstract TranslatedElement getChild(int id); - - /** - * Gets the an identifier string for the element. This id is unique within - * the scope of the element's function. - */ - int getId() { result = this.getUniqueId() } - - private TranslatedElement getChildByRank(int rankIndex) { - result = - rank[rankIndex + 1](TranslatedElement child, int id | - child = this.getChild(id) - | - child order by id - ) - } - - language[monotonicAggregates] - private int getDescendantCount() { - result = - 1 + sum(TranslatedElement child | child = this.getChildByRank(_) | child.getDescendantCount()) - } - - private int getUniqueId() { - if not exists(this.getParent()) - then result = 0 - else - exists(TranslatedElement parent | - parent = this.getParent() and - if this = parent.getChildByRank(0) - then result = 1 + parent.getUniqueId() - else - exists(int childIndex, TranslatedElement previousChild | - this = parent.getChildByRank(childIndex) and - previousChild = parent.getChildByRank(childIndex - 1) and - result = previousChild.getUniqueId() + previousChild.getDescendantCount() - ) - ) - } - - /** - * Holds if this element generates an instruction with opcode `opcode` and - * result type `resultType`. `tag` must be unique for each instruction - * generated from the same AST node (not just from the same - * `TranslatedElement`). - * If the instruction does not return a result, `resultType` should be - * `VoidType`. - */ - abstract predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType); - - /** - * Gets the `Function` that contains this element. - */ - abstract Callable getFunction(); - - /** - * Gets the successor instruction of the instruction that was generated by - * this element for tag `tag`. The successor edge kind is specified by `kind`. - */ - abstract Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind); - - /** - * Gets the successor instruction to which control should flow after the - * child element specified by `child` has finished execution. - */ - abstract Instruction getChildSuccessor(TranslatedElement child); - - /** - * Gets the instruction to which control should flow if an exception is thrown - * within this element. This will generally return first `catch` block of the - * nearest enclosing `try`, or the `Unwind` instruction for the function if - * there is no enclosing `try`. - */ - Instruction getExceptionSuccessorInstruction() { - result = this.getParent().getExceptionSuccessorInstruction() - } - - /** - * Gets the primary instruction for the side effect instruction that was - * generated by this element for tag `tag`. - */ - Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { none() } - - /** - * Holds if this element generates a temporary variable with type `type`. - * `tag` must be unique for each variable generated from the same AST node - * (not just from the same `TranslatedElement`). - */ - predicate hasTempVariable(TempVariableTag tag, CSharpType type) { none() } - - /** - * If the instruction specified by `tag` is a `FunctionInstruction`, gets the - * `Function` for that instruction. - */ - Callable getInstructionFunction(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `VariableInstruction`, gets the - * `IRVariable` for that instruction. - */ - IRVariable getInstructionVariable(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `FieldInstruction`, gets the - * `Field` for that instruction. - */ - Field getInstructionField(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is an `IndexedElementInstruction`, - * gets the `ArrayAccess` of that instruction. - */ - ArrayAccess getInstructionArrayAccess(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `ConstantValueInstruction`, gets - * the constant value for that instruction. - */ - string getInstructionConstantValue(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `PointerArithmeticInstruction`, - * gets the size of the type pointed to by the pointer. - */ - int getInstructionElementSize(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` has a result of type `UnknownType`, - * gets the size of the result in bytes. If the result does not have a known - * constant size, this predicate does not hold. - */ - int getInstructionResultSize(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `StringConstantInstruction`, - * gets the `StringLiteral` for that instruction. - */ - StringLiteral getInstructionStringLiteral(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is a `CatchByTypeInstruction`, - * gets the type of the exception to be caught. - */ - CSharpType getInstructionExceptionType(InstructionTag tag) { none() } - - /** - * If the instruction specified by `tag` is an `InheritanceConversionInstruction`, - * gets the inheritance relationship for that instruction. - */ - predicate getInstructionInheritance(InstructionTag tag, Class baseClass, Class derivedClass) { - none() - } - - /** - * Gets the instruction whose result is consumed as an operand of the - * instruction specified by `tag`, with the operand specified by `operandTag`. - */ - Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } - - /** - * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. - */ - CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } - - /** - * Gets the instruction generated by this element with tag `tag`. - */ - final Instruction getInstruction(InstructionTag tag) { - getInstructionTranslatedElement(result) = this and - getInstructionTag(result) = tag - } - - /** - * Gets the temporary variable generated by this element with tag `tag`. - */ - final IRTempVariable getTempVariable(TempVariableTag tag) { - result.getAst() = this.getAst() and - result.getTag() = tag and - this.hasTempVariable(tag, _) - } - - /** - * Gets the parent element of this element. - */ - final TranslatedElement getParent() { result.getAChild() = this } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll deleted file mode 100644 index 68070261227..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll +++ /dev/null @@ -1,2095 +0,0 @@ -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRUtilities -private import InstructionTag -private import TranslatedCondition -private import TranslatedDeclaration -private import TranslatedElement -private import TranslatedFunction -private import TranslatedInitialization -private import common.TranslatedConditionBase -private import common.TranslatedCallBase -private import common.TranslatedExprBase -private import desugar.Delegate -private import desugar.internal.TranslatedCompilerGeneratedCall -import TranslatedCall -private import experimental.ir.internal.IRCSharpLanguage as Language - -/** - * Gets the TranslatedExpr for the specified expression. If `expr` is a load, - * the result is the TranslatedExpr for the load portion. - */ -TranslatedExpr getTranslatedExpr(Expr expr) { - result.getExpr() = expr and - result.producesExprResult() and - // When a constructor call is needed, we fetch it manually. - // This is because of how we translate object creations: the translated expression - // and the translated constructor call are attached to the same element. - (expr instanceof ObjectCreation implies not result instanceof TranslatedConstructorCall) -} - -/** - * The IR translation of some part of an expression. - * A single `Expr` may consist of multiple `TranslatedExpr` objects. Every - * `Expr` has a single `TranslatedCoreExpr`, which produces the result of the - * expression before any implicit lvalue-to-rvalue conversion. Any expression - * with an lvalue-to-rvalue conversion will also have a `TranslatedLoad` to - * perform that conversion on the original result. A few expressions have - * additional `TranslatedExpr` objects that compute intermediate values, such - * as the `TranslatedAllocatorCall` and `TranslatedAllocationSize` within the - * translation of a `NewExpr`. - */ -abstract class TranslatedExpr extends TranslatedExprBase { - Expr expr; - - /** - * Holds if this `TranslatedExpr` produces the final result of the original - * expression from the AST. - * - * For example, in `y = x;`, the TranslatedLoad for the VariableAccess `x` - * produces the result of that VariableAccess expression, but the - * TranslatedVariableAccess for `x` does not. The TranslatedVariableAccess - * for `y` does produce its result, however, because there is no load on `y`. - */ - abstract predicate producesExprResult(); - - /** - * Gets the type of the result produced by this expression. - */ - final Type getResultType() { result = expr.getType() } - - final override Language::AST getAst() { result = expr } - - final override Callable getFunction() { result = expr.getEnclosingCallable() } - - /** - * Gets the expression from which this `TranslatedExpr` is generated. - */ - final Expr getExpr() { result = expr } - - /** - * Gets the `TranslatedFunction` containing this expression. - */ - final TranslatedFunction getEnclosingFunction() { - result = getTranslatedFunction(expr.getEnclosingCallable()) - } -} - -/** - * The IR translation of the "core" part of an expression. This is the part of - * the expression that produces the result value of the expression, before any - * lvalue-to-rvalue conversion on the result. Every expression has a single - * `TranslatedCoreExpr`. - */ -abstract class TranslatedCoreExpr extends TranslatedExpr { - final override string toString() { result = expr.toString() } - - /** - * All exprs produce a final value, apart from reads. They first need an access, - * then a load. - */ - final override predicate producesExprResult() { - // If the expr needs a load, its translation does not produce the final value. - not needsLoad(expr) - } - - final CSharpType getResultCSharpType() { - if this.isResultLValue() = true - then result = getTypeForGLValue(expr.getType()) - else result = getTypeForPRValue(expr.getType()) - } - - /** - * Returns `true` if the result of this `TranslatedExpr` is a lvalue, or - * `false` if the result is a rvalue. - * - * This predicate returns a `boolean` value instead of just a being a plain - * predicate because all of the subclass predicates that call it require a - * `boolean` value. - */ - final boolean isResultLValue() { - if not this.producesExprResult() then result = true else result = false - } -} - -class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, - TTranslatedConditionValue -{ - TranslatedConditionValue() { this = TTranslatedConditionValue(expr) } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getCondition() } - - override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - ( - tag = ConditionValueTrueTempAddressTag() or - tag = ConditionValueFalseTempAddressTag() or - tag = ConditionValueResultTempAddressTag() - ) and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(expr.getType()) - or - ( - tag = ConditionValueTrueConstantTag() or - tag = ConditionValueFalseConstantTag() - ) and - opcode instanceof Opcode::Constant and - resultType = this.getResultCSharpType() - or - ( - tag = ConditionValueTrueStoreTag() or - tag = ConditionValueFalseStoreTag() - ) and - opcode instanceof Opcode::Store and - resultType = this.getResultCSharpType() - or - tag = ConditionValueResultLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getResultCSharpType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - tag = ConditionValueTrueTempAddressTag() and - result = this.getInstruction(ConditionValueTrueConstantTag()) - or - tag = ConditionValueTrueConstantTag() and - result = this.getInstruction(ConditionValueTrueStoreTag()) - or - tag = ConditionValueTrueStoreTag() and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - tag = ConditionValueFalseTempAddressTag() and - result = this.getInstruction(ConditionValueFalseConstantTag()) - or - tag = ConditionValueFalseConstantTag() and - result = this.getInstruction(ConditionValueFalseStoreTag()) - or - tag = ConditionValueFalseStoreTag() and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - tag = ConditionValueResultTempAddressTag() and - result = this.getInstruction(ConditionValueResultLoadTag()) - or - tag = ConditionValueResultLoadTag() and - result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = ConditionValueTrueStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueTrueTempAddressTag()) - or - operandTag instanceof StoreValueOperandTag and - result = this.getInstruction(ConditionValueTrueConstantTag()) - ) - or - tag = ConditionValueFalseStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueFalseTempAddressTag()) - or - operandTag instanceof StoreValueOperandTag and - result = this.getInstruction(ConditionValueFalseConstantTag()) - ) - or - tag = ConditionValueResultLoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ConditionValueTempVar() and - type = this.getResultCSharpType() - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - ( - tag = ConditionValueTrueTempAddressTag() or - tag = ConditionValueFalseTempAddressTag() or - tag = ConditionValueResultTempAddressTag() - ) and - result = this.getTempVariable(ConditionValueTempVar()) - } - - override string getInstructionConstantValue(InstructionTag tag) { - tag = ConditionValueTrueConstantTag() and result = "1" - or - tag = ConditionValueFalseConstantTag() and result = "0" - } - - override Instruction getResult() { result = this.getInstruction(ConditionValueResultLoadTag()) } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getInstruction(ConditionValueTrueTempAddressTag()) - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getInstruction(ConditionValueFalseTempAddressTag()) - } - - private TranslatedCondition getCondition() { result = getTranslatedCondition(expr) } -} - -/** - * IR translation of an implicit lvalue-to-rvalue conversion on the result of - * an expression. - */ -class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { - TranslatedLoad() { this = TTranslatedLoad(expr) } - - override string toString() { result = "Load of " + expr.toString() } - - override Instruction getFirstInstruction() { result = this.getOperand().getFirstInstruction() } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = LoadTag() and - opcode instanceof Opcode::Load and - if this.producesExprResult() - then resultType = getTypeForPRValue(expr.getType()) - else resultType = getTypeForGLValue(expr.getType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = LoadTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getOperand() and result = this.getInstruction(LoadTag()) - } - - override Instruction getResult() { result = this.getInstruction(LoadTag()) } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = LoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - } - - final override predicate producesExprResult() { - // A load always produces the result of the expression. - any() - } - - private TranslatedCoreExpr getOperand() { result.getExpr() = expr } -} - -abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { - override MutatorOperation expr; - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - final override string getInstructionConstantValue(InstructionTag tag) { - tag = CrementConstantTag() and - exists(Type resultType | - resultType = this.getResultType() and - ( - resultType instanceof IntegralType and result = "1" - or - resultType instanceof FloatingPointType and result = "1.0" - or - resultType instanceof PointerType and result = "1" - ) - ) - } - - private Type getConstantType() { - exists(Type resultType | - resultType = this.getResultType() and - ( - resultType instanceof IntegralType and result = this.getResultType() - or - resultType instanceof FloatingPointType and result = this.getResultType() - or - resultType instanceof PointerType and result = any(IntType t) - ) - ) - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = CrementLoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(expr.getType()) - or - tag = CrementConstantTag() and - opcode instanceof Opcode::Constant and - resultType = getTypeForPRValue(this.getConstantType()) - or - tag = CrementOpTag() and - opcode = this.getOpcode() and - resultType = getTypeForPRValue(expr.getType()) - or - tag = CrementStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(expr.getType()) - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = CrementLoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - tag = CrementOpTag() and - ( - operandTag instanceof LeftOperandTag and - result = this.getInstruction(CrementLoadTag()) - or - operandTag instanceof RightOperandTag and - result = this.getInstruction(CrementConstantTag()) - ) - or - tag = CrementStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - operandTag instanceof StoreValueOperandTag and - result = this.getInstruction(CrementOpTag()) - ) - } - - final override Instruction getFirstInstruction() { - result = this.getOperand().getFirstInstruction() - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - tag = CrementLoadTag() and - result = this.getInstruction(CrementConstantTag()) - or - tag = CrementConstantTag() and - result = this.getInstruction(CrementOpTag()) - or - tag = CrementOpTag() and - result = this.getInstruction(CrementStoreTag()) - or - tag = CrementStoreTag() and - result = this.getParent().getChildSuccessor(this) - ) - } - - final override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getOperand() and result = this.getInstruction(CrementLoadTag()) - } - - final override int getInstructionElementSize(InstructionTag tag) { - tag = CrementOpTag() and - ( - this.getOpcode() instanceof Opcode::PointerAdd or - this.getOpcode() instanceof Opcode::PointerSub - ) and - result = Language::getTypeSize(this.getResultType().(PointerType).getReferentType()) - } - - final TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getOperand()) } - - final Opcode getOpcode() { - exists(Type resultType | - resultType = this.getResultType() and - ( - ( - expr instanceof IncrementOperation and - if resultType instanceof PointerType - then result instanceof Opcode::PointerAdd - else result instanceof Opcode::Add - ) - or - ( - expr instanceof DecrementOperation and - if resultType instanceof PointerType - then result instanceof Opcode::PointerSub - else result instanceof Opcode::Sub - ) - ) - ) - } -} - -class TranslatedPrefixCrementOperation extends TranslatedCrementOperation { - TranslatedPrefixCrementOperation() { - expr instanceof PreIncrExpr or - expr instanceof PreDecrExpr - } - - override Instruction getResult() { result = this.getInstruction(CrementOpTag()) } -} - -class TranslatedPostfixCrementOperation extends TranslatedCrementOperation { - TranslatedPostfixCrementOperation() { - expr instanceof PostIncrExpr or - expr instanceof PostDecrExpr - } - - override Instruction getResult() { result = this.getInstruction(CrementLoadTag()) } -} - -class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, InitializationContext { - override ObjectInitializer expr; - - override Instruction getResult() { none() } - - override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override TranslatedElement getChild(int id) { - result = getTranslatedExpr(expr.getMemberInitializer(id)) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getChild(index) and - if exists(this.getChild(index + 1)) - then result = this.getChild(index + 1).getFirstInstruction() - else result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getTargetAddress() { - // The target address is the address of the newly allocated object, - // which can be retrieved from the parent `TranslatedObjectCreation`. - result = this.getParent().getInstruction(NewObjTag()) - } - - override Type getTargetType() { - result = this.getParent().getInstruction(NewObjTag()).getResultType() - } -} - -class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, InitializationContext { - override CollectionInitializer expr; - - override Instruction getResult() { none() } - - override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override TranslatedElement getChild(int id) { - result = getTranslatedExpr(expr.getElementInitializer(id)) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getChild(index) and - ( - result = this.getChild(index + 1).getFirstInstruction() - or - not exists(this.getChild(index + 1)) and - result = this.getParent().getChildSuccessor(this) - ) - ) - } - - override Instruction getTargetAddress() { - // The target address is the address of the newly allocated object, - // which can be retrieved from the parent `TranslatedObjectCreation`. - result = this.getParent().getInstruction(NewObjTag()) - } - - override Type getTargetType() { - result = this.getParent().getInstruction(NewObjTag()).getResultType() - } -} - -/** - * The translation of an array access expression. The `ElementsAddress` - * instruction, given the address of an array, return the address - * of the element at index 0 of that array. To correctly treat the - * multidimensional case, we generate the address incrementally. For example, - * the address of a[1][1] will produce the instructions: - * r0_1(Int32[,]) = VariableAddress[a] : - * r0_2(Int32[,]) = ElementsAddress : r0_1 - * r0_3(Int32) = Constant[1] : - * r0_4(Int32[,]) = PointerAdd[4] : r0_2, r0_3 - * r0_5(Int32[]) = ElementsAddress : r0_4 - * r0_6(Int32) = Constant[1] : - * r0_7(Int32[]) = PointerAdd[4] : r0_5, r0_6 - * - * To support this incremental address calculation, - * the `ElementsAddress` and `PointerAdd` instructions are indexed (so that - * we correctly find the successor of instructions). - */ -class TranslatedArrayAccess extends TranslatedNonConstantExpr { - override ArrayAccess expr; - - override Instruction getFirstInstruction() { - result = this.getBaseOperand().getFirstInstruction() - } - - final override TranslatedElement getChild(int id) { - id = -1 and result = this.getBaseOperand() - or - result = this.getOffsetOperand(id) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - exists(int index | - this.inBounds(index) and - kind instanceof GotoEdge and - ( - // The successor of a `PointerAdd` is an `ElementsAddress` if - // that `PointerAdd` is not the last `PointerAdd` instruction. - tag = PointerAddTag(index) and - result = this.getInstruction(ElementsAddressTag(index + 1)) - or - // The successor of the last `PointerAdd` instruction is - // the successor of the `TranslatedArrayAccess`. - tag = PointerAddTag(this.getRank() - 1) and - result = this.getParent().getChildSuccessor(this) - or - // The successor of an `ElementsAddress` instruction is - // an offset expression. - tag = ElementsAddressTag(index) and - result = this.getOffsetOperand(index).getFirstInstruction() - ) - ) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - // The base address of the array is followed by the first - // `ElementsAddress` instruction. - child = this.getBaseOperand() and - result = this.getInstruction(ElementsAddressTag(0)) - or - // The successor of an offset expression is a `PointerAdd` expression. - child = this.getOffsetOperand(child.getAst().getIndex()) and - child.getAst().getIndex() >= 0 and - result = this.getInstruction(PointerAddTag(child.getAst().getIndex())) - } - - override Instruction getResult() { - result = this.getInstruction(PointerAddTag(this.getRank() - 1)) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - exists(int index | - this.inBounds(index) and - tag = PointerAddTag(index) and - opcode instanceof Opcode::PointerAdd and - resultType = getTypeForPRValue(getArrayOfDim(this.getRank() - index, expr.getType())) - ) - or - exists(int index | - this.inBounds(index) and - tag = ElementsAddressTag(index) and - opcode instanceof Opcode::ElementsAddress and - resultType = getTypeForPRValue(getArrayOfDim(this.getRank() - index, expr.getType())) - ) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - exists(int index | - this.inBounds(index) and - tag = PointerAddTag(index) and - ( - operandTag instanceof LeftOperandTag and - result = this.getInstruction(ElementsAddressTag(index)) - or - operandTag instanceof RightOperandTag and - result = this.getOffsetOperand(index).getResult() - ) - ) - or - tag = ElementsAddressTag(0) and - ( - operandTag instanceof UnaryOperandTag and - result = this.getBaseOperand().getResult() - ) - or - exists(int index | - this.inBounds(index) and - index > 0 and - tag = ElementsAddressTag(index) and - ( - operandTag instanceof UnaryOperandTag and - result = this.getInstruction(PointerAddTag(index - 1)) - ) - ) - } - - override int getInstructionElementSize(InstructionTag tag) { - exists(int index | - this.inBounds(index) and - tag = PointerAddTag(index) and - result = Language::getTypeSize(expr.getQualifier().getType().(ArrayType).getElementType()) - ) - } - - private TranslatedExpr getBaseOperand() { result = getTranslatedExpr(expr.getQualifier()) } - - private TranslatedExpr getOffsetOperand(int index) { - this.inBounds(index) and - result = getTranslatedExpr(expr.getChild(index)) - } - - private predicate inBounds(int index) { index in [0 .. this.getRank() - 1] } - - private int getRank() { result = count(expr.getIndex(_)) } -} - -abstract class TranslatedPointerOps extends TranslatedNonConstantExpr { - override UnaryOperation expr; - - final override Instruction getFirstInstruction() { - result = this.getOperand().getFirstInstruction() - } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - final override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getOperand() and result = this.getParent().getChildSuccessor(this) - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getResult() { result = this.getOperand().getResult() } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - none() - } - - abstract TranslatedExpr getOperand(); -} - -class TranslatedPointerIndirectionExpr extends TranslatedPointerOps { - override PointerIndirectionExpr expr; - - override TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getOperand()) } -} - -class TranslatedAddressExpr extends TranslatedPointerOps { - override AddressOfExpr expr; - - override TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getOperand()) } -} - -class TranslatedThisExpr extends TranslatedNonConstantExpr { - override ThisAccess expr; - - final override TranslatedElement getChild(int id) { none() } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::CopyValue and - resultType = getTypeForPRValue(expr.getType()) - } - - final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } - - final override Instruction getFirstInstruction() { - result = this.getInstruction(OnlyInstructionTag()) - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) - } - - final override Instruction getChildSuccessor(TranslatedElement child) { none() } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag instanceof UnaryOperandTag and - result = this.getInitializeThisInstruction() - } - - private Instruction getInitializeThisInstruction() { - result = getTranslatedFunction(expr.getEnclosingCallable()).getInitializeThisInstruction() - } -} - -abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { - override VariableAccess expr; - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getQualifier() // Might not exist - } - - final TranslatedExpr getQualifier() { - expr instanceof QualifiableExpr and - result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier()) - } - - override Instruction getResult() { - if this.needsExtraLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getInstruction(AddressTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - this.needsExtraLoad() and - tag = LoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(expr.getType()) - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = AddressTag() and - ( - if this.needsExtraLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getParent().getChildSuccessor(this) - ) and - kind instanceof GotoEdge - or - this.needsExtraLoad() and - tag = LoadTag() and - kind instanceof GotoEdge and - result = this.getParent().getChildSuccessor(this) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - this.needsExtraLoad() and - tag = LoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(AddressTag()) - } - - final override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getQualifier() and result = this.getInstruction(AddressTag()) - } - - /** - * Some variable accesses need an extra load, eg. ref parameters, - * out parameters - */ - final private predicate needsExtraLoad() { - ( - expr.getTarget().(Parameter).isOutOrRef() or - expr.getTarget().(Parameter).isIn() - ) and - (expr.getParent() instanceof FieldAccess implies expr.getType().isRefType()) - } -} - -class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { - TranslatedNonFieldVariableAccess() { - not expr instanceof FieldAccess and - // If the parent expression is a `LocalVariableDeclAndInitExpr`, - // then translate only the variables that are initializers (on the RHS) - // and not the LHS (the address of the LHS is generated during - // the translation of the initialization). - ( - expr.getParent() instanceof LocalVariableDeclAndInitExpr - implies - expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer() - ) - or - // Static field accesses should be modeled as `TranslatedNonFieldAccess` - expr.(FieldAccess).getTarget().isStatic() - } - - override Instruction getFirstInstruction() { - if exists(this.getQualifier()) - then result = this.getQualifier().getFirstInstruction() - else result = this.getInstruction(AddressTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType) - or - tag = AddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getResultType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = getIRUserVariable(expr.getEnclosingCallable(), expr.getTarget()) - } -} - -class TranslatedFieldAccess extends TranslatedVariableAccess { - override FieldAccess expr; - - TranslatedFieldAccess() { - // Static field accesses should be modeled as `TranslatedNonFieldAccess` - not expr.getTarget().isStatic() - } - - override Instruction getFirstInstruction() { - // If there is a qualifier - if exists(this.getQualifier()) - then result = this.getQualifier().getFirstInstruction() - else - // it means that the access is part of an `ObjectInitializer` expression - // so the instructions for the qualifier have been generated previously. - result = this.getInstruction(AddressTag()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedVariableAccess.super.getInstructionOperand(tag, operandTag) - or - tag = AddressTag() and - operandTag instanceof UnaryOperandTag and - // A normal field access always has a qualifier - if exists(this.getQualifier()) - then result = this.getQualifier().getResult() - else - // This field access is part of an `ObjectInitializer` - // so the translated element of the initializer - // (which is the parent of the parent of the translated field access), - // being an `InitializationContext`, knows the target address of this field access. - result = this.getParent().getParent().(InitializationContext).getTargetAddress() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = AddressTag() and - opcode instanceof Opcode::FieldAddress and - resultType = getTypeForGLValue(expr.getType()) - } - - override Field getInstructionField(InstructionTag tag) { - tag = AddressTag() and - result = expr.getTarget() - } -} - -class TranslatedFunctionAccess extends TranslatedNonConstantExpr { - override CallableAccess expr; - - override TranslatedElement getChild(int id) { none() } - - override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - - override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::FunctionAddress and - resultType = getTypeForGLValue(expr.getType()) - } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = OnlyInstructionTag() and - result = expr.getTarget() - } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -/** - * IR translation of an expression whose value is not known at compile time. - */ -abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr { - TranslatedNonConstantExpr() { - this = TTranslatedValueExpr(expr) and - not isIRConstant(expr) - } -} - -/** - * IR translation of an expression with a compile-time constant value. This - * includes not only literals, but also "integral constant expressions" (e.g. - * `1 + 2`). - */ -abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr { - TranslatedConstantExpr() { - this = TTranslatedValueExpr(expr) and - isIRConstant(expr) - } - - final override Instruction getFirstInstruction() { - result = this.getInstruction(OnlyInstructionTag()) - } - - final override TranslatedElement getChild(int id) { none() } - - final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - none() - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode = this.getOpcode() and - resultType = getTypeForPRValue(expr.getType()) - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - final override Instruction getChildSuccessor(TranslatedElement child) { none() } - - abstract Opcode getOpcode(); -} - -class TranslatedArithmeticLiteral extends TranslatedConstantExpr { - TranslatedArithmeticLiteral() { not expr instanceof StringLiteral } - - override string getInstructionConstantValue(InstructionTag tag) { - tag = OnlyInstructionTag() and - result = expr.getValue() - } - - override Opcode getOpcode() { result instanceof Opcode::Constant } -} - -class TranslatedStringLiteral extends TranslatedConstantExpr { - override StringLiteral expr; - - override StringLiteral getInstructionStringLiteral(InstructionTag tag) { - tag = OnlyInstructionTag() and - result = expr - } - - override Opcode getOpcode() { result instanceof Opcode::StringConstant } -} - -/** - * IR translation of an expression that performs a single operation on its - * operands and returns the result. - */ -abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr { - /** - * Gets the `Opcode` of the operation to be performed. - */ - abstract Opcode getOpcode(); - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - opcode = this.getOpcode() and - tag = OnlyInstructionTag() and - resultType = this.getResultCSharpType() - } - - final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } -} - -class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { - TranslatedUnaryExpr() { - expr instanceof LogicalNotExpr or - expr instanceof ComplementExpr or - expr instanceof UnaryPlusExpr or - expr instanceof UnaryMinusExpr - } - - final override Instruction getFirstInstruction() { - result = this.getOperand().getFirstInstruction() - } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - final override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag()) - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - result = this.getOperand().getResult() and - operandTag instanceof UnaryOperandTag - } - - final override Opcode getOpcode() { - expr instanceof LogicalNotExpr and result instanceof Opcode::LogicalNot - or - expr instanceof ComplementExpr and result instanceof Opcode::BitComplement - or - expr instanceof UnaryPlusExpr and result instanceof Opcode::CopyValue - or - expr instanceof UnaryMinusExpr and result instanceof Opcode::Negate - } - - private TranslatedExpr getOperand() { - result = getTranslatedExpr(expr.(UnaryOperation).getOperand()) - } -} - -/** - * Represents the translation of a cast expression that generates a - * single `Convert` instruction. - */ -class TranslatedCast extends TranslatedNonConstantExpr { - override Cast expr; - - override Instruction getFirstInstruction() { result = this.getOperand().getFirstInstruction() } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = ConvertTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getOperand() and result = this.getInstruction(ConvertTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - ( - tag = ConvertTag() and - opcode = this.getOpcode() and - resultType = getTypeForPRValue(expr.getType()) - ) - } - - override Instruction getResult() { result = this.getInstruction(ConvertTag()) } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - ( - tag = ConvertTag() and - operandTag instanceof UnaryOperandTag and - result = this.getOperand().getResult() - ) - } - - private TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getExpr()) } - - private Opcode getOpcode() { - expr instanceof CastExpr and result instanceof Opcode::CheckedConvertOrThrow - or - expr instanceof AsExpr and result instanceof Opcode::CheckedConvertOrNull - } -} - -private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) { - expr instanceof LeftShiftExpr and result instanceof Opcode::ShiftLeft - or - expr instanceof RightShiftExpr and result instanceof Opcode::ShiftRight - or - expr instanceof UnsignedRightShiftExpr and result instanceof Opcode::UnsignedShiftRight - or - expr instanceof BitwiseAndExpr and result instanceof Opcode::BitAnd - or - expr instanceof BitwiseOrExpr and result instanceof Opcode::BitOr - or - expr instanceof BitwiseXorExpr and result instanceof Opcode::BitXor -} - -private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) { - expr instanceof AddExpr and result instanceof Opcode::Add - or - expr instanceof SubExpr and result instanceof Opcode::Sub - or - expr instanceof MulExpr and result instanceof Opcode::Mul - or - expr instanceof DivExpr and result instanceof Opcode::Div - or - expr instanceof RemExpr and result instanceof Opcode::Rem -} - -private Opcode comparisonOpcode(ComparisonOperation expr) { - expr instanceof EQExpr and result instanceof Opcode::CompareEQ - or - expr instanceof NEExpr and result instanceof Opcode::CompareNE - or - expr instanceof LTExpr and result instanceof Opcode::CompareLT - or - expr instanceof GTExpr and result instanceof Opcode::CompareGT - or - expr instanceof LEExpr and result instanceof Opcode::CompareLE - or - expr instanceof GEExpr and result instanceof Opcode::CompareGE -} - -/** - * IR translation of a simple binary operation. - */ -class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { - TranslatedBinaryOperation() { - expr instanceof BinaryArithmeticOperation or - expr instanceof BinaryBitwiseOperation or - expr instanceof ComparisonOperation - } - - override Instruction getFirstInstruction() { - result = this.getLeftOperand().getFirstInstruction() - } - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getLeftOperand() - or - id = 1 and result = this.getRightOperand() - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - if this.swapOperandsOnOp() - then ( - operandTag instanceof RightOperandTag and - result = this.getLeftOperand().getResult() - or - operandTag instanceof LeftOperandTag and - result = this.getRightOperand().getResult() - ) else ( - operandTag instanceof LeftOperandTag and - result = this.getLeftOperand().getResult() - or - operandTag instanceof RightOperandTag and - result = this.getRightOperand().getResult() - ) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getLeftOperand() and - result = this.getRightOperand().getFirstInstruction() - or - child = this.getRightOperand() and - result = this.getInstruction(OnlyInstructionTag()) - } - - override Opcode getOpcode() { - result = binaryArithmeticOpcode(expr) or - result = binaryBitwiseOpcode(expr) or - result = comparisonOpcode(expr) - } - - override int getInstructionElementSize(InstructionTag tag) { - tag = OnlyInstructionTag() and - exists(Opcode opcode | - opcode = this.getOpcode() and - ( - opcode instanceof Opcode::PointerAdd or - opcode instanceof Opcode::PointerSub or - opcode instanceof Opcode::PointerDiff - ) and - result = Language::getTypeSize(this.getPointerOperand().getResultType()) - ) - } - - private TranslatedExpr getPointerOperand() { - if this.swapOperandsOnOp() - then result = this.getRightOperand() - else result = this.getLeftOperand() - } - - private predicate swapOperandsOnOp() { - // Swap the operands on a pointer add 'i + p', so that the pointer operand - // always comes first. Note that we still evaluate the operands - // left-to-right. - exists(AddExpr ptrAdd, Type rightType | - ptrAdd = expr and - rightType = ptrAdd.getRightOperand().getType() and - rightType instanceof PointerType - ) - } - - private TranslatedExpr getLeftOperand() { - result = getTranslatedExpr(expr.(BinaryOperation).getLeftOperand()) - } - - private TranslatedExpr getRightOperand() { - result = getTranslatedExpr(expr.(BinaryOperation).getRightOperand()) - } -} - -abstract class TranslatedAssignment extends TranslatedNonConstantExpr { - override Assignment expr; - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getLeftOperand() - or - id = 1 and result = this.getRightOperand() - } - - final override Instruction getFirstInstruction() { - // Evaluation is right-to-left - result = this.getRightOperand().getFirstInstruction() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - ( - this.needsConversion() and - tag = AssignmentConvertRightTag() and - // For now only use `Opcode::Convert` to - // crudely represent conversions. Could - // be useful to represent the whole chain of conversions - opcode instanceof Opcode::Convert and - resultType = getTypeForPRValue(expr.getLValue().getType()) - ) - } - - final override Instruction getResult() { result = this.getStoredValue() } - - abstract Instruction getStoredValue(); - - final TranslatedExpr getLeftOperand() { result = getTranslatedExpr(expr.getLValue()) } - - final TranslatedExpr getRightOperand() { result = getTranslatedExpr(expr.getRValue()) } - - final predicate needsConversion() { expr.getLValue().getType() != expr.getRValue().getType() } -} - -class TranslatedAssignExpr extends TranslatedAssignment { - TranslatedAssignExpr() { - expr instanceof AssignExpr and - // if the lvalue is an accessor call, ignore assignment - // since the assignment expr is desugared into a function call - not expr.getLValue() instanceof AccessorCall - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = AssignmentStoreTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - or - this.needsConversion() and - tag = AssignmentConvertRightTag() and - result = this.getLeftOperand().getFirstInstruction() and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - // Operands are evaluated right-to-left. - ( - child = this.getRightOperand() and - if this.needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getLeftOperand().getFirstInstruction() - ) - or - child = this.getLeftOperand() and - result = this.getInstruction(AssignmentStoreTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - TranslatedAssignment.super.hasInstruction(opcode, tag, resultType) - or - tag = AssignmentStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(expr.getType()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = AssignmentStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getLeftOperand().getResult() - or - ( - operandTag instanceof StoreValueOperandTag and - if this.needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getRightOperand().getResult() - ) - ) - or - tag = AssignmentConvertRightTag() and - operandTag instanceof UnaryOperandTag and - result = this.getRightOperand().getResult() - } - - override Instruction getStoredValue() { result = this.getRightOperand().getResult() } -} - -class TranslatedAssignOperation extends TranslatedAssignment { - override AssignOperation expr; - - TranslatedAssignOperation() { - // Assignments to events is handled differently - not expr.getLValue() instanceof EventAccess - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - ( - tag = AssignOperationLoadTag() and - if this.leftOperandNeedsConversion() - then result = this.getInstruction(AssignOperationConvertLeftTag()) - else result = this.getInstruction(AssignOperationOpTag()) - ) - or - tag = AssignOperationConvertLeftTag() and - result = this.getInstruction(AssignOperationOpTag()) - or - ( - tag = AssignOperationOpTag() and - if this.leftOperandNeedsConversion() - then result = this.getInstruction(AssignOperationConvertResultTag()) - else result = this.getInstruction(AssignmentStoreTag()) - ) - or - tag = AssignOperationConvertResultTag() and - result = this.getInstruction(AssignmentStoreTag()) - or - tag = AssignmentStoreTag() and - result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - // Operands are evaluated right-to-left. - child = this.getRightOperand() and - result = this.getLeftOperand().getFirstInstruction() - or - child = this.getLeftOperand() and - result = this.getInstruction(AssignOperationLoadTag()) - } - - override Instruction getStoredValue() { - if this.leftOperandNeedsConversion() - then result = this.getInstruction(AssignOperationConvertResultTag()) - else result = this.getInstruction(AssignOperationOpTag()) - } - - private Type getConvertedLeftOperandType() { - if - expr instanceof AssignLeftShiftExpr or - expr instanceof AssignRightShiftExpr or - expr instanceof AssignUnsighedRightShiftExpr - then result = this.getLeftOperand().getResultType() - else - // The right operand has already been converted to the type of the op. - result = this.getRightOperand().getResultType() - } - - private predicate leftOperandNeedsConversion() { - this.getConvertedLeftOperandType() != this.getLeftOperand().getResultType() - } - - private Opcode getOpcode() { - expr instanceof AssignAddExpr and - ( - if expr.getRValue().getType() instanceof PointerType - then result instanceof Opcode::PointerAdd - else result instanceof Opcode::Add - ) - or - expr instanceof AssignSubExpr and - ( - if expr.getRValue().getType() instanceof PointerType - then result instanceof Opcode::PointerSub - else result instanceof Opcode::Sub - ) - or - expr instanceof AssignMulExpr and result instanceof Opcode::Mul - or - expr instanceof AssignDivExpr and result instanceof Opcode::Div - or - expr instanceof AssignRemExpr and result instanceof Opcode::Rem - or - expr instanceof AssignAndExpr and result instanceof Opcode::BitAnd - or - expr instanceof AssignOrExpr and result instanceof Opcode::BitOr - or - expr instanceof AssignXorExpr and result instanceof Opcode::BitXor - or - expr instanceof AssignLeftShiftExpr and result instanceof Opcode::ShiftLeft - or - expr instanceof AssignRightShiftExpr and result instanceof Opcode::ShiftRight - or - expr instanceof AssignUnsighedRightShiftExpr and result instanceof Opcode::UnsignedShiftRight - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = AssignOperationLoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) - or - tag = AssignOperationOpTag() and - opcode = this.getOpcode() and - resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) - or - tag = AssignmentStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(expr.getType()) - or - this.leftOperandNeedsConversion() and - opcode instanceof Opcode::Convert and - ( - tag = AssignOperationConvertLeftTag() and - resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) - or - tag = AssignOperationConvertResultTag() and - resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) - ) - } - - override int getInstructionElementSize(InstructionTag tag) { - tag = AssignOperationOpTag() and - exists(Opcode opcode | - opcode = this.getOpcode() and - ( - opcode instanceof Opcode::PointerAdd or - opcode instanceof Opcode::PointerSub - ) - ) and - result = Language::getTypeSize(this.getResultType().(PointerType).getReferentType()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = AssignOperationLoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getLeftOperand().getResult() - or - this.leftOperandNeedsConversion() and - tag = AssignOperationConvertLeftTag() and - operandTag instanceof UnaryOperandTag and - result = this.getInstruction(AssignOperationLoadTag()) - or - tag = AssignOperationOpTag() and - ( - ( - operandTag instanceof LeftOperandTag and - if this.leftOperandNeedsConversion() - then result = this.getInstruction(AssignOperationConvertLeftTag()) - else result = this.getInstruction(AssignOperationLoadTag()) - ) - or - operandTag instanceof RightOperandTag and - result = this.getRightOperand().getResult() - ) - or - this.leftOperandNeedsConversion() and - tag = AssignOperationConvertResultTag() and - operandTag instanceof UnaryOperandTag and - result = this.getInstruction(AssignOperationOpTag()) - or - tag = AssignmentStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getLeftOperand().getResult() - or - operandTag instanceof StoreValueOperandTag and - result = this.getStoredValue() - ) - } -} - -/** - * Abstract class implemented by any `TranslatedElement` that has a child - * expression that is a call to a constructor, in order to - * provide a pointer to the object being constructed. - */ -abstract class ConstructorCallContext extends TranslatedElement { - /** - * Gets the instruction whose result value is the address of the object to be - * constructed. - */ - abstract Instruction getReceiver(); -} - -class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionContext { - override ConditionalExpr expr; - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getCondition() - or - id = 1 and result = this.getThen() - or - id = 2 and result = this.getElse() - } - - override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - not this.resultIsVoid() and - ( - ( - not this.thenIsVoid() and tag = ConditionValueTrueTempAddressTag() - or - not this.elseIsVoid() and tag = ConditionValueFalseTempAddressTag() - or - tag = ConditionValueResultTempAddressTag() - ) and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getResultType()) - or - ( - not this.thenIsVoid() and tag = ConditionValueTrueStoreTag() - or - not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() - ) and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(this.getResultType()) - or - tag = ConditionValueResultLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getResultCSharpType() - ) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - not this.resultIsVoid() and - kind instanceof GotoEdge and - ( - not this.thenIsVoid() and - ( - tag = ConditionValueTrueTempAddressTag() and - result = this.getInstruction(ConditionValueTrueStoreTag()) - or - tag = ConditionValueTrueStoreTag() and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - ) - or - not this.elseIsVoid() and - ( - tag = ConditionValueFalseTempAddressTag() and - result = this.getInstruction(ConditionValueFalseStoreTag()) - or - tag = ConditionValueFalseStoreTag() and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - ) - or - tag = ConditionValueResultTempAddressTag() and - result = this.getInstruction(ConditionValueResultLoadTag()) - or - tag = ConditionValueResultLoadTag() and - result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - not this.resultIsVoid() and - ( - not this.thenIsVoid() and - tag = ConditionValueTrueStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueTrueTempAddressTag()) - or - operandTag instanceof StoreValueOperandTag and - result = this.getThen().getResult() - ) - or - not this.elseIsVoid() and - tag = ConditionValueFalseStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueFalseTempAddressTag()) - or - operandTag instanceof StoreValueOperandTag and - result = this.getElse().getResult() - ) - or - tag = ConditionValueResultLoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - ) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - not this.resultIsVoid() and - tag = ConditionValueTempVar() and - type = getTypeForPRValue(this.getResultType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - not this.resultIsVoid() and - ( - tag = ConditionValueTrueTempAddressTag() or - tag = ConditionValueFalseTempAddressTag() or - tag = ConditionValueResultTempAddressTag() - ) and - result = this.getTempVariable(ConditionValueTempVar()) - } - - override Instruction getResult() { - not this.resultIsVoid() and - result = this.getInstruction(ConditionValueResultLoadTag()) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - ( - child = this.getThen() and - if this.thenIsVoid() - then result = this.getParent().getChildSuccessor(this) - else result = this.getInstruction(ConditionValueTrueTempAddressTag()) - ) - or - ( - child = this.getElse() and - if this.elseIsVoid() - then result = this.getParent().getChildSuccessor(this) - else result = this.getInstruction(ConditionValueFalseTempAddressTag()) - ) - } - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getThen().getFirstInstruction() - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getElse().getFirstInstruction() - } - - private TranslatedCondition getCondition() { - result = getTranslatedCondition(expr.getCondition()) - } - - private TranslatedExpr getThen() { result = getTranslatedExpr(expr.getThen()) } - - private TranslatedExpr getElse() { result = getTranslatedExpr(expr.getElse()) } - - private predicate thenIsVoid() { - this.getThen().getResultType() instanceof VoidType - or - // A `ThrowExpr.getType()` incorrectly returns the type of exception being - // thrown, rather than `void`. Handle that case here. - expr.getThen() instanceof ThrowExpr - } - - private predicate elseIsVoid() { - this.getElse().getResultType() instanceof VoidType - or - // A `ThrowExpr.getType()` incorrectly returns the type of exception being - // thrown, rather than `void`. Handle that case here. - expr.getElse() instanceof ThrowExpr - } - - private predicate resultIsVoid() { this.getResultType() instanceof VoidType } -} - -/** - * The IR translation of an `IsExpr`. - */ -// TODO: Once `TranslatedInitialization.qll` is refactored, -// get rid of the initialization here. -// TODO: Refactor the generated instructions since it's pretty cluttered. -class TranslatedIsExpr extends TranslatedNonConstantExpr { - override IsExpr expr; - - override Instruction getFirstInstruction() { result = this.getIsExpr().getFirstInstruction() } - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getIsExpr() - or - id = 1 and result = this.getPatternVarDecl() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = ConvertTag() and - kind instanceof GotoEdge and - result = this.getInstruction(GeneratedConstantTag()) - or - this.hasVar() and - tag = InitializerStoreTag() and - kind instanceof GotoEdge and - result = this.getParent().getChildSuccessor(this) - or - ( - tag = GeneratedNeqTag() and - kind instanceof GotoEdge and - if this.hasVar() - then result = this.getInstruction(GeneratedBranchTag()) - else result = this.getParent().getChildSuccessor(this) - ) - or - // If a var is declared, we only do the initialization - // if the `IsExpr` is evaluated to `true`. - this.hasVar() and - tag = GeneratedBranchTag() and - ( - kind instanceof TrueEdge and - result = this.getInstruction(InitializerStoreTag()) - or - kind instanceof FalseEdge and - result = this.getParent().getChildSuccessor(this) - ) - or - tag = GeneratedConstantTag() and - kind instanceof GotoEdge and - if this.hasVar() - then result = this.getPatternVarDecl().getFirstInstruction() - else result = this.getInstruction(GeneratedNeqTag()) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getIsExpr() and - result = this.getInstruction(ConvertTag()) - or - this.hasVar() and - child = this.getPatternVarDecl() and - result = this.getInstruction(GeneratedNeqTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - this.hasVar() and - tag = InitializerStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(expr.getPattern().getType()) - or - tag = ConvertTag() and - opcode instanceof Opcode::CheckedConvertOrNull and - resultType = getTypeForPRValue(expr.getPattern().getType()) - or - tag = GeneratedNeqTag() and - opcode instanceof Opcode::CompareNE and - resultType = getTypeForPRValue(expr.getType()) - or - tag = GeneratedConstantTag() and - opcode instanceof Opcode::Constant and - resultType = getTypeForPRValue(expr.getPattern().getType()) - or - this.hasVar() and - tag = GeneratedBranchTag() and - opcode instanceof Opcode::ConditionalBranch and - resultType = getVoidType() - } - - override string getInstructionConstantValue(InstructionTag tag) { - tag = GeneratedConstantTag() and - // Review: "0" or "null"? - result = "0" - } - - override Instruction getResult() { result = this.getInstruction(GeneratedNeqTag()) } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = ConvertTag() and - operandTag instanceof UnaryOperandTag and - result = this.getIsExpr().getResult() - or - this.hasVar() and - tag = InitializerStoreTag() and - ( - operandTag instanceof StoreValueOperandTag and - result = this.getInstruction(ConvertTag()) - or - operandTag instanceof AddressOperandTag and - result = this.getPatternVarDecl().getTargetAddress() - ) - or - tag = GeneratedNeqTag() and - ( - operandTag instanceof LeftOperandTag and - result = this.getInstruction(ConvertTag()) - or - operandTag instanceof RightOperandTag and - result = this.getInstruction(GeneratedConstantTag()) - ) - or - this.hasVar() and - tag = GeneratedBranchTag() and - operandTag instanceof ConditionOperandTag and - result = this.getInstruction(GeneratedNeqTag()) - } - - private TranslatedExpr getIsExpr() { result = getTranslatedExpr(expr.getExpr()) } - - private predicate hasVar() { exists(this.getPatternVarDecl()) } - - private TranslatedLocalVariableDeclaration getPatternVarDecl() { - result = getTranslatedLocalDeclaration(expr.getPattern()) - } -} - -/** - * The IR translation of a lambda expression. This initializes a temporary variable whose type is that of the lambda, - * using the initializer list that represents the captures of the lambda. - */ -class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationContext { - override LambdaExpr expr; - - final override Instruction getFirstInstruction() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override Instruction getResult() { result = this.getInstruction(LoadTag()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = InitializerVariableAddressTag() and - kind instanceof GotoEdge and - result = this.getInstruction(InitializerStoreTag()) - or - tag = InitializerStoreTag() and - kind instanceof GotoEdge and - ( - result = this.getInitialization().getFirstInstruction() - or - not this.hasInitializer() and result = this.getInstruction(LoadTag()) - ) - or - tag = LoadTag() and - kind instanceof GotoEdge and - result = this.getParent().getChildSuccessor(this) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and - result = this.getInstruction(LoadTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(expr.getType()) - or - tag = InitializerStoreTag() and - opcode instanceof Opcode::Uninitialized and - resultType = getTypeForPRValue(expr.getType()) - or - tag = LoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(expr.getType()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - tag = LoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - ( - tag = InitializerVariableAddressTag() or - tag = InitializerStoreTag() - ) and - result = this.getTempVariable(LambdaTempVar()) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LambdaTempVar() and - type = getTypeForPRValue(this.getResultType()) - } - - final override Instruction getTargetAddress() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override Type getTargetType() { result = this.getResultType() } - - private predicate hasInitializer() { exists(this.getInitialization()) } - - private TranslatedInitialization getInitialization() { - result = getTranslatedInitialization(expr.getChild(0)) - } -} - -/** - * The translation of a `DelegateCall`. Since this type of call needs - * desugaring, we treat it as a special case. The AST node of the - * call expression will be the parent to a compiler generated call. - */ -class TranslatedDelegateCall extends TranslatedNonConstantExpr { - override DelegateCall expr; - - final override Instruction getFirstInstruction() { - result = this.getInvokeCall().getFirstInstruction() - } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getInvokeCall() } - - override Instruction getResult() { result = this.getInvokeCall().getResult() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInvokeCall() and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } - - private TranslatedCompilerGeneratedCall getInvokeCall() { - result = DelegateElements::getInvoke(expr) - } -} - -/** - * Represents the IR translation of creation expression. Can be the translation of an - * `ObjectCreation` or a `DelegateCreation`. - * The `NewObj` instruction denotes the fact that during initialization a new - * object is allocated, which is then initialized by the constructor. - */ -abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreationExpr, - ConstructorCallContext -{ - TranslatedCreation() { this = TTranslatedCreationExpr(expr) } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getConstructorCall() - or - id = 1 and result = this.getInitializerExpr() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - // Instruction that allocated space for a new object, - // and returns its address - tag = NewObjTag() and - opcode instanceof Opcode::NewObj and - resultType = getTypeForPRValue(expr.getType()) - or - this.needsLoad() and - tag = LoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(expr.getType()) - } - - final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) } - - override Instruction getResult() { - if this.needsLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getInstruction(NewObjTag()) - } - - override Instruction getReceiver() { result = this.getInstruction(NewObjTag()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - tag = NewObjTag() and - result = this.getConstructorCall().getFirstInstruction() - or - this.needsLoad() and - kind instanceof GotoEdge and - tag = LoadTag() and - result = this.getParent().getChildSuccessor(this) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - this.needsLoad() and - tag = LoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(NewObjTag()) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - ( - child = this.getConstructorCall() and - if exists(this.getInitializerExpr()) - then result = this.getInitializerExpr().getFirstInstruction() - else result = this.getLoadOrChildSuccessor() - ) - or - child = this.getInitializerExpr() and - result = this.getLoadOrChildSuccessor() - } - - private Instruction getLoadOrChildSuccessor() { - if this.needsLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getParent().getChildSuccessor(this) - } - - abstract TranslatedElement getConstructorCall(); - - abstract TranslatedExpr getInitializerExpr(); - - /** - * If the newly allocated object is a value type, then we need - * to load the newly allocated object before storing it in the variable, - * since `NewObj` returns an address. - */ - abstract predicate needsLoad(); -} - -/** - * Represents the IR translation of an `ObjectCreation`. - */ -class TranslatedObjectCreation extends TranslatedCreation { - override ObjectCreation expr; - - override TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) } - - override TranslatedConstructorCall getConstructorCall() { - // Since calls are also expressions, we can't - // use the predicate getTranslatedExpr (since that would - // also return `this`). - result.getAst() = this.getAst() - } - - override predicate needsLoad() { expr.getObjectType().isValueType() } -} - -/** - * Represents the IR translation of a `DelegateCreation`. - */ -class TranslatedDelegateCreation extends TranslatedCreation { - override DelegateCreation expr; - - override TranslatedExpr getInitializerExpr() { none() } - - override TranslatedElement getConstructorCall() { - result = DelegateElements::getConstructor(expr) - } - - override predicate needsLoad() { none() } -} - -/** - * Represents the IR translation of an assign operation where the lhs is an event access. - */ -class TranslatedEventAccess extends TranslatedNonConstantExpr { - override AssignOperation expr; - - TranslatedEventAccess() { expr.getLValue() instanceof EventAccess } - - // We only translate the lhs, since the rhs is translated as part of the - // accessor call. - override TranslatedElement getChild(int id) { id = 0 and result = this.getLValue() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getFirstInstruction() { - result = this.getLValue().getFirstInstruction() - } - - override Instruction getResult() { none() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getLValue() and - result = this.getParent().getChildSuccessor(this) - } - - private TranslatedExpr getLValue() { result = getTranslatedExpr(expr.getLValue()) } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll deleted file mode 100644 index f0970984d46..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll +++ /dev/null @@ -1,333 +0,0 @@ -import csharp -import experimental.ir.implementation.raw.IR -private import experimental.ir.implementation.Opcode -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRUtilities -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.TempVariableTag -private import InstructionTag -private import TranslatedElement -private import TranslatedExpr -private import TranslatedInitialization -private import TranslatedStmt -private import experimental.ir.internal.IRCSharpLanguage as Language - -/** - * Gets the `TranslatedFunction` that represents function `callable`. - */ -TranslatedFunction getTranslatedFunction(Callable callable) { result.getAst() = callable } - -/** - * Represents the IR translation of a function. This is the root element for - * all other elements associated with this function. - */ -class TranslatedFunction extends TranslatedElement, TTranslatedFunction { - Callable callable; - - TranslatedFunction() { this = TTranslatedFunction(callable) } - - final override string toString() { result = callable.toString() } - - final override Language::AST getAst() { result = callable } - - /** - * Gets the function being translated. - */ - final override Callable getFunction() { result = callable } - - final override TranslatedElement getChild(int id) { - id = -2 and result = this.getConstructorInitializer() - or - id = -1 and result = this.getBody() - or - result = this.getParameter(id) - } - - final private TranslatedConstructorInitializer getConstructorInitializer() { - exists(ConstructorInitializer ci | - ci = callable.getAChild() and - result = getTranslatedConstructorInitializer(ci) - ) - } - - final private TranslatedStmt getBody() { result = getTranslatedStmt(callable.getBody()) } - - final private TranslatedParameter getParameter(int index) { - result = getTranslatedParameter(callable.getParameter(index)) - } - - final override Instruction getFirstInstruction() { - result = this.getInstruction(EnterFunctionTag()) - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - tag = EnterFunctionTag() and - result = this.getInstruction(AliasedDefinitionTag()) - or - ( - tag = AliasedDefinitionTag() and - if exists(this.getThisType()) - then result = this.getInstruction(InitializeThisTag()) - else - if exists(this.getParameter(0)) - then result = this.getParameter(0).getFirstInstruction() - else result = this.getBodyOrReturn() - ) - or - ( - tag = InitializeThisTag() and - if exists(this.getParameter(0)) - then result = this.getParameter(0).getFirstInstruction() - else - if exists(this.getConstructorInitializer()) - then result = this.getConstructorInitializer().getFirstInstruction() - else result = this.getBodyOrReturn() - ) - or - tag = ReturnValueAddressTag() and - result = this.getInstruction(ReturnTag()) - or - tag = ReturnTag() and - result = this.getInstruction(AliasedUseTag()) - or - tag = UnwindTag() and - result = this.getInstruction(AliasedUseTag()) - or - tag = AliasedUseTag() and - result = this.getInstruction(ExitFunctionTag()) - ) - } - - final override Instruction getChildSuccessor(TranslatedElement child) { - exists(int paramIndex | - child = this.getParameter(paramIndex) and - if exists(callable.getParameter(paramIndex + 1)) - then result = this.getParameter(paramIndex + 1).getFirstInstruction() - else - if exists(this.getConstructorInitializer()) - then result = this.getConstructorInitializer().getFirstInstruction() - else result = this.getBodyOrReturn() - ) - or - child = this.getConstructorInitializer() and - result = this.getBodyOrReturn() - or - child = this.getBody() and - result = this.getReturnSuccessorInstruction() - } - - private Instruction getBodyOrReturn() { - if exists(this.getBody()) - then result = this.getBody().getFirstInstruction() - else result = this.getReturnSuccessorInstruction() - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - ( - tag = EnterFunctionTag() and - opcode instanceof Opcode::EnterFunction and - resultType = getVoidType() - or - tag = AliasedDefinitionTag() and - opcode instanceof Opcode::AliasedDefinition and - resultType = getUnknownType() - or - tag = InitializeThisTag() and - opcode instanceof Opcode::InitializeThis and - resultType = getTypeForGLValue(this.getThisType()) - or - tag = ReturnValueAddressTag() and - opcode instanceof Opcode::VariableAddress and - not this.getReturnType() instanceof VoidType and - resultType = getTypeForGLValue(this.getReturnType()) - or - ( - tag = ReturnTag() and - resultType = getVoidType() and - if this.getReturnType() instanceof VoidType - then opcode instanceof Opcode::ReturnVoid - else opcode instanceof Opcode::ReturnValue - ) - or - tag = UnwindTag() and - opcode instanceof Opcode::Unwind and - resultType = getVoidType() and - ( - // Only generate the `Unwind` instruction if there is any exception - // handling present in the function (compiler generated or not). - exists(TryStmt try | try.getEnclosingCallable() = callable) or - exists(ThrowStmt throw | throw.getEnclosingCallable() = callable) - ) - or - tag = AliasedUseTag() and - opcode instanceof Opcode::AliasedUse and - resultType = getVoidType() - or - tag = ExitFunctionTag() and - opcode instanceof Opcode::ExitFunction and - resultType = getVoidType() - ) - } - - final override Instruction getExceptionSuccessorInstruction() { - result = this.getInstruction(UnwindTag()) - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = ReturnTag() and - not this.getReturnType() instanceof VoidType and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ReturnValueAddressTag()) - } - - final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { - tag = ReturnTag() and - not this.getReturnType() instanceof VoidType and - operandTag instanceof LoadOperandTag and - result = getTypeForPRValue(this.getReturnType()) - or - tag = AliasedUseTag() and - operandTag instanceof SideEffectOperandTag and - result = getUnknownType() - } - - final override IRVariable getInstructionVariable(InstructionTag tag) { - tag = ReturnValueAddressTag() and - result = this.getReturnVariable() - } - - final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ReturnValueTempVar() and - type = getTypeForPRValue(this.getReturnType()) and - not this.getReturnType() instanceof VoidType - } - - /** - * Gets the instruction to which control should flow after a `return` - * statement. In C#, this should be the instruction which generates `VariableAddress[#return]`. - */ - final Instruction getReturnSuccessorInstruction() { - if this.getReturnType() instanceof VoidType - then result = this.getInstruction(ReturnTag()) - else result = this.getInstruction(ReturnValueAddressTag()) - } - - /** - * Gets the variable that represents the return value of this function. - */ - final IRReturnVariable getReturnVariable() { - result = getIRTempVariable(callable, ReturnValueTempVar()) - } - - /** - * Gets the single `InitializeThis` instruction for this function. Holds only - * if the function is an instance member function, constructor, or destructor. - */ - final Instruction getInitializeThisInstruction() { - result = this.getInstruction(InitializeThisTag()) - } - - /** - * Gets the type pointed to by the `this` pointer for this function (i.e. `*this`). - * Holds only if the function is an instance member function, constructor, or destructor. - */ - final Type getThisType() { - // `callable` is a user declared member and it is not static - callable instanceof Member and - not callable.(Member).isStatic() and - result = callable.getDeclaringType() - or - // `callable` is a compiler generated accessor - callable instanceof Accessor and - not callable.(Accessor).isStatic() and - result = callable.getDeclaringType() - } - - /** - * Holds if this function defines or accesses variable `var` with type `type`. This includes all - * parameters and local variables, plus any static fields that are directly accessed by the - * function. - */ - final predicate hasUserVariable(Variable var, CSharpType type) { - ( - var.(Member).isStatic() and - exists(VariableAccess access | - access.getTarget() = var and - access.getEnclosingCallable() = callable - ) - or - var.(LocalScopeVariable).getCallable() = callable - ) and - type = getTypeForPRValue(getVariableType(var)) - } - - final private Type getReturnType() { result = callable.getReturnType() } -} - -/** - * Gets the `TranslatedParameter` that represents parameter `param`. - */ -TranslatedParameter getTranslatedParameter(Parameter param) { result.getAst() = param } - -/** - * Represents the IR translation of a function parameter, including the - * initialization of that parameter with the incoming argument. - */ -class TranslatedParameter extends TranslatedElement, TTranslatedParameter { - Parameter param; - - TranslatedParameter() { this = TTranslatedParameter(param) } - - final override string toString() { result = param.toString() } - - final override Language::AST getAst() { result = param } - - final override Callable getFunction() { result = param.getCallable() } - - final override Instruction getFirstInstruction() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override TranslatedElement getChild(int id) { none() } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - tag = InitializerVariableAddressTag() and - result = this.getInstruction(InitializerStoreTag()) - or - tag = InitializerStoreTag() and - result = this.getParent().getChildSuccessor(this) - ) - } - - final override Instruction getChildSuccessor(TranslatedElement child) { none() } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(param.getType()) - or - tag = InitializerStoreTag() and - opcode instanceof Opcode::InitializeParameter and - resultType = getTypeForPRValue(param.getType()) - } - - final override IRVariable getInstructionVariable(InstructionTag tag) { - ( - tag = InitializerStoreTag() or - tag = InitializerVariableAddressTag() - ) and - result = getIRUserVariable(this.getFunction(), param) - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll deleted file mode 100644 index c7cb9232d55..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll +++ /dev/null @@ -1,388 +0,0 @@ -/** - * Class that deals with variable initializations. - * Separated from `TranslatedExpr` for clarity. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import InstructionTag -private import TranslatedElement -private import TranslatedExpr -private import TranslatedFunction -private import IRInternal -private import desugar.Delegate - -/** - * Gets the `TranslatedInitialization` for the expression `expr`. - */ -TranslatedInitialization getTranslatedInitialization(Expr expr) { result.getExpr() = expr } - -/** - * Base class for any `TranslatedElement` that has an initialization as a child. - * Provides the child with the address and type of the location to be - * initialized. - */ -abstract class InitializationContext extends TranslatedElement { - /** - * Gets the instruction that produces the address of the location to be - * initialized. - */ - abstract Instruction getTargetAddress(); - - /** - * Gets the type of the location to be initialized. - */ - abstract Type getTargetType(); -} - -/** - * Represents the IR translation of any initialization, whether from an - * initializer list or from a direct initializer. - */ -abstract class TranslatedInitialization extends TranslatedElement, TTranslatedInitialization { - Expr expr; - - TranslatedInitialization() { this = TTranslatedInitialization(expr) } - - final override string toString() { result = "init: " + expr.toString() } - - final override Callable getFunction() { result = expr.getEnclosingCallable() } - - final override Language::AST getAst() { result = expr } - - /** - * Gets the expression that is doing the initialization. - */ - final Expr getExpr() { result = expr } - - /** - * Gets the initialization context that describes the location being - * initialized. - */ - final InitializationContext getContext() { result = this.getParent() } - - final TranslatedFunction getEnclosingFunction() { - result = getTranslatedFunction(expr.getEnclosingCallable()) - } -} - -/** - * Represents the IR translation of an initialization from an initializer list. - */ -abstract class TranslatedListInitialization extends TranslatedInitialization, InitializationContext { - override Instruction getFirstInstruction() { - result = this.getChild(0).getFirstInstruction() - or - not exists(this.getChild(0)) and result = this.getParent().getChildSuccessor(this) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getChild(index) and - if exists(this.getChild(index + 1)) - then result = this.getChild(index + 1).getFirstInstruction() - else result = this.getParent().getChildSuccessor(this) - ) - } - - final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getTargetAddress() { result = this.getContext().getTargetAddress() } - - override Type getTargetType() { result = this.getContext().getTargetType() } -} - -/** - * Represents the IR translation of an initialization of an array from an - * initializer list. - */ -class TranslatedArrayListInitialization extends TranslatedListInitialization { - override ArrayInitializer expr; - - override TranslatedElement getChild(int id) { - // The children are in initialization order - result = - rank[id + 1](TranslatedElementInitialization init | - init.getInitList() = expr - | - init order by init.getElementIndex() - ) - } -} - -/** - * Represents the IR translation of an initialization from a single initializer - * expression, where the initialization is performed via bitwise copy. - */ -class TranslatedDirectInitialization extends TranslatedInitialization { - TranslatedDirectInitialization() { - not expr instanceof ArrayInitializer and - not expr instanceof ObjectInitializer and - not expr instanceof CollectionInitializer - } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() } - - override Instruction getFirstInstruction() { - result = this.getInitializer().getFirstInstruction() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = InitializerStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(this.getContext().getTargetType()) - or - this.needsConversion() and - tag = AssignmentConvertRightTag() and - // For now only use `Opcode::Convert` to - // crudely represent conversions. Could - // be useful to represent the whole chain of conversions - opcode instanceof Opcode::Convert and - resultType = getTypeForPRValue(this.getContext().getTargetType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = InitializerStoreTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - or - this.needsConversion() and - tag = AssignmentConvertRightTag() and - result = this.getInstruction(InitializerStoreTag()) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitializer() and - if this.needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getInstruction(InitializerStoreTag()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getParent().(InitializationContext).getTargetAddress() - or - ( - operandTag instanceof AddressOperandTag and - result = this.getContext().getTargetAddress() - or - operandTag instanceof StoreValueOperandTag and - result = this.getInitializer().getResult() - ) - ) - or - tag = AssignmentConvertRightTag() and - operandTag instanceof UnaryOperandTag and - result = this.getInitializer().getResult() - or - tag = AssignmentConvertRightTag() and - operandTag instanceof UnaryOperandTag and - result = this.getInstruction(NewObjTag()) - } - - TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) } - - private predicate needsConversion() { expr.getType() != this.getContext().getTargetType() } -} - -/** - * Represents the IR translation of the initialization of an array element from - * an element of an initializer list. - */ -abstract class TranslatedElementInitialization extends TranslatedElement { - ArrayInitializer initList; - - final override string toString() { - result = initList.toString() + "[" + this.getElementIndex().toString() + "]" - } - - final override Language::AST getAst() { result = initList } - - final override Callable getFunction() { result = initList.getEnclosingCallable() } - - final override Instruction getFirstInstruction() { - result = this.getInstruction(this.getElementIndexTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = this.getElementIndexTag() and - opcode instanceof Opcode::Constant and - resultType = getIntType() - or - tag = this.getElementAddressTag() and - opcode instanceof Opcode::PointerAdd and - resultType = getTypeForGLValue(this.getElementType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = this.getElementIndexTag() and - result = this.getInstruction(this.getElementAddressTag()) and - kind instanceof GotoEdge - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = this.getElementAddressTag() and - ( - operandTag instanceof LeftOperandTag and - result = this.getParent().(InitializationContext).getTargetAddress() - or - operandTag instanceof RightOperandTag and - result = this.getInstruction(this.getElementIndexTag()) - ) - } - - override int getInstructionElementSize(InstructionTag tag) { - tag = this.getElementAddressTag() and - result = Language::getTypeSize(this.getElementType()) - } - - override string getInstructionConstantValue(InstructionTag tag) { - tag = this.getElementIndexTag() and - result = this.getElementIndex().toString() - } - - abstract int getElementIndex(); - - final InstructionTag getElementAddressTag() { - result = InitializerElementAddressTag(this.getElementIndex()) - } - - final InstructionTag getElementIndexTag() { - result = InitializerElementIndexTag(this.getElementIndex()) - } - - final ArrayInitializer getInitList() { result = initList } - - final Type getElementType() { result = initList.getAnElement().getType() } -} - -/** - * Represents the IR translation of the initialization of an array element from - * an explicit element in an initializer list. - */ -class TranslatedExplicitElementInitialization extends TranslatedElementInitialization, - TTranslatedExplicitElementInitialization, InitializationContext -{ - int elementIndex; - - TranslatedExplicitElementInitialization() { - this = TTranslatedExplicitElementInitialization(initList, elementIndex) - } - - override Instruction getTargetAddress() { - result = this.getInstruction(this.getElementAddressTag()) - } - - override Type getTargetType() { result = this.getElementType() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - result = TranslatedElementInitialization.super.getInstructionSuccessor(tag, kind) - or - tag = this.getElementAddressTag() and - result = this.getInitialization().getFirstInstruction() and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and result = this.getParent().getChildSuccessor(this) - } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override int getElementIndex() { result = elementIndex } - - TranslatedInitialization getInitialization() { - result = getTranslatedInitialization(initList.getElement(elementIndex)) - } -} - -// TODO: Possibly refactor into something simpler -abstract class TranslatedConstructorCallFromConstructor extends TranslatedElement, - ConstructorCallContext -{ - Call call; - - final override Language::AST getAst() { result = call } - - final override TranslatedElement getChild(int id) { - id = 0 and result = this.getConstructorCall() - } - - final override Callable getFunction() { result = call.getEnclosingCallable() } - - final override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getConstructorCall() and - result = this.getParent().getChildSuccessor(this) - } - - final TranslatedExpr getConstructorCall() { result = getTranslatedExpr(call) } -} - -TranslatedConstructorInitializer getTranslatedConstructorInitializer(ConstructorInitializer ci) { - result.getAst() = ci -} - -/** - * Represents the IR translation of a call from a constructor to a base class - * constructor or another constructor in same class . - */ -// Review: do we need the conversion instructions in C#? -class TranslatedConstructorInitializer extends TranslatedConstructorCallFromConstructor, - TTranslatedConstructorInitializer -{ - TranslatedConstructorInitializer() { this = TTranslatedConstructorInitializer(call) } - - override string toString() { result = "constructor init: " + call.toString() } - - override Instruction getFirstInstruction() { - if this.needsConversion() - then result = this.getInstruction(OnlyInstructionTag()) - else result = this.getConstructorCall().getFirstInstruction() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - this.needsConversion() and - tag = OnlyInstructionTag() and - opcode instanceof Opcode::Convert and - resultType = getTypeForGLValue(call.getTarget().getDeclaringType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - kind instanceof GotoEdge and - result = this.getConstructorCall().getFirstInstruction() - } - - override Instruction getReceiver() { - if this.needsConversion() - then result = this.getInstruction(OnlyInstructionTag()) - else result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction() - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag instanceof UnaryOperandTag and - result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction() - } - - predicate needsConversion() { - call.getTarget().getDeclaringType() != this.getFunction().getDeclaringType() - } - - override predicate getInstructionInheritance( - InstructionTag tag, Class baseClass, Class derivedClass - ) { - tag = OnlyInstructionTag() and - baseClass = call.getTarget().getDeclaringType() and - derivedClass = this.getFunction().getDeclaringType() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll deleted file mode 100644 index 71d8c42e170..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll +++ /dev/null @@ -1,1092 +0,0 @@ -import csharp -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.implementation.internal.OperandTag -private import InstructionTag -private import TranslatedCondition -private import TranslatedDeclaration -private import TranslatedElement -private import TranslatedExpr -private import TranslatedFunction -private import TranslatedInitialization -private import common.TranslatedConditionBase -private import IRInternal -private import experimental.ir.internal.IRUtilities -private import desugar.Foreach -private import desugar.Lock - -TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt } - -abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt { - Stmt stmt; - - TranslatedStmt() { this = TTranslatedStmt(stmt) } - - final override string toString() { result = stmt.toString() } - - final override Language::AST getAst() { result = stmt } - - final override Callable getFunction() { result = stmt.getEnclosingCallable() } -} - -class TranslatedEmptyStmt extends TranslatedStmt { - TranslatedEmptyStmt() { - stmt instanceof EmptyStmt or - stmt instanceof LabelStmt or - stmt instanceof CaseStmt - } - - override TranslatedElement getChild(int id) { none() } - - override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::NoOp and - resultType = getVoidType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -class TranslatedDeclStmt extends TranslatedStmt { - override LocalVariableDeclStmt stmt; - - override TranslatedElement getChild(int id) { result = this.getLocalDeclaration(id) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getFirstInstruction() { - result = this.getLocalDeclaration(0).getFirstInstruction() - } - - private int getChildCount() { result = count(stmt.getAVariableDeclExpr()) } - - private TranslatedLocalDeclaration getLocalDeclaration(int index) { - result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(index)) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getLocalDeclaration(index) and - if index = (this.getChildCount() - 1) - then result = this.getParent().getChildSuccessor(this) - else result = this.getLocalDeclaration(index + 1).getFirstInstruction() - ) - } -} - -class TranslatedExprStmt extends TranslatedStmt { - override ExprStmt stmt; - - TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getExpr() and - result = this.getParent().getChildSuccessor(this) - } -} - -/** - * Class that deals with an `ExprStmt` whose child is an `AssignExpr` whose - * lvalue is an accessor call. - * Since we desugar such an expression to function call, - * we ignore the assignment and make the only child of the translated statement - * the accessor call. - */ -class TranslatedExprStmtAccessorSet extends TranslatedExprStmt { - override ExprStmt stmt; - - TranslatedExprStmtAccessorSet() { - stmt.getExpr() instanceof AssignExpr and - stmt.getExpr().(AssignExpr).getLValue() instanceof AccessorCall - } - - override TranslatedExpr getExpr() { - result = getTranslatedExpr(stmt.getExpr().(AssignExpr).getLValue()) - } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } - - override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getExpr() and - result = this.getParent().getChildSuccessor(this) - } -} - -abstract class TranslatedReturnStmt extends TranslatedStmt { - override ReturnStmt stmt; - - final TranslatedFunction getEnclosingFunction() { - result = getTranslatedFunction(stmt.getEnclosingCallable()) - } -} - -class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationContext { - TranslatedReturnValueStmt() { exists(stmt.getExpr()) } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override Instruction getFirstInstruction() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getEnclosingFunction().getFunction().getReturnType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = InitializerVariableAddressTag() and - result = this.getInitialization().getFirstInstruction() and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and - result = this.getEnclosingFunction().getReturnSuccessorInstruction() - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = InitializerVariableAddressTag() and - result = this.getEnclosingFunction().getReturnVariable() - } - - override Instruction getTargetAddress() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override Type getTargetType() { - result = this.getEnclosingFunction().getReturnVariable().getType() - } - - TranslatedInitialization getInitialization() { - result = getTranslatedInitialization(stmt.getExpr()) - } -} - -class TranslatedReturnVoidStmt extends TranslatedReturnStmt { - TranslatedReturnVoidStmt() { not exists(stmt.getExpr()) } - - override TranslatedElement getChild(int id) { none() } - - override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::NoOp and - resultType = getVoidType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getEnclosingFunction().getReturnSuccessorInstruction() and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -/** - * The IR translation of a C++ `try` statement. - */ -// TODO: Make sure that if the exception is uncaught or rethrown -// finally is still executed. -class TranslatedTryStmt extends TranslatedStmt { - override TryStmt stmt; - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getBody() - or - id = 1 and result = this.getFinally() - or - result = this.getCatchClause(id - 2) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getCatchClause(_) and result = this.getFinally().getFirstInstruction() - or - child = this.getBody() and result = this.getFinally().getFirstInstruction() - or - child = this.getFinally() and result = this.getParent().getChildSuccessor(this) - } - - final Instruction getNextHandler(TranslatedClause clause) { - exists(int index | - clause = this.getCatchClause(index) and - result = this.getCatchClause(index + 1).getFirstInstruction() - ) - or - // 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. - clause = this.getCatchClause(count(stmt.getACatchClause()) - 1) and - result = this.getParent().getExceptionSuccessorInstruction() - } - - final override Instruction getExceptionSuccessorInstruction() { - result = this.getCatchClause(0).getFirstInstruction() - } - - private TranslatedClause getCatchClause(int index) { - result = getTranslatedStmt(stmt.getCatchClause(index)) - } - - private TranslatedStmt getFinally() { result = getTranslatedStmt(stmt.getFinally()) } - - private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBlock()) } -} - -class TranslatedBlock extends TranslatedStmt { - override BlockStmt stmt; - - override TranslatedElement getChild(int id) { result = this.getStmt(id) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - this.isEmpty() and - opcode instanceof Opcode::NoOp and - tag = OnlyInstructionTag() and - resultType = getVoidType() - } - - override Instruction getFirstInstruction() { - if this.isEmpty() - then result = this.getInstruction(OnlyInstructionTag()) - else result = this.getStmt(0).getFirstInstruction() - } - - private predicate isEmpty() { stmt.isEmpty() } - - private TranslatedStmt getStmt(int index) { result = getTranslatedStmt(stmt.getStmt(index)) } - - private int getStmtCount() { result = count(stmt.getAStmt()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getStmt(index) and - if index = (this.getStmtCount() - 1) - then result = this.getParent().getChildSuccessor(this) - else result = this.getStmt(index + 1).getFirstInstruction() - ) - } -} - -/** - * The IR translation of a C# `catch` clause. - */ -abstract class TranslatedClause extends TranslatedStmt { - override CatchClause stmt; - - override TranslatedElement getChild(int id) { id = 1 and result = this.getBlock() } - - override Instruction getFirstInstruction() { result = this.getInstruction(CatchTag()) } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBlock() and result = this.getParent().getChildSuccessor(this) - } - - override Instruction getExceptionSuccessorInstruction() { - // A throw from within a `catch` block flows to the handler for the parent of - // the `try`. - result = this.getParent().getParent().getExceptionSuccessorInstruction() - } - - TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) } -} - -/** - * The IR translation of a C# `catch` block that catches an exception with a - * specific type (e.g. `catch (Exception ex) { ... }`). - */ -class TranslatedCatchByTypeClause extends TranslatedClause { - TranslatedCatchByTypeClause() { stmt instanceof SpecificCatchClause } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = CatchTag() and - opcode instanceof Opcode::CatchByType and - resultType = getVoidType() - } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getParameter() - or - result = super.getChild(id) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - result = super.getChildSuccessor(child) - or - child = this.getParameter() and result = this.getBlock().getFirstInstruction() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = CatchTag() and - ( - kind instanceof GotoEdge and - result = this.getParameter().getFirstInstruction() - or - kind instanceof ExceptionEdge and - result = this.getParent().(TranslatedTryStmt).getNextHandler(this) - ) - } - - override CSharpType getInstructionExceptionType(InstructionTag tag) { - tag = CatchTag() and - result = getTypeForPRValue(stmt.(SpecificCatchClause).getVariable().getType()) - } - - private TranslatedLocalDeclaration getParameter() { - result = getTranslatedLocalDeclaration(stmt.(SpecificCatchClause).getVariableDeclExpr()) - } -} - -/** - * The IR translation of catch block with no parameters. - */ -class TranslatedGeneralCatchClause extends TranslatedClause { - TranslatedGeneralCatchClause() { stmt instanceof GeneralCatchClause } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = CatchTag() and - opcode instanceof Opcode::CatchAny and - resultType = getVoidType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = CatchTag() and - kind instanceof GotoEdge and - result = this.getBlock().getFirstInstruction() - } -} - -/** - * The IR translation of a throw statement that throws an exception, - * as opposed to just rethrowing one. - */ -class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext { - override ThrowStmt stmt; - - TranslatedThrowExceptionStmt() { - // Must throw an exception - exists(stmt.getExpr()) - } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override Instruction getFirstInstruction() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = ThrowTag() and - opcode instanceof Opcode::ThrowValue and - resultType = getVoidType() - or - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getExceptionType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = ThrowTag() and - kind instanceof ExceptionEdge and - result = this.getParent().getExceptionSuccessorInstruction() - or - tag = InitializerVariableAddressTag() and - result = this.getInitialization().getFirstInstruction() and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and - result = this.getInstruction(ThrowTag()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = InitializerVariableAddressTag() and - result = getIRTempVariable(stmt, ThrowTempVar()) - } - - final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ThrowTempVar() and - type = getTypeForPRValue(this.getExceptionType()) - } - - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = ThrowTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { - tag = ThrowTag() and - operandTag instanceof LoadOperandTag and - result = getTypeForPRValue(this.getExceptionType()) - } - - override Instruction getTargetAddress() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - override Type getTargetType() { result = this.getExceptionType() } - - TranslatedInitialization getInitialization() { - result = getTranslatedInitialization(stmt.getExpr()) - } - - private Type getExceptionType() { result = stmt.getExpr().getType() } -} - -/** - * The IR translation of a simple throw statement, ie. one that just - * rethrows an exception. - */ -class TranslatedEmptyThrowStmt extends TranslatedStmt { - override ThrowStmt stmt; - - TranslatedEmptyThrowStmt() { not exists(stmt.getExpr()) } - - override TranslatedElement getChild(int id) { none() } - - override Instruction getFirstInstruction() { result = this.getInstruction(ThrowTag()) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = ThrowTag() and - opcode instanceof Opcode::ReThrow and - resultType = getVoidType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = ThrowTag() and - kind instanceof ExceptionEdge and - result = this.getParent().getExceptionSuccessorInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -class TranslatedIfStmt extends TranslatedStmt, ConditionContext { - override IfStmt stmt; - - override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getCondition() - or - id = 1 and result = this.getThen() - or - id = 2 and result = this.getElse() - } - - private TranslatedCondition getCondition() { - result = getTranslatedCondition(stmt.getCondition()) - } - - private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) } - - private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) } - - private predicate hasElse() { exists(stmt.getElse()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getThen().getFirstInstruction() - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and - if this.hasElse() - then result = this.getElse().getFirstInstruction() - else result = this.getParent().getChildSuccessor(this) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - (child = this.getThen() or child = this.getElse()) and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } -} - -abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { - override LoopStmt stmt; - - final TranslatedCondition getCondition() { result = getTranslatedCondition(stmt.getCondition()) } - - final TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) } - - final Instruction getFirstConditionInstruction() { - if this.hasCondition() - then result = this.getCondition().getFirstInstruction() - else result = this.getBody().getFirstInstruction() - } - - final predicate hasCondition() { exists(stmt.getCondition()) } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getCondition() - or - id = 1 and result = this.getBody() - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - final override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and result = this.getBody().getFirstInstruction() - } - - final override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and result = this.getParent().getChildSuccessor(this) - } -} - -class TranslatedWhileStmt extends TranslatedLoop { - TranslatedWhileStmt() { stmt instanceof WhileStmt } - - override Instruction getFirstInstruction() { result = this.getFirstConditionInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBody() and result = this.getFirstConditionInstruction() - } -} - -class TranslatedDoStmt extends TranslatedLoop { - TranslatedDoStmt() { stmt instanceof DoStmt } - - override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBody() and result = this.getFirstConditionInstruction() - } -} - -class TranslatedForStmt extends TranslatedLoop { - override ForStmt stmt; - - override TranslatedElement getChild(int id) { - this.initializerIndex(id) and result = this.getDeclAndInit(id) - or - result = this.getUpdate(this.updateIndex(id)) - or - id = this.initializersNo() + this.updatesNo() and result = this.getCondition() - or - id = this.initializersNo() + this.updatesNo() + 1 and result = this.getBody() - } - - private TranslatedElement getDeclAndInit(int index) { - if stmt.getInitializer(index) instanceof LocalVariableDeclExpr - then result = getTranslatedLocalDeclaration(stmt.getInitializer(index)) - else result = getTranslatedExpr(stmt.getInitializer(index)) - } - - private predicate hasInitialization() { exists(stmt.getAnInitializer()) } - - 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 initializerIndex(int index) { index in [0 .. this.initializersNo() - 1] } - - private int updateIndex(int index) { - result in [0 .. this.updatesNo() - 1] and - index = this.initializersNo() + result - } - - override Instruction getFirstInstruction() { - if this.hasInitialization() - then result = this.getDeclAndInit(0).getFirstInstruction() - else result = this.getFirstConditionInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getDeclAndInit(index) and - index < this.initializersNo() - 1 and - result = this.getDeclAndInit(index + 1).getFirstInstruction() - ) - or - child = this.getDeclAndInit(this.initializersNo() - 1) and - result = this.getFirstConditionInstruction() - or - ( - child = this.getBody() and - if this.hasUpdate() - then result = this.getUpdate(0).getFirstInstruction() - else result = this.getFirstConditionInstruction() - ) - or - exists(int index | - child = this.getUpdate(index) and - result = this.getUpdate(index + 1).getFirstInstruction() - ) - or - child = this.getUpdate(this.updatesNo() - 1) and - result = this.getFirstConditionInstruction() - } -} - -/** - * Base class for the translation of `BreakStmt`s and `GotoStmt`s. - */ -abstract class TranslatedSpecificJump extends TranslatedStmt { - override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - - override TranslatedElement getChild(int id) { none() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::NoOp and - resultType = getVoidType() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - kind instanceof GotoEdge and - result = this.getTargetInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } - - /** - * Gets the instruction that is the target of the jump. - */ - abstract Instruction getTargetInstruction(); -} - -class TranslatedBreakStmt extends TranslatedSpecificJump { - override BreakStmt stmt; - - override Instruction getTargetInstruction() { result = getEnclosingLoopOrSwitchNextInstr(stmt) } -} - -private Instruction getEnclosingLoopOrSwitchNextInstr(Stmt crtStmt) { - if crtStmt instanceof LoopStmt or crtStmt instanceof SwitchStmt - then result = getTranslatedStmt(crtStmt).getParent().getChildSuccessor(getTranslatedStmt(crtStmt)) - else result = getEnclosingLoopOrSwitchNextInstr(crtStmt.getParent()) -} - -class TranslatedContinueStmt extends TranslatedSpecificJump { - override ContinueStmt stmt; - - override Instruction getTargetInstruction() { result = getEnclosingLoopTargetInstruction(stmt) } -} - -private Instruction getEnclosingLoopTargetInstruction(Stmt crtStmt) { - if crtStmt instanceof ForStmt - then result = getNextForInstruction(crtStmt) - else - if crtStmt instanceof LoopStmt - then result = getTranslatedStmt(crtStmt).getFirstInstruction() - else result = getEnclosingLoopTargetInstruction(crtStmt.getParent()) -} - -private Instruction getNextForInstruction(ForStmt for) { - if exists(for.getUpdate(0)) - then result = getTranslatedStmt(for).(TranslatedForStmt).getUpdate(0).getFirstInstruction() - else - if exists(for.getCondition()) - then result = getTranslatedStmt(for).(TranslatedForStmt).getCondition().getFirstInstruction() - else result = getTranslatedStmt(for).(TranslatedForStmt).getBody().getFirstInstruction() -} - -class TranslatedGotoLabelStmt extends TranslatedSpecificJump { - override GotoLabelStmt stmt; - - override Instruction getTargetInstruction() { - result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction() - } -} - -class TranslatedGotoCaseStmt extends TranslatedSpecificJump { - override GotoCaseStmt stmt; - - override Instruction getTargetInstruction() { - result = getCase(stmt, stmt.getExpr()).getFirstInstruction() - } -} - -private TranslatedStmt getCase(Stmt crtStmt, Expr expr) { - if crtStmt instanceof SwitchStmt - then - exists(CaseStmt caseStmt | - caseStmt = crtStmt.(SwitchStmt).getACase() and - // We check for the constant value of the expression - // since we can't check for equality between `PatternExpr` and `Expr` - caseStmt.getPattern().getValue() = expr.getValue() and - result = getTranslatedStmt(caseStmt) - ) - else result = getCase(crtStmt.getParent(), expr) -} - -class TranslatedGotoDefaultStmt extends TranslatedSpecificJump { - override GotoDefaultStmt stmt; - - override Instruction getTargetInstruction() { - result = getDefaultCase(stmt).getFirstInstruction() - } -} - -private TranslatedStmt getDefaultCase(Stmt crtStmt) { - if crtStmt instanceof SwitchStmt - then - exists(CaseStmt caseStmt | - caseStmt = crtStmt.(SwitchStmt).getDefaultCase() and - result = getTranslatedStmt(caseStmt) - ) - else result = getDefaultCase(crtStmt.getParent()) -} - -class TranslatedSwitchStmt extends TranslatedStmt { - override SwitchStmt stmt; - - private TranslatedExpr getSwitchExpr() { result = getTranslatedExpr(stmt.getExpr()) } - - override Instruction getFirstInstruction() { result = this.getSwitchExpr().getFirstInstruction() } - - override TranslatedElement getChild(int id) { - if id = -1 - then - // The switch expression. - result = getTranslatedExpr(stmt.getChild(0)) - else - if id = 0 - then - // The first case's body. - result = getTranslatedStmt(stmt.getChild(0)) - else - // The subsequent case's bodies. - result = getTranslatedStmt(stmt.getChild(id)) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = SwitchBranchTag() and - opcode instanceof Opcode::Switch and - resultType = getVoidType() - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = SwitchBranchTag() and - operandTag instanceof ConditionOperandTag and - result = this.getSwitchExpr().getResult() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = SwitchBranchTag() and - exists(CaseStmt caseStmt | - caseStmt = stmt.getACase() and - kind = this.getCaseEdge(caseStmt) and - result = getTranslatedStmt(caseStmt).getFirstInstruction() - ) - or - not exists(stmt.getDefaultCase()) and - tag = SwitchBranchTag() and - kind instanceof DefaultEdge and - result = this.getParent().getChildSuccessor(this) - } - - private EdgeKind getCaseEdge(CaseStmt caseStmt) { - if caseStmt instanceof DefaultCase - then result instanceof DefaultEdge - else - exists(CaseEdge edge | - result = edge and - hasCaseEdge(caseStmt, edge.getMinValue(), edge.getMinValue()) - ) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getSwitchExpr() and result = this.getInstruction(SwitchBranchTag()) - or - exists(int index, int numStmts | - numStmts = count(stmt.getAChild()) and - child = getTranslatedStmt(stmt.getChild(index)) and - if index = (numStmts - 1) - then result = this.getParent().getChildSuccessor(this) - else result = getTranslatedStmt(stmt.getChild(index + 1)).getFirstInstruction() - ) - } -} - -class TranslatedEnumeratorForeach extends TranslatedLoop { - override ForeachStmt stmt; - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getTempEnumDecl() - or - id = 1 and result = this.getTry() - } - - override Instruction getFirstInstruction() { - result = this.getTempEnumDecl().getFirstInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getTempEnumDecl() and - result = this.getTry().getFirstInstruction() - or - child = this.getTry() and - result = this.getParent().getChildSuccessor(this) - } - - private TranslatedElement getTry() { result = ForeachElements::getTry(stmt) } - - private TranslatedElement getTempEnumDecl() { result = ForeachElements::getEnumDecl(stmt) } -} - -class TranslatedUnsafeStmt extends TranslatedStmt { - override UnsafeStmt stmt; - - override TranslatedElement getChild(int id) { id = 0 and result = this.getBlock() } - - override Instruction getFirstInstruction() { result = this.getBlock().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBlock() and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) } -} - -// TODO: does not reflect the fixed part, just treats the stmt -// as some declarations followed by the body -class TranslatedFixedStmt extends TranslatedStmt { - override FixedStmt stmt; - - override TranslatedElement getChild(int id) { - result = this.getDecl(id) - or - id = this.noDecls() and result = this.getBody() - } - - override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int id | - child = this.getDecl(id) and - id < this.noDecls() - 1 and - result = this.getDecl(id + 1).getFirstInstruction() - ) - or - child = this.getDecl(this.noDecls() - 1) and result = this.getBody().getFirstInstruction() - or - child = this.getBody() and result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedLocalDeclaration getDecl(int id) { - result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id)) - } - - private int noDecls() { result = count(stmt.getAVariableDeclExpr()) } - - private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) } -} - -class TranslatedLockStmt extends TranslatedStmt { - override LockStmt stmt; - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getLockedVarDecl() - or - id = 1 and result = this.getLockWasTakenDecl() - or - id = 2 and result = this.getTry() - } - - override Instruction getFirstInstruction() { - result = this.getLockedVarDecl().getFirstInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getLockedVarDecl() and - result = this.getLockWasTakenDecl().getFirstInstruction() - or - child = this.getLockWasTakenDecl() and - result = this.getTry().getFirstInstruction() - or - child = this.getTry() and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedElement getTry() { result = LockElements::getTry(stmt) } - - private TranslatedElement getLockedVarDecl() { result = LockElements::getLockedVarDecl(stmt) } - - private TranslatedElement getLockWasTakenDecl() { - result = LockElements::getLockWasTakenDecl(stmt) - } -} - -// TODO: Should be modeled using the desugaring framework for a -// more exact translation. -class TranslatedCheckedUncheckedStmt extends TranslatedStmt { - TranslatedCheckedUncheckedStmt() { - stmt instanceof CheckedStmt or - stmt instanceof UncheckedStmt - } - - override TranslatedElement getChild(int id) { id = 0 and result = this.getBody() } - - override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBody() and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedElement getBody() { - result = getTranslatedStmt(stmt.(CheckedStmt).getBlock()) or - result = getTranslatedStmt(stmt.(UncheckedStmt).getBlock()) - } -} - -// TODO: Should be modeled using the desugaring framework for a -// more exact translation. -class TranslatedUsingBlockStmt extends TranslatedStmt { - override UsingBlockStmt stmt; - - override TranslatedElement getChild(int id) { - result = this.getDecl(id) - or - id = this.getNumberOfDecls() and result = this.getBody() - } - - override Instruction getFirstInstruction() { - if this.getNumberOfDecls() > 0 - then result = this.getDecl(0).getFirstInstruction() - else result = this.getBody().getFirstInstruction() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int id | - child = this.getDecl(id) and - result = this.getDecl(id + 1).getFirstInstruction() - ) - or - child = this.getDecl(this.getNumberOfDecls() - 1) and - result = this.getBody().getFirstInstruction() - or - child = this.getBody() and result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedLocalDeclaration getDecl(int id) { - result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id)) - } - - private int getNumberOfDecls() { result = count(stmt.getAVariableDeclExpr()) } - - private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) } -} - -// TODO: Should be modeled using the desugaring framework for a -// more exact translation. -class TranslatedUsingDeclStmt extends TranslatedStmt { - override UsingDeclStmt stmt; - - override TranslatedElement getChild(int id) { result = this.getDecl(id) } - - override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int id | - child = this.getDecl(id) and - id < this.noDecls() - 1 and - result = this.getDecl(id + 1).getFirstInstruction() - ) - or - child = this.getDecl(this.noDecls() - 1) and result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - private TranslatedLocalDeclaration getDecl(int id) { - result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id)) - } - - private int noDecls() { result = count(stmt.getAVariableDeclExpr()) } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll deleted file mode 100644 index 6243663f1cc..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Contains an abstract class that serves as a Base for classes that deal with the translation of calls - * (both AST generated and compiler generated). - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRCSharpLanguage as Language -private import TranslatedExprBase - -abstract class TranslatedCallBase extends TranslatedElement { - final override 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, - // 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 = this.getQualifier() - or - result = this.getArgument(id) - } - - final override Instruction getFirstInstruction() { - if exists(this.getQualifier()) - then result = this.getQualifier().getFirstInstruction() - else result = this.getInstruction(CallTargetTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = CallTag() and - opcode instanceof Opcode::Call and - resultType = getTypeForPRValue(this.getCallResultType()) - or - this.hasSideEffect() and - tag = CallSideEffectTag() and - ( - if this.hasWriteSideEffect() - then ( - opcode instanceof Opcode::CallSideEffect and - resultType = getUnknownType() - ) else ( - opcode instanceof Opcode::CallReadSideEffect and - resultType = getUnknownType() - ) - ) - or - tag = CallTargetTag() and - opcode instanceof Opcode::FunctionAddress and - // Since the DB does not have a function type, - // we just use the UnknownType - resultType = getFunctionAddressType() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getQualifier() and - result = this.getInstruction(CallTargetTag()) - or - exists(int argIndex | - child = this.getArgument(argIndex) and - if exists(this.getArgument(argIndex + 1)) - then result = this.getArgument(argIndex + 1).getFirstInstruction() - else result = this.getInstruction(CallTag()) - ) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - ( - tag = CallTag() and - if this.hasSideEffect() - then result = this.getInstruction(CallSideEffectTag()) - else result = this.getParent().getChildSuccessor(this) - ) - or - this.hasSideEffect() and - tag = CallSideEffectTag() and - result = this.getParent().getChildSuccessor(this) - or - tag = CallTargetTag() and - kind instanceof GotoEdge and - result = this.getFirstArgumentOrCallInstruction() - ) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = CallTag() and - ( - operandTag instanceof CallTargetOperandTag and - result = this.getInstruction(CallTargetTag()) - or - operandTag instanceof ThisArgumentOperandTag and - result = this.getQualifierResult() - or - exists(PositionalArgumentOperandTag argTag | - argTag = operandTag and - result = this.getArgument(argTag.getArgIndex()).getResult() - ) - ) - } - - final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { - tag = CallSideEffectTag() and - this.hasSideEffect() and - operandTag instanceof SideEffectOperandTag and - result = getUnknownType() - } - - Instruction getResult() { result = this.getInstruction(CallTag()) } - - /** - * Gets the result type of the call. - */ - abstract Type getCallResultType(); - - /** - * Holds if the call has a `this` argument. - */ - predicate hasQualifier() { exists(this.getQualifier()) } - - /** - * Gets the expr for the qualifier of the call. - */ - abstract TranslatedExprBase getQualifier(); - - /** - * Gets the instruction whose result value is the `this` argument of the call. - * In general, this is just the result of `getQualifier()`, but it can be - * overridden by a subclass for cases where there is a `this` argument that is - * not computed from a child expression (e.g. a constructor call). - */ - abstract Instruction getQualifierResult(); - - /** - * Gets the argument with the specified `index`. Does not include the `this` - * argument. We use `TranslatedExprBase` so that we can give both `TranslatedExpr` args, - * in the case of AST generated arguments, or `TranslatedCompilerElement` args in the case of - * compiler generated arguments. - */ - abstract TranslatedExprBase getArgument(int index); - - /** - * If there are any arguments, gets the first instruction of the first - * argument. Otherwise, returns the call instruction. - */ - final Instruction getFirstArgumentOrCallInstruction() { - if this.hasArguments() - then result = this.getArgument(0).getFirstInstruction() - else result = this.getInstruction(CallTag()) - } - - /** - * Holds if the call has any arguments, not counting the `this` argument. - */ - final predicate hasArguments() { exists(this.getArgument(0)) } - - predicate hasReadSideEffect() { any() } - - predicate hasWriteSideEffect() { any() } - - private predicate hasSideEffect() { this.hasReadSideEffect() or this.hasWriteSideEffect() } - - override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { - this.hasSideEffect() and - tag = CallSideEffectTag() and - result = this.getResult() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll deleted file mode 100644 index ec12b31f986..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Contains several abstract classes that serve as Bases. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.implementation.raw.internal.TranslatedCondition -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRCSharpLanguage as Language - -/** - * Represents the context of the condition, ie. provides - * information about the instruction that follows a conditional branch. - */ -abstract class ConditionContext extends TranslatedElement { - abstract Instruction getChildTrueSuccessor(ConditionBase child); - - abstract Instruction getChildFalseSuccessor(ConditionBase child); -} - -/** - * 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 = this.getParent() } -} - -/** - * 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 = this.getValueExpr() } - - override Instruction getFirstInstruction() { result = this.getValueExpr().getFirstInstruction() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = ValueConditionConditionalBranchTag() and - opcode instanceof Opcode::ConditionalBranch and - resultType = getVoidType() - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getValueExpr() and - result = this.getInstruction(ValueConditionConditionalBranchTag()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = ValueConditionConditionalBranchTag() and - ( - kind instanceof TrueEdge and - result = this.getConditionContext().getChildTrueSuccessor(this) - or - kind instanceof FalseEdge and - result = this.getConditionContext().getChildFalseSuccessor(this) - ) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = ValueConditionConditionalBranchTag() and - operandTag instanceof ConditionOperandTag and - result = this.valueExprResult() - } - - /** - * 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(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll deleted file mode 100644 index a4e6501d0e4..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ /dev/null @@ -1,93 +0,0 @@ -/** - * 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). - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.internal.IRUtilities -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.implementation.raw.internal.TranslatedInitialization -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class LocalVariableDeclarationBase extends TranslatedElement { - override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override Instruction getFirstInstruction() { result = this.getVarAddress() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getVarType()) - or - this.hasUninitializedInstruction() and - tag = InitializerStoreTag() and - opcode instanceof Opcode::Uninitialized and - resultType = getTypeForPRValue(this.getVarType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - ( - tag = InitializerVariableAddressTag() and - kind instanceof GotoEdge and - if this.hasUninitializedInstruction() - then result = this.getInstruction(InitializerStoreTag()) - else result = this.getInitialization().getFirstInstruction() - ) - or - this.hasUninitializedInstruction() and - kind instanceof GotoEdge and - tag = InitializerStoreTag() and - ( - result = this.getInitialization().getFirstInstruction() - or - not exists(this.getInitialization()) and result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and result = this.getParent().getChildSuccessor(this) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - this.hasUninitializedInstruction() and - tag = InitializerStoreTag() and - operandTag instanceof AddressOperandTag and - result = this.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 - * desugaring process. - */ - predicate hasUninitializedInstruction() { - not exists(this.getInitialization()) or - this.getInitialization() instanceof TranslatedListInitialization - } - - Instruction getVarAddress() { result = this.getInstruction(InitializerVariableAddressTag()) } - - /** - * 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(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll deleted file mode 100644 index ec6a8c0ab00..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Contains an abstract class that serves as a Base for classes that deal with the translation of exprs - * (both AST generated and compiler generated). - */ - -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedExprBase extends TranslatedElement { - /** - * Gets the instruction that produces the result of the expression. - */ - abstract Instruction getResult(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll deleted file mode 100644 index d9c7910be4c..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Exposes several patterns for the compiler generated code, so as to improve code sharing between files that - * deal with the desugaring process. - * For example, we expose the `try ... finally` pattern, which is shared by the desugaring of both the - * `ForeachStmt`, `UsingStmt` and `LockStmt`. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedFunction -private import experimental.ir.implementation.raw.internal.InstructionTag -private import internal.TranslatedCompilerGeneratedStmt -private import internal.TranslatedCompilerGeneratedExpr -private import internal.TranslatedCompilerGeneratedCondition -private import internal.TranslatedCompilerGeneratedCall -private import internal.TranslatedCompilerGeneratedElement -private import internal.TranslatedCompilerGeneratedDeclaration -private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase -private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase -private import experimental.ir.internal.IRCSharpLanguage as Language - -/** - * The general form of a compiler generated try stmt. - * The concrete implementation needs to specify the body of the try and the - * finally block. - */ -abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGeneratedStmt { - override Stmt generatedBy; - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getBody() - or - id = 1 and result = this.getFinally() - } - - override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getBody() and result = this.getFinally().getFirstInstruction() - or - child = this.getFinally() and result = this.getParent().getChildSuccessor(this) - } - - override Instruction getExceptionSuccessorInstruction() { - result = this.getParent().getExceptionSuccessorInstruction() - } - - /** - * Gets the finally block. - */ - abstract TranslatedElement getFinally(); - - /** - * Gets the body of the try stmt. - */ - abstract TranslatedElement getBody(); -} - -/** - * The general form of a compiler generated constant expression. - * The concrete implementation needs to specify the immediate operand that represents the constant. - */ -abstract class TranslatedCompilerGeneratedConstant extends TranslatedCompilerGeneratedExpr { - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - opcode instanceof Opcode::Constant and - tag = OnlyInstructionTag() and - resultType = getTypeForPRValue(this.getResultType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = OnlyInstructionTag() and - kind instanceof GotoEdge and - result = this.getParent().getChildSuccessor(this) - } - - override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - - override TranslatedElement getChild(int id) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } -} - -/** - * The general form of a compiler generated block stmt. - * The concrete implementation needs to specify the statements that - * compose the block. - */ -abstract class TranslatedCompilerGeneratedBlock extends TranslatedCompilerGeneratedStmt { - override TranslatedElement getChild(int id) { result = this.getStmt(id) } - - override Instruction getFirstInstruction() { result = this.getStmt(0).getFirstInstruction() } - - abstract TranslatedElement getStmt(int index); - - private int getStmtCount() { result = count(this.getStmt(_)) } - - override Instruction getChildSuccessor(TranslatedElement child) { - exists(int index | - child = this.getStmt(index) and - if index = (this.getStmtCount() - 1) - then result = this.getParent().getChildSuccessor(this) - else result = this.getStmt(index + 1).getFirstInstruction() - ) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } -} - -/** - * The general form of a compiler generated if stmt. - * The concrete implementation needs to specify the condition, - * the body of the `then` and the body of the `else`. - */ -abstract class TranslatedCompilerGeneratedIfStmt extends TranslatedCompilerGeneratedStmt, - ConditionContext -{ - override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getCondition() - or - id = 1 and result = this.getThen() - or - id = 2 and result = this.getElse() - } - - abstract TranslatedCompilerGeneratedValueCondition getCondition(); - - abstract TranslatedCompilerGeneratedElement getThen(); - - abstract TranslatedCompilerGeneratedElement getElse(); - - private predicate hasElse() { exists(this.getElse()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and - result = this.getThen().getFirstInstruction() - } - - override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and - if this.hasElse() - then result = this.getElse().getFirstInstruction() - else result = this.getParent().getChildSuccessor(this) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - (child = this.getThen() or child = this.getElse()) and - result = this.getParent().getChildSuccessor(this) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } -} - -/** - * The general form of a compiler generated variable access. - * The concrete implementation needs to specify the immediate - * operand for the `VariableAddress` instruction and if the - * access needs a `Load` instruction or not (eg. `ref` params do not) - */ -abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompilerGeneratedExpr { - override Instruction getFirstInstruction() { result = this.getInstruction(AddressTag()) } - - override TranslatedElement getChild(int id) { none() } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } - - /** - * Returns the type of the accessed variable. Can be overridden when the return - * type is different than the type of the underlying variable. - */ - Type getVariableType() { result = this.getResultType() } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = AddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(this.getVariableType()) - or - this.needsLoad() and - tag = LoadTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForPRValue(this.getVariableType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - this.needsLoad() and - tag = LoadTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - or - ( - tag = AddressTag() and - kind instanceof GotoEdge and - if this.needsLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getParent().getChildSuccessor(this) - ) - } - - override Instruction getResult() { - if this.needsLoad() - then result = this.getInstruction(LoadTag()) - else result = this.getInstruction(AddressTag()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - this.needsLoad() and - tag = LoadTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(AddressTag()) - } - - /** - * Holds if the variable access should be followed by a `Load` instruction. - */ - abstract predicate needsLoad(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll deleted file mode 100644 index 3f1a1dec646..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll +++ /dev/null @@ -1,109 +0,0 @@ -/** - * File that translates the desugaring of delegate creation and call expressions. - * In particular, in the IR we explicitly allocate a new object and call the delegate's constructor when - * creating a new one. - * For the delegate call, we explicitly call the `Invoke` method. - * More information about the internals: - * https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs - * This is a rough approximation which will need further refining. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedStmt -private import experimental.ir.implementation.raw.internal.TranslatedCondition -private import experimental.ir.internal.IRCSharpLanguage as Language -private import Common -private import internal.TranslatedCompilerGeneratedCall -private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase - -/** - * Module that exposes the functions needed for the translation of the delegate creation and call expressions. - */ -module DelegateElements { - TranslatedDelegateConstructorCall getConstructor(DelegateCreation generatedBy) { - result.getAst() = generatedBy - } - - TranslatedDelegateInvokeCall getInvoke(DelegateCall generatedBy) { result.getAst() = generatedBy } - - int noGeneratedElements(Element generatedBy) { - ( - generatedBy instanceof DelegateCreation or - generatedBy instanceof DelegateCall - ) and - result = 2 - } -} - -/** - * The translation of the constructor call that happens as part of the delegate creation. - */ -private class TranslatedDelegateConstructorCall extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override DelegateCreation generatedBy; - - TranslatedDelegateConstructorCall() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) } - - final override Type getCallResultType() { result instanceof VoidType } - - override TranslatedExpr getArgument(int index) { - index = 0 and result = getTranslatedExpr(generatedBy.getArgument()) - } - - override TranslatedExprBase getQualifier() { none() } - - override Instruction getQualifierResult() { - exists(ConstructorCallContext context | - context = this.getParent() and - result = context.getReceiver() - ) - } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - exists(Callable internal | - internal.getName() = generatedBy.getDelegateType().getName() and - internal.isCompilerGenerated() and - internal.getFile() = generatedBy.getFile() and - result = internal - ) - } -} - -/** - * The translation of the invoke call that happens as part of the desugaring of the delegate call. - */ -private class TranslatedDelegateInvokeCall extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override DelegateCall generatedBy; - - TranslatedDelegateInvokeCall() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) } - - final override Type getCallResultType() { result instanceof VoidType } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - exists(Callable internal | - internal.getName() = "Invoke" and - internal.isCompilerGenerated() and - internal.getFile() = generatedBy.getFile() and - result = internal - ) - } - - override TranslatedExprBase getQualifier() { result = getTranslatedExpr(generatedBy.getExpr()) } - - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } - - override TranslatedExpr getArgument(int index) { - result = getTranslatedExpr(generatedBy.getArgument(index)) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll deleted file mode 100644 index e49f579ecdf..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll +++ /dev/null @@ -1,457 +0,0 @@ -/** - * File that provides the desugaring of a `Foreach` stmt. - * Since Roslyn rewrites it in quite a few ways, - * for now only desugar it to a "canonical" form. - * Also we only deal with foreach stmts where there is only - * one declaration (see below). - * For example the code: - * ```csharp - * foreach(var item in some_enumerable) { - * // body - * } - * ``` - * gets desugared to: - * ```csharp - * Enumerator e = some_enumerable.GetEnumerator(); - * try - * { - * while(e.MoveNext()) - * { - * int current = e.Current; - * //body - * } - * } - * finally - * { - * e.Dispose(); - * } - * ``` - * More info about the desugaring process for `foreach` stmts: - * https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs - * A TODO is to not call `Dispose` no matter what, but desugar the `finally` as an `AsExpr` (cast to IDisposable), - * the call to `Dispose` being made only if the result of the `AsExpr` is not null. - * This is a rough approximation which will need further refining. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedStmt -private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase -private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase -private import experimental.ir.internal.IRCSharpLanguage as Language -private import Common -private import internal.TranslatedCompilerGeneratedStmt -private import internal.TranslatedCompilerGeneratedCall -private import internal.TranslatedCompilerGeneratedDeclaration -private import internal.TranslatedCompilerGeneratedCondition -private import internal.TranslatedCompilerGeneratedElement - -/** - * Module that exposes the functions needed for the translation of the `foreach` stmt. - */ -module ForeachElements { - TranslatedForeachTry getTry(ForeachStmt generatedBy) { result.getAst() = generatedBy } - - TranslatedForeachEnumerator getEnumDecl(ForeachStmt generatedBy) { result.getAst() = generatedBy } - - int noGeneratedElements() { result = 13 } -} - -private class TranslatedForeachTry extends TranslatedCompilerGeneratedTry, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachTry() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) } - - override TranslatedElement getFinally() { - exists(TranslatedForeachFinally ff | - ff.getAst() = generatedBy and - result = ff - ) - } - - override TranslatedElement getBody() { - exists(TranslatedForeachWhile fw | - fw.getAst() = generatedBy and - result = fw - ) - } -} - -/** - * The translation of the finally block. - */ -private class TranslatedForeachFinally extends TranslatedCompilerGeneratedBlock, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachFinally() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) } - - override TranslatedElement getStmt(int index) { - index = 0 and - exists(TranslatedForeachDispose fd | - fd.getAst() = generatedBy and - result = fd - ) - } -} - -/** - * The compiler generated while loop. - * Note that this class is not private since it is needed in `IRConstruction.qll`, - * to correctly mark which edges should be back edges. - */ -class TranslatedForeachWhile extends TranslatedCompilerGeneratedStmt, ConditionContext, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachWhile() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - none() - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } - - override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInit() and result = this.getBody().getFirstInstruction() - or - child = this.getBody() and result = this.getCondition().getFirstInstruction() - } - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getCondition() - or - id = 1 and result = this.getInit() - or - id = 2 and result = this.getBody() - } - - final override Instruction getChildTrueSuccessor(ConditionBase child) { - child = this.getCondition() and result = this.getInit().getFirstInstruction() - } - - final override Instruction getChildFalseSuccessor(ConditionBase child) { - child = this.getCondition() and result = this.getParent().getChildSuccessor(this) - } - - TranslatedStmt getBody() { result = getTranslatedStmt(generatedBy.getBody()) } - - TranslatedElement getInit() { - exists(TranslatedForeachIterVar iv | - iv.getAst() = generatedBy and - result = iv - ) - } - - ValueConditionBase getCondition() { - exists(TranslatedForeachWhileCondition cond | - cond.getAst() = generatedBy and - result = cond - ) - } -} - -/** - * The translation of the call to the `MoveNext` method, used as a condition for the while. - */ -private class TranslatedForeachMoveNext extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachMoveNext() { this = TTranslatedCompilerGeneratedElement(generatedBy, 3) } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - result = generatedBy.getMoveNext() - } - - override Type getCallResultType() { result instanceof BoolType } - - override TranslatedExpr getArgument(int id) { none() } - - override TranslatedExprBase getQualifier() { - exists(TranslatedMoveNextEnumAcc acc | - acc.getAst() = generatedBy and - result = acc - ) - } - - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } -} - -/** - * The translation of the call to retrieve the enumerator. - */ -private class TranslatedForeachGetEnumerator extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachGetEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 4) } - - final override Type getCallResultType() { - result = this.getInstructionFunction(CallTargetTag()).getReturnType() - } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - result = generatedBy.getGetEnumerator() - } - - override TranslatedExpr getArgument(int id) { none() } - - override TranslatedExprBase getQualifier() { - result = getTranslatedExpr(generatedBy.getIterableExpr()) - } - - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } -} - -/** - * The translation of the call to the getter method of the `Current` property of the enumerator. - */ -private class TranslatedForeachCurrent extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachCurrent() { this = TTranslatedCompilerGeneratedElement(generatedBy, 5) } - - override Type getCallResultType() { result = generatedBy.getElementType() } - - override TranslatedExpr getArgument(int id) { none() } - - override TranslatedExprBase getQualifier() { - exists(TranslatedForeachCurrentEnumAcc acc | - acc.getAst() = generatedBy and - result = acc - ) - } - - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - result = generatedBy.getCurrent().getGetter() - } -} - -/** - * The translation of the call to dispose (inside the finally block) - */ -private class TranslatedForeachDispose extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachDispose() { this = TTranslatedCompilerGeneratedElement(generatedBy, 6) } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - result = generatedBy.getDispose() - } - - final override Type getCallResultType() { result instanceof VoidType } - - override TranslatedExpr getArgument(int id) { none() } - - override TranslatedExprBase getQualifier() { - exists(TranslatedForeachDisposeEnumAcc acc | - acc.getAst() = generatedBy and - result = acc - ) - } - - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } -} - -/** - * The condition for the while, ie. a call to MoveNext. - */ -private class TranslatedForeachWhileCondition extends TranslatedCompilerGeneratedValueCondition, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachWhileCondition() { this = TTranslatedCompilerGeneratedElement(generatedBy, 7) } - - override TranslatedCompilerGeneratedCall getValueExpr() { - exists(TranslatedForeachMoveNext mn | - mn.getAst() = generatedBy and - result = mn - ) - } - - override Instruction valueExprResult() { result = this.getValueExpr().getResult() } -} - -/** - * Class that represents that translation of the declaration that happens before the `try ... finally` block (the - * declaration of the `temporary` enumerator variable) - */ -private class TranslatedForeachEnumerator extends TranslatedCompilerGeneratedDeclaration, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ForeachEnumTempVar() and - type = getTypeForPRValue(this.getInitialization().getCallResultType()) - } - - override IRTempVariable getIRVariable() { - result = getIRTempVariable(generatedBy, ForeachEnumTempVar()) - } - - override TranslatedCompilerGeneratedCall getInitialization() { - exists(TranslatedForeachGetEnumerator ge | - ge.getAst() = generatedBy and - result = ge - ) - } - - override Instruction getInitializationResult() { result = this.getInitialization().getResult() } -} - -/** - * Class that represents that translation of the declaration that's happening inside the body of the while. - */ -private class TranslatedForeachIterVar extends TranslatedCompilerGeneratedDeclaration, - TTranslatedCompilerGeneratedElement -{ - override ForeachStmt generatedBy; - - TranslatedForeachIterVar() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = InitializerVariableAddressTag() and - result = this.getIRVariable() - } - - override IRVariable getIRVariable() { - result = getIRUserVariable(this.getFunction(), generatedBy.getAVariable()) - } - - override TranslatedCompilerGeneratedCall getInitialization() { - exists(TranslatedForeachCurrent crtProp | - crtProp.getAst() = generatedBy and - result = crtProp - ) - } - - override Instruction getInitializationResult() { result = this.getInitialization().getResult() } -} - -/** - * Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier - * for the call to `MoveNext`. - */ -private class TranslatedMoveNextEnumAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override ForeachStmt generatedBy; - - TranslatedMoveNextEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 10) } - - override Type getResultType() { result instanceof BoolType } - - override Type getVariableType() { - exists(TranslatedForeachGetEnumerator ge | - ge.getAst() = generatedBy and - result = ge.getCallResultType() - ) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ForeachEnumTempVar() and - type = getTypeForPRValue(this.getVariableType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(ForeachEnumTempVar()) - } - - override predicate needsLoad() { any() } -} - -/** - * Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier - * for the call to the getter of the property `Current`. - */ -private class TranslatedForeachCurrentEnumAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override ForeachStmt generatedBy; - - TranslatedForeachCurrentEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 11) } - - override Type getResultType() { result instanceof BoolType } - - override Type getVariableType() { - exists(TranslatedForeachGetEnumerator ge | - ge.getAst() = generatedBy and - result = ge.getCallResultType() - ) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ForeachEnumTempVar() and - type = getTypeForPRValue(this.getVariableType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(ForeachEnumTempVar()) - } - - override predicate needsLoad() { any() } -} - -/** - * Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier - * for the call to `Dispose`. - */ -private class TranslatedForeachDisposeEnumAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override ForeachStmt generatedBy; - - TranslatedForeachDisposeEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 12) } - - override Type getResultType() { result instanceof BoolType } - - override Type getVariableType() { - exists(TranslatedForeachGetEnumerator ge | - ge.getAst() = generatedBy and - result = ge.getCallResultType() - ) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = ForeachEnumTempVar() and - type = getTypeForPRValue(this.getVariableType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(ForeachEnumTempVar()) - } - - override predicate needsLoad() { any() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll deleted file mode 100644 index 40ca922b325..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll +++ /dev/null @@ -1,426 +0,0 @@ -/** - * File that provides the desugaring of a `lock` stmt. - * The statement: - * ```csharp - * lock (anExpr) ... - * ``` - * gets desugared to: - * ```csharp - * SomeRefType lockedVar = anExpr; - * bool __lockWasTaken = false; - * try { - * System.Threading.Monitor.Enter(lockedVar, ref __lockWasTaken); - * ... - * } - * finally { - * if (__lockWasTaken) System.Threading.Monitor.Exit(lockedVar); - * } - * ``` - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.TempVariableTag -private import experimental.ir.implementation.raw.internal.TranslatedExpr -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedStmt -private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase -private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.internal.IRCSharpLanguage as Language -private import Common -private import internal.TranslatedCompilerGeneratedStmt -private import internal.TranslatedCompilerGeneratedCall -private import internal.TranslatedCompilerGeneratedDeclaration -private import internal.TranslatedCompilerGeneratedCondition -private import internal.TranslatedCompilerGeneratedElement -private import internal.TranslatedCompilerGeneratedExpr - -/** - * Module that exposes the functions needed for the translation of the `lock` stmt. - */ -module LockElements { - TranslatedLockedVarDecl getLockedVarDecl(LockStmt generatedBy) { result.getAst() = generatedBy } - - TranslatedLockTry getTry(LockStmt generatedBy) { result.getAst() = generatedBy } - - TranslatedLockWasTakenDecl getLockWasTakenDecl(LockStmt generatedBy) { - result.getAst() = generatedBy - } - - int noGeneratedElements() { result = 14 } -} - -/** - * The translation of the `try` stmt. - */ -private class TranslatedLockTry extends TranslatedCompilerGeneratedTry, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedLockTry() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) } - - override TranslatedElement getFinally() { - exists(TranslatedLockFinally fin | - fin.getAst() = generatedBy and - result = fin - ) - } - - override TranslatedElement getBody() { - exists(TranslatedLockTryBody ltb | - ltb.getAst() = generatedBy and - result = ltb - ) - } -} - -/** - * The translation of the `lock` stmt's body. - */ -private class TranslatedLockTryBody extends TranslatedCompilerGeneratedBlock, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedLockTryBody() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) } - - override TranslatedElement getStmt(int index) { - index = 0 and - exists(TranslatedMonitorEnter me | - me.getAst() = generatedBy and - result = me - ) - or - index = 1 and - result = getTranslatedStmt(generatedBy.getBlock()) - } -} - -/** - * The translation of the finally block. - */ -private class TranslatedLockFinally extends TranslatedCompilerGeneratedBlock, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedLockFinally() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) } - - override TranslatedElement getStmt(int index) { - index = 0 and - exists(TranslatedFinallyIf fif | - fif.getAst() = generatedBy and - result = fif - ) - } -} - -/** - * The translation of the call to dispose (inside the finally block) - */ -private class TranslatedMonitorExit extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedMonitorExit() { this = TTranslatedCompilerGeneratedElement(generatedBy, 3) } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - exists(Callable exit | - exit.hasFullyQualifiedName("System.Threading.Monitor", "Exit") and - result = exit - ) - } - - final override Type getCallResultType() { result instanceof VoidType } - - override TranslatedExprBase getArgument(int id) { - id = 0 and - exists(TranslatedMonitorExitVarAcc var | - var.getAst() = generatedBy and - result = var - ) - } - - override TranslatedExprBase getQualifier() { none() } - - override Instruction getQualifierResult() { none() } -} - -/** - * The translation of the call to dispose (inside the finally block) - */ -private class TranslatedMonitorEnter extends TranslatedCompilerGeneratedCall, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedMonitorEnter() { this = TTranslatedCompilerGeneratedElement(generatedBy, 4) } - - override Callable getInstructionFunction(InstructionTag tag) { - tag = CallTargetTag() and - exists(Callable dispose | - dispose.hasFullyQualifiedName("System.Threading.Monitor", "Enter") and - result = dispose - ) - } - - final override Type getCallResultType() { result instanceof VoidType } - - override TranslatedExprBase getArgument(int id) { - id = 0 and - exists(TranslatedMonitorEnterVarAcc var | - var.getAst() = generatedBy and - result = var - ) - or - id = 1 and - exists(TranslatedLockWasTakenRefArg refArg | - refArg.getAst() = generatedBy and - result = refArg - ) - } - - override TranslatedExprBase getQualifier() { none() } - - override Instruction getQualifierResult() { none() } -} - -/** - * The translation of the condition of the `if` present in the `finally` clause. - */ -private class TranslatedIfCondition extends TranslatedCompilerGeneratedValueCondition, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedIfCondition() { this = TTranslatedCompilerGeneratedElement(generatedBy, 5) } - - override TranslatedCompilerGeneratedExpr getValueExpr() { - exists(TranslatedLockWasTakenCondVarAcc condVar | - condVar.getAst() = generatedBy and - result = condVar - ) - } - - override Instruction valueExprResult() { result = this.getValueExpr().getResult() } -} - -/** - * The translation of the `if` stmt present in the `finally` clause. - */ -private class TranslatedFinallyIf extends TranslatedCompilerGeneratedIfStmt, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedFinallyIf() { this = TTranslatedCompilerGeneratedElement(generatedBy, 6) } - - override TranslatedCompilerGeneratedValueCondition getCondition() { - exists(TranslatedIfCondition cond | - cond.getAst() = generatedBy and - result = cond - ) - } - - override TranslatedCompilerGeneratedCall getThen() { - exists(TranslatedMonitorExit me | - me.getAst() = generatedBy and - result = me - ) - } - - override TranslatedCompilerGeneratedCall getElse() { none() } -} - -/** - * Represents the translation of the constant that is part of the initialization for the - * bool temp variable. - */ -private class TranslatedWasTakenConst extends TranslatedCompilerGeneratedConstant, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedWasTakenConst() { this = TTranslatedCompilerGeneratedElement(generatedBy, 7) } - - override string getInstructionConstantValue(InstructionTag tag) { - tag = OnlyInstructionTag() and - result = "false" - } - - override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } - - override Type getResultType() { result instanceof BoolType } -} - -/** - * Represents the translation of the `lockWasTaken` temp variable declaration. - */ -private class TranslatedLockWasTakenDecl extends TranslatedCompilerGeneratedDeclaration, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedLockWasTakenDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockWasTakenTemp() and - type = getBoolType() - } - - override IRTempVariable getIRVariable() { - result = getIRTempVariable(generatedBy, LockWasTakenTemp()) - } - - override TranslatedCompilerGeneratedExpr getInitialization() { - exists(TranslatedWasTakenConst const | - const.getAst() = generatedBy and - result = const - ) - } - - override Type getVarType() { result = this.getInitialization().getResultType() } - - override Instruction getInitializationResult() { result = this.getInitialization().getResult() } -} - -/** - * Represents the translation of the declaration of the temp variable that is initialized to the - * expression being locked. - */ -private class TranslatedLockedVarDecl extends TranslatedCompilerGeneratedDeclaration, - TTranslatedCompilerGeneratedElement -{ - override LockStmt generatedBy; - - TranslatedLockedVarDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockedVarTemp() and - type = getTypeForPRValue(generatedBy.getExpr().getType()) - } - - override IRTempVariable getIRVariable() { - result = getIRTempVariable(generatedBy, LockedVarTemp()) - } - - override TranslatedExprBase getInitialization() { - result = getTranslatedExpr(generatedBy.getExpr()) - } - - override Type getVarType() { result = generatedBy.getExpr().getType() } - - override Instruction getInitializationResult() { result = this.getInitialization().getResult() } -} - -/** - * Represents the translation of access to the temp variable that is initialized to the - * expression being locked. - * Used as an argument for the `MonitorEnter` call. - */ -private class TranslatedMonitorEnterVarAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override LockStmt generatedBy; - - TranslatedMonitorEnterVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 10) } - - override Type getResultType() { result = generatedBy.getExpr().getType() } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockedVarTemp() and - type = getTypeForPRValue(this.getResultType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(LockedVarTemp()) - } - - override predicate needsLoad() { any() } -} - -/** - * Represents the translation of access to the temp variable that is initialized to the - * expression being locked. - * Used as an argument for the `MonitorExit` call. - */ -private class TranslatedMonitorExitVarAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override LockStmt generatedBy; - - TranslatedMonitorExitVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 11) } - - override Type getResultType() { result = generatedBy.getExpr().getType() } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(LockedVarTemp()) - } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockedVarTemp() and - type = getTypeForPRValue(this.getResultType()) - } - - override predicate needsLoad() { any() } -} - -/** - * Represents that translation of access to the temporary bool variable. - * Used as an argument for the `MonitorEnter` call. - */ -private class TranslatedLockWasTakenCondVarAcc extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override LockStmt generatedBy; - - TranslatedLockWasTakenCondVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 12) } - - override Type getResultType() { result instanceof BoolType } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockWasTakenTemp() and - type = getTypeForPRValue(this.getResultType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(LockWasTakenTemp()) - } - - override predicate needsLoad() { any() } -} - -/** - * That represents that translation of access to the temporary bool variable. Its value is used - * as the `if` condition in the finally clause. - */ -private class TranslatedLockWasTakenRefArg extends TTranslatedCompilerGeneratedElement, - TranslatedCompilerGeneratedVariableAccess -{ - override LockStmt generatedBy; - - TranslatedLockWasTakenRefArg() { this = TTranslatedCompilerGeneratedElement(generatedBy, 13) } - - override Type getResultType() { result instanceof BoolType } - - override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { - tag = LockWasTakenTemp() and - type = getTypeForPRValue(this.getResultType()) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = AddressTag() and - result = this.getTempVariable(LockWasTakenTemp()) - } - - override predicate needsLoad() { none() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll deleted file mode 100644 index 8b137891791..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll +++ /dev/null @@ -1 +0,0 @@ - diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll deleted file mode 100644 index d1834f90c1c..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Contains an abstract class that is the super class of the classes that deal with compiler generated calls. - */ - -import csharp -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedFunction -private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase -private import TranslatedCompilerGeneratedElement -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, - TranslatedCompilerGeneratedElement -{ - final override string toString() { - result = "compiler generated call (" + generatedBy.toString() + ")" - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll deleted file mode 100644 index 57fdc12121c..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Contains an abstract class that is the super class of the classes that deal with compiler generated conditions. - */ - -import csharp -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase -private import TranslatedCompilerGeneratedElement -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement, - ValueConditionBase -{ - final override string toString() { - result = "compiler generated condition (" + generatedBy.toString() + ")" - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll deleted file mode 100644 index 2a3ace143c8..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Contains an abstract class, which is the super class of all the classes that represent compiler - * generated declarations. It extends the Base for declarations by incorporating a `Store` instruction, since - * we treat the initialization as part of the declaration for compiler generated declarations. - */ - -import csharp -private import experimental.ir.implementation.Opcode -private import experimental.ir.implementation.internal.OperandTag -private import experimental.ir.implementation.raw.internal.InstructionTag -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.implementation.raw.internal.TranslatedFunction -private import experimental.ir.implementation.raw.internal.common.TranslatedDeclarationBase -private import TranslatedCompilerGeneratedElement -private import experimental.ir.internal.CSharpType -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, - TranslatedCompilerGeneratedElement -{ - final override string toString() { - result = "compiler generated declaration (" + generatedBy.toString() + ")" - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitialization() and result = this.getInstruction(InitializerStoreTag()) - } - - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType) - or - // we can reuse the initializer store tag - // since compiler generated declarations - // do not have the `Uninitialized` instruction - tag = InitializerStoreTag() and - opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(this.getVarType()) - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - result = LocalVariableDeclarationBase.super.getInstructionSuccessor(tag, kind) - or - tag = InitializerStoreTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = LocalVariableDeclarationBase.super.getInstructionOperand(tag, operandTag) - or - tag = InitializerStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof StoreValueOperandTag and - result = this.getInitializationResult() - ) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - tag = InitializerVariableAddressTag() and - result = this.getIRVariable() - } - - // A compiler generated declaration does not have an associated `LocalVariable` - // element - override LocalVariable getDeclVar() { none() } - - override Type getVarType() { result = this.getIRVariable().getType() } - - /** - * Gets the IR variable that corresponds to the declaration. - */ - abstract IRVariable getIRVariable(); - - /** - * Gets result (instruction) of the initialization expression. - */ - abstract Instruction getInitializationResult(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll deleted file mode 100644 index 2e5908b8194..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ /dev/null @@ -1,23 +0,0 @@ -/** - * The abstract super class of every `TranslatedCompilerX` class. It has one member field, `generatedBy`, - * which represents the element that generated the compiler generated element. - */ - -private import experimental.ir.implementation.raw.internal.TranslatedElement -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, - TTranslatedCompilerGeneratedElement -{ - // The element that generates generated the compiler element can - // only be a stmt or an expr - ControlFlowElement generatedBy; - - override string toString() { - result = "compiler generated element (" + generatedBy.toString() + ")" - } - - final override Callable getFunction() { result = generatedBy.getEnclosingCallable() } - - final override Language::AST getAst() { result = generatedBy } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll deleted file mode 100644 index 3c5a60cf812..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Contains an abstract class, which is the super class of all the classes that represent compiler - * generated expressions. - */ - -import csharp -private import TranslatedCompilerGeneratedElement -private import experimental.ir.implementation.raw.Instruction -private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement, - TranslatedExprBase -{ - override string toString() { result = "compiler generated expr (" + generatedBy.toString() + ")" } - - abstract Type getResultType(); -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll deleted file mode 100644 index 70955e02c9b..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Contains an abstract class, which is the super class of all the classes that represent compiler - * generated statements. - */ - -import csharp -private import TranslatedCompilerGeneratedElement -private import experimental.ir.internal.IRCSharpLanguage as Language - -abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement { - final override string toString() { - result = "compiler generated stmt (" + generatedBy.toString() + ")" - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll deleted file mode 100644 index cddc3e23d7e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll +++ /dev/null @@ -1,22 +0,0 @@ -private import DominanceInternal - -predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) = - idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block) - -predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) { - blockImmediatelyDominates+(dominator, block) -} - -predicate blockDominates(Graph::Block dominator, Graph::Block block) { - blockStrictlyDominates(dominator, block) or dominator = block -} - -Graph::Block getDominanceFrontier(Graph::Block dominator) { - Graph::blockSuccessor(dominator, result) and - not blockImmediatelyDominates(dominator, result) - or - exists(Graph::Block prev | result = getDominanceFrontier(prev) | - blockImmediatelyDominates(dominator, prev) and - not blockImmediatelyDominates(dominator, result) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll deleted file mode 100644 index aaa4cc7bd53..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll +++ /dev/null @@ -1,7 +0,0 @@ -private import ReachableBlock as Reachability - -module Graph { - import Reachability::Graph - - class Block = Reachability::ReachableBlock; -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll deleted file mode 100644 index f26565bc278..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll +++ /dev/null @@ -1,22 +0,0 @@ -private import DominanceInternal -private import ReachableBlockInternal -private import Dominance -import IR - -private class DominancePropertyProvider extends IRPropertyProvider { - override string getBlockProperty(IRBlock block, string key) { - exists(IRBlock dominator | - blockImmediatelyDominates(dominator, block) and - key = "ImmediateDominator" and - result = "Block " + dominator.getDisplayIndex().toString() - ) - or - key = "DominanceFrontier" and - result = - strictconcat(IRBlock frontierBlock | - frontierBlock = getDominanceFrontier(block) - | - frontierBlock.getDisplayIndex().toString(), ", " order by frontierBlock.getDisplayIndex() - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll deleted file mode 100644 index 6befad72336..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll +++ /dev/null @@ -1,17 +0,0 @@ -private import ReachableBlockInternal -private import ReachableBlock -import IR - -private class ReachableBlockPropertyProvider extends IRPropertyProvider { - override string getBlockProperty(IRBlock block, string key) { - not block instanceof ReachableBlock and - key = "Unreachable" and - result = "true" - or - exists(EdgeKind kind | - isInfeasibleEdge(block, kind) and - key = "Infeasible(" + kind.toString() + ")" and - result = "true" - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll deleted file mode 100644 index 25a53bbefe8..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll +++ /dev/null @@ -1,53 +0,0 @@ -private import ReachableBlockInternal -private import IR -private import ConstantAnalysis - -predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) { - exists(int conditionValue | - conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and - if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge - ) -} - -pragma[noinline] -predicate isInfeasibleEdge(IRBlockBase block, EdgeKind kind) { - isInfeasibleInstructionSuccessor(block.getLastInstruction(), kind) -} - -private IRBlock getAFeasiblePredecessorBlock(IRBlock successor) { - exists(EdgeKind kind | - result.getSuccessor(kind) = successor and - not isInfeasibleEdge(result, kind) - ) -} - -private predicate isBlockReachable(IRBlock block) { - exists(IRFunction f | getAFeasiblePredecessorBlock*(block) = f.getEntryBlock()) -} - -/** - * An IR block that is reachable from the entry block of the function, considering only feasible - * edges. - */ -class ReachableBlock extends IRBlockBase { - ReachableBlock() { isBlockReachable(this) } - - final ReachableBlock getAFeasiblePredecessor() { result = getAFeasiblePredecessorBlock(this) } - - final ReachableBlock getAFeasibleSuccessor() { this = getAFeasiblePredecessorBlock(result) } -} - -/** - * An instruction that is contained in a reachable block. - */ -class ReachableInstruction extends Instruction { - ReachableInstruction() { this.getBlock() instanceof ReachableBlock } -} - -module Graph { - predicate isEntryBlock(ReachableBlock block) { exists(IRFunction f | block = f.getEntryBlock()) } - - predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) { - succ = pred.getAFeasibleSuccessor() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index 93131e2abb5..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.implementation.raw.IR as IR -import experimental.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll deleted file mode 100644 index 79873d8366e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Provides classes that describe the Intermediate Representation (IR) of the program. - * - * The IR is a representation of the semantics of the program, with very little dependence on the - * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, - * and `++i` all have the same semantic effect, but appear in the AST as three different types of - * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental - * operations similar to: - * - * ``` - * r1(int*) = VariableAddress[i] // Compute the address of variable `i` - * r2(int) = Load &:r1, m0 // Load the value of `i` - * r3(int) = Constant[1] // An integer constant with the value `1` - * r4(int) = Add r2, r3 // Add `1` to the value of `i` - * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` - * ``` - * - * This allows IR-based analysis to focus on the fundamental operations, rather than having to be - * concerned with the various ways of expressing those operations in source code. - * - * The key classes in the IR are: - * - * - `IRFunction` - Contains the IR for an entire function definition, including all of that - * function's `Instruction`s, `IRBlock`s, and `IRVariables`. - * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be - * performed, the operands that produce the inputs to that operation, and the type of the result - * of the operation. Control flows from an `Instruction` to one of a set of successor - * `Instruction`s. - * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly - * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has - * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` - * that produces its value (its "definition"). - * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is - * created for each variable directly accessed by the function. In addition, `IRVariable`s are - * created to represent certain temporary storage locations that do not have explicitly declared - * variables in the source code, such as the return value of the function. - * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a - * sequence of instructions such that control flow can only enter the block at the first - * instruction, and can only leave the block from the last instruction. - * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` - * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all - * be represented as the `IRType` `uint4`, a four-byte unsigned integer. - */ - -import IRFunction -import Instruction -import IRBlock -import IRVariable -import Operand -private import internal.IRImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind - -private newtype TIRPropertyProvider = MkIRPropertyProvider() - -/** - * A class that provides additional properties to be dumped for IR instructions and blocks when using - * the PrintIR module. Libraries that compute additional facts about IR elements can extend the - * single instance of this class to specify the additional properties computed by the library. - */ -class IRPropertyProvider extends TIRPropertyProvider { - /** Gets a textual representation of this element. */ - string toString() { result = "IRPropertyProvider" } - - /** - * Gets the value of the property named `key` for the specified instruction. - */ - string getInstructionProperty(Instruction instruction, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified block. - */ - string getBlockProperty(IRBlock block, string key) { none() } - - /** - * Gets the value of the property named `key` for the specified operand. - */ - string getOperandProperty(Operand operand, string key) { none() } - - /** - * Holds if the instruction `instr` should be included when printing - * the IR instructions. - */ - predicate shouldPrintInstruction(Instruction instr) { any() } - - /** - * Holds if the operand `operand` should be included when printing the an - * instruction's operand list. - */ - predicate shouldPrintOperand(Operand operand) { any() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll deleted file mode 100644 index 50395db47e7..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ /dev/null @@ -1,356 +0,0 @@ -/** - * Provides classes describing basic blocks in the IR of a function. - */ - -private import internal.IRInternal -import Instruction -private import internal.IRBlockImports as Imports -import Imports::EdgeKind -private import Cached - -/** - * Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the - * sort keys of the block (derived from its first instruction) - */ -pragma[nomagic] -private predicate blockSortKeys( - IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2 -) { - block.getEnclosingIRFunction() = func and - block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and - // Ensure that the block containing `EnterFunction` always comes first. - if block.getFirstInstruction() instanceof EnterFunctionInstruction - then sortOverride = 0 - else sortOverride = 1 -} - -/** - * A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only - * incoming edges at the beginning of the sequence and the only outgoing edges at the end of the - * sequence. - * - * This class does not contain any members that query the predecessor or successor edges of the - * block. This allows different classes that extend `IRBlockBase` to expose different subsets of - * edges (e.g. ignoring unreachable edges). - * - * Most consumers should use the class `IRBlock`. - */ -class IRBlockBase extends TIRBlock { - /** Gets a textual representation of this block. */ - final string toString() { result = getFirstInstruction(this).toString() } - - /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } - - /** - * INTERNAL: Do not use. - * - * Gets the zero-based index of the block within its function. - * - * This predicate is used by debugging and printing code only. - */ - int getDisplayIndex() { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) - ) and - exists(IRFunction func | - this = - rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2) - | - funcBlock order by sortOverride, sortKey1, sortKey2 - ) - ) - } - - /** - * Gets the `index`th non-`Phi` instruction in this block. - */ - final Instruction getInstruction(int index) { result = getInstruction(this, index) } - - /** - * Get the `Phi` instructions that appear at the start of this block. - */ - final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() - } - - /** - * Gets an instruction in this block. This includes `Phi` instructions. - */ - final Instruction getAnInstruction() { - result = this.getInstruction(_) or - result = this.getAPhiInstruction() - } - - /** - * Gets the first non-`Phi` instruction in this block. - */ - final Instruction getFirstInstruction() { result = getFirstInstruction(this) } - - /** - * Gets the last instruction in this block. - */ - final Instruction getLastInstruction() { - result = this.getInstruction(this.getInstructionCount() - 1) - } - - /** - * Gets the number of non-`Phi` instructions in this block. - */ - final int getInstructionCount() { result = getInstructionCount(this) } - - /** - * Gets the `IRFunction` that contains this block. - */ - final IRFunction getEnclosingIRFunction() { - result = getFirstInstruction(this).getEnclosingIRFunction() - } - - /** - * Gets the `Function` that contains this block. - */ - final Language::Declaration getEnclosingFunction() { - result = getFirstInstruction(this).getEnclosingFunction() - } -} - -/** - * A basic block with additional information about its predecessor and successor edges. Each edge - * corresponds to the control flow between the last instruction of one block and the first - * instruction of another block. - */ -class IRBlock extends IRBlockBase { - /** - * Gets a block to which control flows directly from this block. - */ - final IRBlock getASuccessor() { blockSuccessor(this, result) } - - /** - * Gets a block from which control flows directly to this block. - */ - final IRBlock getAPredecessor() { blockSuccessor(result, this) } - - /** - * Gets the block to which control flows directly from this block along an edge of kind `kind`. - */ - final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } - - /** - * Gets the block to which control flows directly from this block along a back edge of kind - * `kind`. - */ - final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } - - /** - * Holds if this block immediately dominates `block`. - * - * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` - * is a direct successor of block `A`. - */ - final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } - - /** - * Holds if this block strictly dominates `block`. - * - * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` - * are not the same block. - */ - final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } - - /** - * Holds if this block dominates `block`. - * - * Block `A` dominates block `B` if any control flow path from the entry block of the function to - * block `B` must pass through block `A`. A block always dominates itself. - */ - final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } - - /** - * Gets a block on the dominance frontier of this block. - * - * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not - * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. - */ - pragma[noinline] - final IRBlock dominanceFrontier() { - this.getASuccessor() = result and - not this.immediatelyDominates(result) - or - exists(IRBlock prev | result = prev.dominanceFrontier() | - this.immediatelyDominates(prev) and - not this.immediatelyDominates(result) - ) - } - - /** - * Holds if this block immediately post-dominates `block`. - * - * Block `A` immediate post-dominates block `B` if block `A` strictly post-dominates block `B` and - * block `B` is a direct successor of block `A`. - */ - final predicate immediatelyPostDominates(IRBlock block) { - blockImmediatelyPostDominates(this, block) - } - - /** - * Holds if this block strictly post-dominates `block`. - * - * Block `A` strictly post-dominates block `B` if block `A` post-dominates block `B` and blocks `A` - * and `B` are not the same block. - */ - final predicate strictlyPostDominates(IRBlock block) { - blockImmediatelyPostDominates+(this, block) - } - - /** - * Holds if this block is a post-dominator of `block`. - * - * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the - * function must pass through block `A`. A block always post-dominates itself. - */ - final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } - - /** - * Gets a block on the post-dominance frontier of this block. - * - * The post-dominance frontier of block `A` is the set of blocks `B` such that block `A` does not - * post-dominate block `B`, but block `A` does post-dominate an immediate successor of block `B`. - */ - pragma[noinline] - final IRBlock postDominanceFrontier() { - this.getAPredecessor() = result and - not this.immediatelyPostDominates(result) - or - exists(IRBlock prev | result = prev.postDominanceFrontier() | - this.immediatelyPostDominates(prev) and - not this.immediatelyPostDominates(result) - ) - } - - /** - * Holds if this block is reachable from the entry block of its function. - */ - final predicate isReachableFromFunctionEntry() { - this = this.getEnclosingIRFunction().getEntryBlock() or - this.getAPredecessor().isReachableFromFunctionEntry() - } -} - -private predicate startsBasicBlock(Instruction instr) { - not instr instanceof PhiInstruction and - not adjacentInBlock(_, instr) -} - -/** Holds if `i2` follows `i1` in a `IRBlock`. */ -private predicate adjacentInBlock(Instruction i1, Instruction i2) { - // - i2 must be the only successor of i1 - i2 = unique(Instruction i | i = i1.getASuccessor()) and - // - i1 must be the only predecessor of i2 - i1 = unique(Instruction i | i.getASuccessor() = i2) and - // - The edge between the two must be a GotoEdge. We just check that one - // exists since we've already checked that it's unique. - exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and - // - The edge must not be a back edge. This means we get the same back edges - // in the basic-block graph as we do in the raw CFG. - not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) - // This predicate could be simplified to remove one of the `unique`s if we - // were willing to rely on the CFG being well-formed and thus never having - // more than one successor to an instruction that has a `GotoEdge` out of it. -} - -private predicate isEntryBlock(TIRBlock block) { - block = MkIRBlock(any(EnterFunctionInstruction enter)) -} - -cached -private module Cached { - cached - newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ - private Instruction getInstructionFromFirst(Instruction first, int index) = - shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) - - /** Holds if `i` is the `index`th instruction in `block`. */ - cached - Instruction getInstruction(TIRBlock block, int index) { - result = getInstructionFromFirst(getFirstInstruction(block), index) - } - - cached - int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) } - - cached - predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - exists(Instruction predLast, Instruction succFirst | - predLast = getInstruction(pred, getInstructionCount(pred) - 1) and - succFirst = predLast.getSuccessor(kind) and - succ = MkIRBlock(succFirst) - ) - } - - pragma[noinline] - private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 } - - pragma[noopt] - cached - predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - backEdgeSuccessorRaw(pred, succ, kind) - or - // See the QLDoc on `backEdgeSuccessorRaw`. - exists(TIRBlock pred2 | - // Joining with `blockIdentity` is a performance trick to get - // `forwardEdgeRaw` on the RHS of a join, where it's fast. - blockIdentity(pred, pred2) and - forwardEdgeRaw+(pred, pred2) - ) and - blockSuccessor(pred, succ, kind) - } - - /** - * Holds if there is an edge from `pred` to `succ` that is not a back edge. - */ - private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) { - exists(EdgeKind kind | - blockSuccessor(pred, succ, kind) and - not backEdgeSuccessorRaw(pred, succ, kind) - ) - } - - /** - * Holds if the `kind`-edge from `pred` to `succ` is a back edge according to - * `Construction`. - * - * There could be loops of non-back-edges if there is a flaw in the IR - * construction or back-edge detection, and this could cause non-termination - * of subsequent analysis. To prevent that, a subsequent predicate further - * classifies all edges as back edges if they are involved in a loop of - * non-back-edges. - */ - private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) { - exists(Instruction predLast, Instruction succFirst | - predLast = getInstruction(pred, getInstructionCount(pred) - 1) and - succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and - succ = MkIRBlock(succFirst) - ) - } - - cached - predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) } - - cached - predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) = - idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) -} - -private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } - -private predicate blockFunctionExit(IRBlock exit) { - exit.getLastInstruction() instanceof ExitFunctionInstruction -} - -private predicate blockPredecessor(IRBlock src, IRBlock pred) { src.getAPredecessor() = pred } - -private predicate blockImmediatelyPostDominates(IRBlock postDominator, IRBlock block) = - idominance(blockFunctionExit/1, blockPredecessor/2)(_, postDominator, block) diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql deleted file mode 100644 index 909a7a5fc24..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name SSA IR Consistency Check - * @description Performs consistency checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ssa-ir-consistency-check - */ - -import IRConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll deleted file mode 100644 index edc785dfabe..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll +++ /dev/null @@ -1,549 +0,0 @@ -private import IR -import InstructionConsistency // module is below -import IRTypeConsistency // module is in IRType.qll -import internal.IRConsistencyImports - -module InstructionConsistency { - private import internal.InstructionImports as Imports - private import Imports::OperandTag - private import Imports::Overlap - private import internal.IRInternal - - private newtype TOptionalIRFunction = - TPresentIRFunction(IRFunction irFunc) or - TMissingIRFunction() - - /** - * An `IRFunction` that might not exist. This is used so that we can produce consistency failures - * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. - */ - abstract private class OptionalIRFunction extends TOptionalIRFunction { - abstract string toString(); - - abstract Language::Location getLocation(); - } - - class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { - private IRFunction irFunc; - - PresentIRFunction() { this = TPresentIRFunction(irFunc) } - - override string toString() { - result = concat(LanguageDebug::getIdentityString(irFunc.getFunction()), "; ") - } - - override Language::Location getLocation() { - // To avoid an overwhelming number of results when the extractor merges functions with the - // same name, just pick a single location. - result = - min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) - } - - IRFunction getIRFunction() { result = irFunc } - } - - private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { - override string toString() { result = "" } - - override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } - } - - private OptionalIRFunction getInstructionIRFunction(Instruction instr) { - result = TPresentIRFunction(instr.getEnclosingIRFunction()) - or - not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - pragma[inline] - private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { - result = getInstructionIRFunction(instr) and - irFuncText = result.toString() - } - - private OptionalIRFunction getOperandIRFunction(Operand operand) { - result = TPresentIRFunction(operand.getEnclosingIRFunction()) - or - not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - pragma[inline] - private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { - result = getOperandIRFunction(operand) and - irFuncText = result.toString() - } - - private OptionalIRFunction getBlockIRFunction(IRBlock block) { - result = TPresentIRFunction(block.getEnclosingIRFunction()) - or - not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() - } - - /** - * Holds if instruction `instr` is missing an expected operand with tag `tag`. - */ - query predicate missingOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag | - instr.getOpcode().hasOperand(tag) and - not exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - message = - "Instruction '" + instr.getOpcode().toString() + - "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if instruction `instr` has an unexpected operand with tag `tag`. - */ - query predicate unexpectedOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag | - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and - message = - "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + - "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if instruction `instr` has multiple operands with tag `tag`. - */ - query predicate duplicateOperand( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(OperandTag tag, int operandCount | - operandCount = - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - operandCount > 1 and - message = - "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if `Phi` instruction `instr` is missing an operand corresponding to - * the predecessor block `pred`. - */ - query predicate missingPhiOperand( - PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRBlock pred | - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred - ) and - message = - "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + - pred.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - query predicate missingOperandType( - Operand operand, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Instruction use | - not exists(operand.getType()) and - use = operand.getUse() and - message = - "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' is missing a type in function '$@'." and - irFunc = getOperandIRFunction(operand, irFuncText) - ) - } - - query predicate duplicateChiOperand( - ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText - ) { - chi.getTotal() = chi.getPartial() and - message = - "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function '$@'." and - irFunc = getInstructionIRFunction(chi, irFuncText) - } - - query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(instr.getPrimaryInstruction()) and - message = - "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if an instruction, other than `ExitFunction`, has no successors. - */ - query predicate instructionWithoutSuccessor( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(instr.getASuccessor()) and - not instr instanceof ExitFunctionInstruction and - // Phi instructions aren't linked into the instruction-level flow graph. - not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction and - message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if there are multiple edges of the same kind from `source`. - */ - query predicate ambiguousSuccessors( - Instruction source, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(EdgeKind kind, int n | - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - message = - "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + - kind.toString() + "' in function '$@'." and - irFunc = getInstructionIRFunction(source, irFuncText) - ) - } - - /** - * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function - * contains no element that can cause loops. - */ - query predicate unexplainedLoop( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Language::Function f | - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) and - message = - "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if a `Phi` instruction is present in a block with fewer than two - * predecessors. - */ - query predicate unnecessaryPhiInstruction( - PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int n | - n = count(instr.getBlock().getAPredecessor()) and - n < 2 and - message = - "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + - " predecessors in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if a memory operand is connected to a definition with an unmodeled result. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - def = operand.getAnyDef() and - not def.isResultModeled() and - message = - "Memory operand definition on instruction '" + instr.toString() + - "' has unmodeled result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if operand `operand` consumes a value that was defined in - * a different function. - */ - query predicate operandAcrossFunctions( - Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, - OptionalIRFunction defIRFunc, string defIRFuncText - ) { - exists(Instruction useInstr, Instruction defInstr | - operand.getUse() = useInstr and - operand.getAnyDef() = defInstr and - useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and - defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and - useIRFunc != defIRFunc and - message = - "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + - "' in function '$@', but is defined on instruction '" + defInstr.toString() + - "' in function '$@'." - ) - } - - /** - * Holds if instruction `instr` is not in exactly one block. - */ - query predicate instructionWithoutUniqueBlock( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int blockCount | - blockCount = count(instr.getBlock()) and - blockCount != 1 and - message = - "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + - " blocks in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - private predicate forwardEdge(IRBlock b1, IRBlock b2) { - b1.getASuccessor() = b2 and - not b1.getBackEdgeSuccessor(_) = b2 - } - - /** - * Holds if `f` contains a loop in which no edge is a back edge. - * - * This check ensures we don't have too _few_ back edges. - */ - query predicate containsLoopOfForwardEdges(IRFunction f, string message) { - exists(IRBlock block | - forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f and - message = "Function contains a loop consisting of only forward edges." - ) - } - - /** - * Holds if `block` is reachable from its function entry point but would not - * be reachable by traversing only forward edges. This check is skipped for - * functions containing `goto` statements as the property does not generally - * hold there. - * - * This check ensures we don't have too _many_ back edges. - */ - query predicate lostReachability( - IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRFunction f, IRBlock entry | - entry = f.getEntryBlock() and - entry.getASuccessor+() = block and - not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) and - message = - "Block '" + block.toString() + - "' is not reachable by traversing only forward edges in function '$@'." and - irFunc = TPresentIRFunction(f) and - irFuncText = irFunc.toString() - ) - } - - /** - * Holds if the number of back edges differs between the `Instruction` graph - * and the `IRBlock` graph. - */ - query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { - exists(int fromInstr, int fromBlock | - fromInstr = - count(Instruction i1, Instruction i2 | - getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock and - message = - "The instruction graph for function '" + irFunc.toString() + "' contains " + - fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() - + " back edges." - ) - } - - /** - * 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, OptionalIRFunction irFunc, string irFuncText - ) { - exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - 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 - irFunc = getOperandIRFunction(useOperand, irFuncText) - ) - } - - query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - irFunc = getInstructionIRFunction(switchInstr, irFuncText) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - shouldBeConflated(instr) and - not instr.isResultConflated() and - message = - "Instruction '" + instr.toString() + - "' should be marked as having a conflated result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate wronglyMarkedAsConflated( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - instr.isResultConflated() and - not shouldBeConflated(instr) and - message = - "Instruction '" + instr.toString() + - "' should not be marked as having a conflated result in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - irFunc = getOperandIRFunction(useOperand, irFuncText) - ) - } - - query predicate nonUniqueEnclosingIRFunction( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(int irFuncCount | - irFuncCount = count(instr.getEnclosingIRFunction()) and - irFuncCount != 1 and - message = - "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + - " results for `getEnclosingIRFunction()` in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - ) - } - - /** - * Holds if the object address operand for the given `FieldAddress` instruction does not have an - * address type. - */ - query predicate fieldAddressOnNonPointer( - FieldAddressInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - not instr.getObjectAddressOperand().getIRType() instanceof IRAddressType and - message = - "FieldAddress instruction '" + instr.toString() + - "' has an object address operand that is not an address, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - /** - * Holds if the `this` argument operand for the given `Call` instruction does not have an address - * type. - */ - query predicate thisArgumentIsNonPointer( - CallInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(ThisArgumentOperand thisOperand | thisOperand = instr.getThisArgumentOperand() | - not thisOperand.getIRType() instanceof IRAddressType - ) and - message = - "Call instruction '" + instr.toString() + - "' has a `this` argument operand that is not an address, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } - - query predicate nonUniqueIRVariable( - Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText - ) { - exists(VariableInstruction vi, IRVariable v1, IRVariable v2 | - instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2 - ) and - message = - "Variable instruction '" + instr.toString() + - "' has multiple associated variables, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - or - instr.getOpcode() instanceof Opcode::VariableAddress and - not instr instanceof VariableInstruction and - message = - "Variable address instruction '" + instr.toString() + - "' has no associated variable, in function '$@'." and - irFunc = getInstructionIRFunction(instr, irFuncText) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll deleted file mode 100644 index 354ba41e3d1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Provides the class `IRFunction`, which represents the Intermediate Representation for the - * definition of a function. - */ - -private import internal.IRInternal -private import internal.IRFunctionImports as Imports -import Imports::IRFunctionBase -import Instruction - -/** - * The IR for a function. - */ -class IRFunction extends IRFunctionBase { - /** - * Gets the entry point for this function. - */ - pragma[noinline] - final EnterFunctionInstruction getEnterFunctionInstruction() { - result.getEnclosingIRFunction() = this - } - - /** - * Gets the exit point for this function. - */ - pragma[noinline] - final ExitFunctionInstruction getExitFunctionInstruction() { - result.getEnclosingIRFunction() = this - } - - /** - * Gets the single return instruction for this function. - */ - pragma[noinline] - final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this } - - /** - * Gets the variable used to hold the return value of this function. If this - * function does not return a value, this predicate does not hold. - */ - pragma[noinline] - final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this } - - /** - * Gets the block containing the entry point of this function. - */ - pragma[noinline] - final IRBlock getEntryBlock() { - result.getFirstInstruction() = this.getEnterFunctionInstruction() - } - - /** - * Gets all instructions in this function. - */ - final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this } - - /** - * Gets all blocks in this function. - */ - final IRBlock getABlock() { result.getEnclosingIRFunction() = this } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll deleted file mode 100644 index b31c7898ba7..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ /dev/null @@ -1,337 +0,0 @@ -/** - * Provides classes that represent variables accessed by the IR. - */ - -private import internal.IRInternal -import IRFunction -private import internal.IRVariableImports as Imports -import Imports::TempVariableTag -private import Imports::IRUtilities -private import Imports::TTempVariableTag -private import Imports::TIRVariable -private import Imports::IRType - -/** - * A variable referenced by the IR for a function. - * - * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated - * by the AST-to-IR translation (`IRTempVariable`). - */ -class IRVariable extends TIRVariable { - Language::Declaration func; - - IRVariable() { - this = TIRUserVariable(_, _, func) or - this = TIRTempVariable(func, _, _, _) or - this = TIRStringLiteral(func, _, _, _) or - this = TIRDynamicInitializationFlag(func, _, _) - } - - /** Gets a textual representation of this element. */ - string toString() { none() } - - /** - * Holds if this variable's value cannot be changed within a function. Currently used for string - * literals, but could also apply to `const` global and static variables. - */ - predicate isReadOnly() { none() } - - /** - * Gets the type of the variable. - */ - final Language::Type getType() { this.getLanguageType().hasType(result, false) } - - /** - * Gets the language-neutral type of the variable. - */ - final IRType getIRType() { result = this.getLanguageType().getIRType() } - - /** - * Gets the type of the variable. - */ - Language::LanguageType getLanguageType() { none() } - - /** - * Gets the AST node that declared this variable, or that introduced this - * variable as part of the AST-to-IR translation. - */ - Language::AST getAst() { none() } - - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - - /** - * Gets an identifier string for the variable. This identifier is unique - * within the function. - */ - string getUniqueId() { none() } - - /** - * Gets the source location of this variable. - */ - final Language::Location getLocation() { result = this.getAst().getLocation() } - - /** - * Gets the IR for the function that references this variable. - */ - final IRFunction getEnclosingIRFunction() { result.getFunction() = func } - - /** - * Gets the function that references this variable. - */ - final Language::Declaration getEnclosingFunction() { result = func } -} - -/** - * A user-declared variable referenced by the IR for a function. - */ -class IRUserVariable extends IRVariable, TIRUserVariable { - Language::Variable var; - Language::LanguageType type; - - IRUserVariable() { this = TIRUserVariable(var, type, func) } - - final override string toString() { result = this.getVariable().toString() } - - final override Language::AST getAst() { result = var } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - - final override string getUniqueId() { - result = this.getVariable().toString() + " " + this.getVariable().getLocation().toString() - } - - final override Language::LanguageType getLanguageType() { result = type } - - /** - * Gets the original user-declared variable. - */ - Language::Variable getVariable() { result = var } -} - -/** - * A variable (user-declared or temporary) that is allocated on the stack. This includes all - * parameters, non-static local variables, and temporary variables. - */ -class IRAutomaticVariable extends IRVariable { - IRAutomaticVariable() { - exists(Language::Variable var | - this = TIRUserVariable(var, _, func) and - Language::isVariableAutomatic(var) - ) - or - this = TIRTempVariable(func, _, _, _) - } -} - -/** - * A user-declared variable that is allocated on the stack. This includes all parameters and - * non-static local variables. - */ -class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { - override Language::AutomaticVariable var; - - final override Language::AutomaticVariable getVariable() { result = var } -} - -/** - * A user-declared variable that is not allocated on the stack. This includes all global variables, - * namespace-scope variables, static fields, and static local variables. - */ -class IRStaticUserVariable extends IRUserVariable { - override Language::StaticVariable var; - - IRStaticUserVariable() { not Language::isVariableAutomatic(var) } - - final override Language::StaticVariable getVariable() { result = var } -} - -/** - * A variable that is not user-declared. This includes temporary variables generated as part of IR - * construction, as well as string literals. - */ -class IRGeneratedVariable extends IRVariable { - Language::AST ast; - Language::LanguageType type; - - IRGeneratedVariable() { - this = TIRTempVariable(func, ast, _, type) or - this = TIRStringLiteral(func, ast, type, _) or - this = TIRDynamicInitializationFlag(func, ast, type) - } - - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAst() { result = ast } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - - override string toString() { result = this.getBaseString() + this.getLocationString() } - - override string getUniqueId() { none() } - - /** - * INTERNAL: Do not use. - * - * Gets a string containing the source code location of the AST that generated this variable. - * - * This is used by debugging and printing code only. - */ - final string getLocationString() { - result = - ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - /** - * INTERNAL: Do not use. - * - * Gets the string that is combined with the location of the variable to generate the string - * representation of this variable. - * - * This is used by debugging and printing code only. - */ - string getBaseString() { none() } -} - -/** - * A temporary variable introduced by IR construction. The most common examples are the variable - * generated to hold the return value of a function, or the variable generated to hold the result of - * a condition operator (`a ? b : c`). - */ -class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { - TempVariableTag tag; - - IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - - final override string getUniqueId() { - result = "Temp: " + Construction::getTempVariableUniqueId(this) - } - - /** - * Gets the "tag" object that differentiates this temporary variable from other temporary - * variables generated for the same AST. - */ - final TempVariableTag getTag() { result = tag } - - override string getBaseString() { result = "#temp" } -} - -/** - * A temporary variable generated to hold the return value of a function. - */ -class IRReturnVariable extends IRTempVariable { - IRReturnVariable() { tag = ReturnValueTempVar() } - - final override string toString() { result = "#return" } -} - -/** - * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. - */ -class IRThrowVariable extends IRTempVariable { - IRThrowVariable() { tag = ThrowTempVar() } - - final override string getBaseString() { result = "#throw" } -} - -/** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. - */ -class IREllipsisVariable extends IRTempVariable, IRParameter { - IREllipsisVariable() { tag = EllipsisTempVar() } - - final override string toString() { result = "#ellipsis" } - - final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() } -} - -/** - * A temporary variable generated to hold the `this` pointer. - */ -class IRThisVariable extends IRTempVariable, IRParameter { - IRThisVariable() { tag = ThisTempVar() } - - final override string toString() { result = "#this" } - - final override int getIndex() { result = -1 } -} - -/** - * A variable generated to represent the contents of a string literal. This variable acts much like - * a read-only global variable. - */ -class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { - Language::StringLiteral literal; - - IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } - - final override predicate isReadOnly() { any() } - - final override string getUniqueId() { - result = "String: " + this.getLocationString() + "=" + Language::getStringLiteralText(literal) - } - - final override string getBaseString() { result = "#string" } - - /** - * Gets the AST of the string literal represented by this `IRStringLiteral`. - */ - final Language::StringLiteral getLiteral() { result = literal } -} - -/** - * A variable generated to track whether a specific non-stack variable has been initialized. This is - * used to model the runtime initialization of static local variables in C++, as well as static - * fields in C#. - */ -class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag { - Language::Variable var; - - IRDynamicInitializationFlag() { - this = TIRDynamicInitializationFlag(func, var, type) and ast = var - } - - final override string toString() { result = var.toString() + "#init" } - - /** - * Gets variable whose initialization is guarded by this flag. - */ - final Language::Variable getVariable() { result = var } - - final override string getUniqueId() { - result = - "Init: " + this.getVariable().toString() + " " + this.getVariable().getLocation().toString() - } - - final override string getBaseString() { result = "#init:" + var.toString() + ":" } -} - -/** - * An IR variable which acts like a function parameter, including positional parameters and the - * temporary variables generated for `this` and ellipsis parameters. - */ -class IRParameter extends IRAutomaticVariable { - IRParameter() { - this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter - or - this = TIRTempVariable(_, _, ThisTempVar(), _) - or - this = TIRTempVariable(_, _, EllipsisTempVar(), _) - } - - /** - * Gets the zero-based index of this parameter. The `this` parameter has index -1. - */ - int getIndex() { none() } -} - -/** - * An IR variable representing a positional parameter. - */ -class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { - final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll deleted file mode 100644 index 189ffce2903..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ /dev/null @@ -1,2231 +0,0 @@ -/** - * Provides classes that represent the individual instructions in the IR for a function. - */ - -private import internal.IRInternal -import IRFunction -import IRBlock -import IRVariable -import Operand -private import internal.InstructionImports as Imports -import Imports::EdgeKind -import Imports::IRType -import Imports::MemoryAccessKind -import Imports::Opcode -private import Imports::OperandTag - -/** - * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified - * `File` and line number. Used for assigning register names when printing IR. - */ -private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(irFunc.getFunction()) - ) and - exists(Language::Location location | - irFunc = result.getEnclosingIRFunction() and - location = result.getLocation() and - file = location.getFile() and - line = location.getStartLine() - ) -} - -/** - * A single instruction in the IR. - */ -class Instruction extends Construction::TStageInstruction { - Instruction() { - // The base `TStageInstruction` type is a superset of the actual instructions appearing in this - // stage. This call lets the stage filter out the ones that are not reused from raw IR. - Construction::hasInstruction(this) - } - - /** Gets a textual representation of this element. */ - final string toString() { result = this.getOpcode().toString() + ": " + this.getAst().toString() } - - /** - * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what - * would be printed by PrintIR.ql. For example: - * - * `mu0_28(int) = Store r0_26, r0_27` - */ - final string getDumpString() { - result = - this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() - } - - private predicate shouldGenerateDumpStrings() { - exists(IRConfiguration::IRConfiguration config | - config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) - ) - } - - /** - * Gets a string describing the operation of this instruction. This includes - * the opcode and the immediate value, if any. For example: - * - * VariableAddress[x] - */ - final string getOperationString() { - this.shouldGenerateDumpStrings() and - if exists(this.getImmediateString()) - then - result = - this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + - "]" - else result = this.getOperationPrefix() + this.getOpcode().toString() - } - - /** - * Gets a string describing the immediate value of this instruction, if any. - */ - string getImmediateString() { none() } - - private string getOperationPrefix() { - this.shouldGenerateDumpStrings() and - if this instanceof SideEffectInstruction then result = "^" else result = "" - } - - private string getResultPrefix() { - this.shouldGenerateDumpStrings() and - if this.getResultIRType() instanceof IRVoidType - then result = "v" - else - if this.hasMemoryResult() - then if this.isResultModeled() then result = "m" else result = "mu" - else result = "r" - } - - /** - * Gets the zero-based index of this instruction within its block. This is - * used by debugging and printing code only. - */ - int getDisplayIndexInBlock() { - this.shouldGenerateDumpStrings() and - exists(IRBlock block | - this = block.getInstruction(result) - or - this = - rank[-result - 1](PhiInstruction phiInstr | - phiInstr = block.getAPhiInstruction() - | - phiInstr order by phiInstr.getUniqueId() - ) - ) - } - - private int getLineRank() { - this.shouldGenerateDumpStrings() and - exists(IRFunction enclosing, Language::File file, int line | - this = - rank[result](Instruction instr | - instr = getAnInstructionAtLine(enclosing, file, line) - | - instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() - ) - ) - } - - /** - * Gets a human-readable string that uniquely identifies this instruction - * within the function. This string is used to refer to this instruction when - * printing IR dumps. - * - * Example: `r1_1` - */ - string getResultId() { - this.shouldGenerateDumpStrings() and - result = - this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank() - } - - /** - * Gets a string describing the result of this instruction, suitable for - * display in IR dumps. This consists of the result ID plus the type of the - * result. - * - * Example: `r1_1(int*)` - */ - final string getResultString() { - this.shouldGenerateDumpStrings() and - result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" - } - - /** - * Gets a string describing the operands of this instruction, suitable for - * display in IR dumps. - * - * Example: `func:r3_4, this:r3_5` - */ - string getOperandsString() { - this.shouldGenerateDumpStrings() and - result = - concat(Operand operand | - operand = this.getAnOperand() - | - operand.getDumpString(), ", " order by operand.getDumpSortOrder() - ) - } - - /** - * Gets a string identifier for this function that is unique among all - * instructions in the same function. - * - * This is used for sorting IR output for tests, and is likely to be - * inefficient for any other use. - */ - final string getUniqueId() { result = Construction::getInstructionUniqueId(this) } - - /** - * INTERNAL: Do not use. - * - * Gets two sort keys for this instruction - used to order instructions for printing - * in test outputs. - */ - final predicate hasSortKeys(int key1, int key2) { - Construction::instructionHasSortKeys(this, key1, key2) - } - - /** - * Gets the basic block that contains this instruction. - */ - final IRBlock getBlock() { result.getAnInstruction() = this } - - /** - * Gets the function that contains this instruction. - */ - final Language::Declaration getEnclosingFunction() { - result = this.getEnclosingIRFunction().getFunction() - } - - /** - * Gets the IRFunction object that contains the IR for this instruction. - */ - final IRFunction getEnclosingIRFunction() { - result = Construction::getInstructionEnclosingIRFunction(this) - } - - /** - * Gets the AST that caused this instruction to be generated. - */ - final Language::AST getAst() { result = Construction::getInstructionAst(this) } - - /** - * Gets the location of the source code for this instruction. - */ - final Language::Location getLocation() { result = this.getAst().getLocation() } - - /** - * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a - * conversion. - */ - final Language::Expr getConvertedResultExpression() { - result = Raw::getInstructionConvertedResultExpression(this) - } - - /** - * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. - */ - final Language::Expr getUnconvertedResultExpression() { - result = Raw::getInstructionUnconvertedResultExpression(this) - } - - /** - * Gets the language-specific type of the result produced by this instruction. - * - * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a - * less complex, language-neutral type system in which all semantically equivalent types share the - * same `IRType` instance. For example, in C++, four different `Instruction`s might have three - * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, - * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. - */ - final Language::LanguageType getResultLanguageType() { - result = Construction::getInstructionResultType(this) - } - - /** - * Gets the type of the result produced by this instruction. If the instruction does not produce - * a result, its result type will be `IRVoidType`. - */ - cached - final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } - - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = this.getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * ``` - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * ``` - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } - - /** - * Gets the size of the result produced by this instruction, in bytes. If the - * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. - */ - final int getResultSize() { result = this.getResultLanguageType().getByteSize() } - - /** - * Gets the opcode that specifies the operation performed by this instruction. - */ - pragma[inline] - final Opcode getOpcode() { Construction::getInstructionOpcode(result, this) } - - /** - * Gets all direct uses of the result of this instruction. The result can be - * an `Operand` for which `isDefinitionInexact` holds. - */ - final Operand getAUse() { result.getAnyDef() = this } - - /** - * Gets all of this instruction's operands. - */ - final Operand getAnOperand() { result.getUse() = this } - - /** - * Holds if this instruction produces a memory result. - */ - final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } - - /** - * Gets the kind of memory access performed by this instruction's result. - * Holds only for instructions with a memory result. - */ - pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { - result = this.getOpcode().getWriteMemoryAccess() - } - - /** - * Holds if the memory access performed by this instruction's result will not always write to - * every bit in the memory location. This is most commonly used for memory accesses that may or - * may not actually occur depending on runtime state (for example, the write side effect of an - * output parameter that is not written to on all paths), or for accesses where the memory - * location is a conservative estimate of the memory that might actually be accessed at runtime - * (for example, the global side effects of a function call). - */ - pragma[inline] - final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } - - /** - * Gets the operand that holds the memory address to which this instruction stores its - * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` - * is `r1`. - */ - final AddressOperand getResultAddressOperand() { - this.getResultMemoryAccess().usesAddressOperand() and - result.getUse() = this - } - - /** - * Gets the instruction that holds the exact memory address to which this instruction stores its - * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` - * is the instruction that defines `r1`. - */ - final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } - - /** - * Holds if the result of this instruction is precisely modeled in SSA. Always - * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result has no uses. - * - * For example: - * ``` - * int x = 1; - * int *p = &x; - * int y = *p; - * ``` - * In non-aliased SSA, `x` will not be modeled because it has its address - * taken. In that case, `isResultModeled()` would not hold for the result of - * the `Store` to `x`. - */ - final predicate isResultModeled() { - // Register results are always in SSA form. - not this.hasMemoryResult() or - Construction::hasModeledMemoryResult(this) - } - - /** - * Holds if this is an instruction with a memory result that represents a - * conflation of more than one memory allocation. - * - * This happens in practice when dereferencing a pointer that cannot be - * tracked back to a single local allocation. Such memory is instead modeled - * as originating on the `AliasedDefinitionInstruction` at the entry of the - * function. - */ - final predicate isResultConflated() { Construction::hasConflatedMemoryResult(this) } - - /** - * Gets the successor of this instruction along the control flow edge - * specified by `kind`. - */ - final Instruction getSuccessor(EdgeKind kind) { - result = Construction::getInstructionSuccessor(this, kind) - } - - /** - * Gets the a _back-edge successor_ of this instruction along the control - * flow edge specified by `kind`. A back edge in the control-flow graph is - * intuitively the edge that goes back around a loop. If all back edges are - * removed from the control-flow graph, it becomes acyclic. - */ - final Instruction getBackEdgeSuccessor(EdgeKind kind) { - // We don't take these edges from - // `Construction::getInstructionBackEdgeSuccessor` since that relation has - // not been treated to remove any loops that might be left over due to - // flaws in the IR construction or back-edge detection. - exists(IRBlock block | - block = this.getBlock() and - this = block.getLastInstruction() and - result = block.getBackEdgeSuccessor(kind).getFirstInstruction() - ) - } - - /** - * Gets all direct successors of this instruction. - */ - final Instruction getASuccessor() { result = this.getSuccessor(_) } - - /** - * Gets a predecessor of this instruction such that the predecessor reaches - * this instruction along the control flow edge specified by `kind`. - */ - final Instruction getPredecessor(EdgeKind kind) { result.getSuccessor(kind) = this } - - /** - * Gets all direct predecessors of this instruction. - */ - final Instruction getAPredecessor() { result = this.getPredecessor(_) } -} - -/** - * An instruction that refers to a variable. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * variable. For example, it is used for `VariableAddress`, which returns the address of a specific - * variable, and `InitializeParameter`, which returns the value that was passed to the specified - * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions - * that happen to load from or store to a particular variable; in those cases, the memory location - * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be - * defined by the result of a `VariableAddress` instruction. - */ -class VariableInstruction extends Instruction { - IRVariable var; - - VariableInstruction() { var = Raw::getInstructionVariable(this) } - - override string getImmediateString() { result = var.toString() } - - /** - * Gets the variable that this instruction references. - */ - final IRVariable getIRVariable() { result = var } - - /** - * Gets the AST variable that this instruction's IR variable refers to, if one exists. - */ - final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } -} - -/** - * An instruction that refers to a field of a class, struct, or union. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * field. For example, it is used for `FieldAddress`, which computes the address of a specific - * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen - * to load from or store to a particular field; in those cases, the memory location being accessed - * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the - * result of a `FieldAddress` instruction. - */ -class FieldInstruction extends Instruction { - Language::Field field; - - FieldInstruction() { field = Raw::getInstructionField(this) } - - final override string getImmediateString() { result = field.toString() } - - /** - * Gets the field that this instruction references. - */ - final Language::Field getField() { result = field } -} - -/** - * An instruction that refers to a function. - * - * This class is used for any instruction whose operation fundamentally depends on a specific - * function. For example, it is used for `FunctionAddress`, which returns the address of a specific - * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a - * particular function; in that case, the function being called is specified by the - * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a - * `FunctionAddress` instruction. - */ -class FunctionInstruction extends Instruction { - Language::Function funcSymbol; - - FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } - - final override string getImmediateString() { result = funcSymbol.toString() } - - /** - * Gets the function that this instruction references. - */ - final Language::Function getFunctionSymbol() { result = funcSymbol } -} - -/** - * An instruction whose result is a compile-time constant value. - */ -class ConstantValueInstruction extends Instruction { - string value; - - ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } - - final override string getImmediateString() { result = value } - - /** - * Gets the constant value of this instruction's result. - */ - final string getValue() { result = value } -} - -/** - * An instruction that refers to an argument of a `Call` instruction. - * - * This instruction is used for side effects of a `Call` instruction that read or write memory - * pointed to by one of the arguments of the call. - */ -class IndexedInstruction extends Instruction { - int index; - - IndexedInstruction() { index = Raw::getInstructionIndex(this) } - - final override string getImmediateString() { result = index.toString() } - - /** - * Gets the zero-based index of the argument that this instruction references. - */ - final int getIndex() { result = index } -} - -/** - * An instruction representing the entry point to a function. - * - * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins - * at this instruction. This instruction has no predecessors. - */ -class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } -} - -/** - * An instruction that returns the address of a variable. - * - * This instruction returns the address of a local variable, parameter, static field, - * namespace-scope variable, or global variable. For the address of a non-static field of a class, - * struct, or union, see `FieldAddressInstruction`. - */ -class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } -} - -/** - * An instruction that returns the address of a function. - * - * This instruction returns the address of a function, including non-member functions, static member - * functions, and non-static member functions. - * - * The result has an `IRFunctionAddress` type. - */ -class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } -} - -/** - * An instruction that returns the address of a "virtual" delete function. - * - * This function, which does not actually exist in the source code, is used to - * delete objects of a class with a virtual destructor. In that case the deacllocation - * function is selected at runtime based on the dynamic type of the object. So this - * function dynamically dispatches to the correct deallocation function. - * It also should pass in the required extra arguments to the deallocation function - * which may differ dynamically depending on the type of the object. - */ -class VirtualDeleteFunctionAddressInstruction extends Instruction { - VirtualDeleteFunctionAddressInstruction() { - this.getOpcode() instanceof Opcode::VirtualDeleteFunctionAddress - } -} - -/** - * An instruction that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. - * - * Each parameter of a function will have exactly one `InitializeParameter` instruction that - * initializes that parameter. - */ -class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } - - /** - * Gets the parameter initialized by this instruction. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction initializes the parameter with index `index`, or - * if `index` is `-1` and this instruction initializes `this`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.getIRVariable() instanceof IRThisVariable - } -} - -/** - * An instruction that initializes all memory that existed before this function was called. - * - * This instruction provides a definition for memory that, because it was actually allocated and - * initialized elsewhere, would not otherwise have a definition in this function. - */ -class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } -} - -/** - * An instruction that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. - */ -class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } - - /** - * Gets the parameter initialized by this instruction. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction initializes the memory pointed to by the parameter with - * index `index`, or if `index` is `-1` and this instruction initializes the memory - * pointed to by `this`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.getIRVariable() instanceof IRThisVariable - } -} - -/** - * An instruction that initializes the `this` pointer parameter of the enclosing function. - */ -class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } -} - -/** - * An instruction that computes the address of a non-static field of an object. - */ -class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } - - /** - * Gets the operand that provides the address of the object containing the field. - */ - final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the object containing the field. - */ - final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } -} - -/** - * An instruction that computes the address of the first element of a managed array. - * - * This instruction is used for element access to C# arrays. - */ -class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } - - /** - * Gets the operand that provides the address of the array object. - */ - final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the array object. - */ - final Instruction getArrayObjectAddress() { - result = this.getArrayObjectAddressOperand().getDef() - } -} - -/** - * An instruction that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. - * - * This type of instruction appears when there is an `ErrorExpr` in the AST, - * meaning that the extractor could not understand the expression and therefore - * produced a partial AST. Queries that give alerts when some action is _not_ - * taken may want to ignore any function that contains an `ErrorInstruction`. - */ -class ErrorInstruction extends Instruction { - ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } -} - -/** - * An instruction that returns an uninitialized value. - * - * This instruction is used to provide an initial definition for a stack variable that does not have - * an initializer, or whose initializer only partially initializes the variable. - */ -class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } - - /** - * Gets the variable that is uninitialized. - */ - final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } -} - -/** - * An instruction that has no effect. - * - * This instruction is typically inserted to ensure that a particular AST is associated with at - * least one instruction, even when the AST has no semantic effect. - */ -class NoOpInstruction extends Instruction { - NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } -} - -/** - * An instruction that returns control to the caller of the function. - * - * This instruction represents the normal (non-exception) return from a function, either from an - * explicit `return` statement or from control flow reaching the end of the function's body. - * - * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is - * represented as an initialization of the temporary variable that holds the return value, with - * control then flowing to the common `ReturnInstruction` for that function. Exception: A function - * that never returns will not have a `ReturnInstruction`. - * - * The `ReturnInstruction` for a function will have a control-flow successor edge to a block - * containing the `ExitFunction` instruction for that function. - * - * There are two different return instructions: `ReturnValueInstruction`, for returning a value from - * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a - * `void`-returning function. - */ -class ReturnInstruction extends Instruction { - ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } -} - -/** - * An instruction that returns control to the caller of the function, without returning a value. - */ -class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } -} - -/** - * An instruction that returns control to the caller of the function, including a return value. - */ -class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } - - /** - * Gets the operand that provides the value being returned by the function. - */ - final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that provides the address of the value being returned by the function. - */ - final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value being returned by the function, if an - * exact definition is available. - */ - final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } - - /** - * Gets the instruction whose result provides the address of the value being returned by the function. - */ - final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } -} - -/** - * An instruction that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. - * - * This instruction does not itself return control to the caller. It merely represents the potential - * for a caller to use the memory pointed to by the parameter sometime after the call returns. This - * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility - * that the caller initialized the memory pointed to by the parameter before the call. - */ -class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } - - /** - * Gets the operand that provides the value of the pointed-to memory. - */ - final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value of the pointed-to memory, if an exact - * definition is available. - */ - final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } - - /** - * Gets the operand that provides the address of the pointed-to memory. - */ - final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the pointed-to memory. - */ - final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - - /** - * Gets the parameter for which this instruction reads the final pointed-to value within the - * function. - */ - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - /** - * Holds if this instruction is the return indirection for `this`. - */ - final predicate isThisIndirection() { var instanceof IRThisVariable } - - /** - * Holds if this instruction is the return indirection for the parameter with index `index`, or - * if this instruction is the return indirection for `this` and `index` is `-1`. - */ - pragma[noinline] - final predicate hasIndex(int index) { - index >= 0 and index = this.getParameter().getIndex() - or - index = -1 and this.isThisIndirection() - } -} - -/** - * An instruction that returns a copy of its operand. - * - * There are several different copy instructions, depending on the source and destination of the - * copy operation: - * - `CopyValueInstruction` - Copies a register operand to a register result. - * - `LoadInstruction` - Copies a memory operand to a register result. - * - `StoreInstruction` - Copies a register operand to a memory result. - */ -class CopyInstruction extends Instruction { - CopyInstruction() { this.getOpcode() instanceof CopyOpcode } - - /** - * Gets the operand that provides the input value of the copy. - */ - Operand getSourceValueOperand() { none() } - - /** - * Gets the instruction whose result provides the input value of the copy, if an exact definition - * is available. - */ - final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } -} - -/** - * An instruction that returns a register result containing a copy of its register operand. - */ -class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - - final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * Gets a string describing the location pointed to by the specified address operand. - */ -private string getAddressOperandDescription(AddressOperand operand) { - result = operand.getDef().(VariableAddressInstruction).getIRVariable().toString() - or - not operand.getDef() instanceof VariableAddressInstruction and - result = "?" -} - -/** - * An instruction that returns a register result containing a copy of its memory operand. - */ -class LoadInstruction extends CopyInstruction { - LoadInstruction() { this.getOpcode() instanceof Opcode::Load } - - final override string getImmediateString() { - result = getAddressOperandDescription(this.getSourceAddressOperand()) - } - - /** - * Gets the operand that provides the address of the value being loaded. - */ - final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the value being loaded. - */ - final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - - final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * An instruction that returns a memory result containing a copy of its register operand. - */ -class StoreInstruction extends CopyInstruction { - StoreInstruction() { this.getOpcode() instanceof Opcode::Store } - - final override string getImmediateString() { - result = getAddressOperandDescription(this.getDestinationAddressOperand()) - } - - /** - * Gets the operand that provides the address of the location to which the value will be stored. - */ - final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the location to which the value will - * be stored, if an exact definition is available. - */ - final Instruction getDestinationAddress() { - result = this.getDestinationAddressOperand().getDef() - } - - final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } -} - -/** - * An instruction that branches to one of two successor instructions based on the value of a Boolean - * operand. - */ -class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } - - /** - * Gets the operand that provides the Boolean condition controlling the branch. - */ - final ConditionOperand getConditionOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the Boolean condition controlling the branch. - */ - final Instruction getCondition() { result = this.getConditionOperand().getDef() } - - /** - * Gets the instruction to which control will flow if the condition is true. - */ - final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } - - /** - * Gets the instruction to which control will flow if the condition is false. - */ - final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } -} - -/** - * An instruction representing the exit point of a function. - * - * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns - * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no - * successors. - */ -class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } -} - -/** - * An instruction whose result is a constant value. - */ -class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } -} - -/** - * An instruction whose result is a constant value of integer or Boolean type. - */ -class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { - exists(IRType resultType | - resultType = this.getResultIRType() and - (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) - ) - } -} - -/** - * An instruction whose result is a constant value of floating-point type. - */ -class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } -} - -/** - * An instruction whose result is the address of a string literal. - */ -class StringConstantInstruction extends VariableInstruction { - override IRStringLiteral var; - - final override string getImmediateString() { - result = Language::getStringLiteralText(this.getValue()) - } - - /** - * Gets the string literal whose address is returned by this instruction. - */ - final Language::StringLiteral getValue() { result = var.getLiteral() } -} - -/** - * An instruction whose result is computed from two operands. - */ -class BinaryInstruction extends Instruction { - BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } - - /** - * Gets the left operand of this binary instruction. - */ - final LeftOperand getLeftOperand() { result = this.getAnOperand() } - - /** - * Gets the right operand of this binary instruction. - */ - final RightOperand getRightOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the value of the left operand of this binary - * instruction. - */ - final Instruction getLeft() { result = this.getLeftOperand().getDef() } - - /** - * Gets the instruction whose result provides the value of the right operand of this binary - * instruction. - */ - final Instruction getRight() { result = this.getRightOperand().getDef() } - - /** - * Holds if this instruction's operands are `op1` and `op2`, in either order. - */ - final predicate hasOperands(Operand op1, Operand op2) { - op1 = this.getLeftOperand() and op2 = this.getRightOperand() - or - op1 = this.getRightOperand() and op2 = this.getLeftOperand() - } -} - -/** - * An instruction that computes the result of an arithmetic operation. - */ -class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } -} - -/** - * An instruction that performs an arithmetic operation on two numeric operands. - */ -class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } - -/** - * An instruction whose result is computed by performing an arithmetic operation on a single - * numeric operand. - */ -class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } - -/** - * An instruction that computes the sum of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is - * performed according to IEEE-754. - */ -class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { this.getOpcode() instanceof Opcode::Add } -} - -/** - * An instruction that computes the difference of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed - * according to IEEE-754. - */ -class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { this.getOpcode() instanceof Opcode::Sub } -} - -/** - * An instruction that computes the product of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is - * performed according to IEEE-754. - */ -class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { this.getOpcode() instanceof Opcode::Mul } -} - -/** - * An instruction that computes the quotient of two numeric operands. - * - * Both operands must have the same numeric type, which will also be the result type. The result of - * division by zero or integer overflow is undefined. Floating-point division is performed according - * to IEEE-754. - */ -class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { this.getOpcode() instanceof Opcode::Div } -} - -/** - * An instruction that computes the remainder of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. The result of - * division by zero or integer overflow is undefined. - */ -class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { this.getOpcode() instanceof Opcode::Rem } -} - -/** - * An instruction that negates a single numeric operand. - * - * The operand must have a numeric type, which will also be the result type. The result of integer - * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation - * is performed according to IEEE-754. - */ -class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } -} - -/** - * An instruction that computes the result of a bitwise operation. - */ -class BitwiseInstruction extends Instruction { - BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } -} - -/** - * An instruction that performs a bitwise operation on two integer operands. - */ -class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } - -/** - * An instruction that performs a bitwise operation on a single integer operand. - */ -class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } - -/** - * An instruction that computes the bitwise "and" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } -} - -/** - * An instruction that computes the bitwise "or" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } -} - -/** - * An instruction that computes the bitwise "xor" of two integer operands. - * - * Both operands must have the same integer type, which will also be the result type. - */ -class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } -} - -/** - * An instruction that shifts its left operand to the left by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. The - * rightmost bits are zero-filled. - */ -class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } -} - -/** - * An instruction that shifts its left operand to the right by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. If the - * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand - * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit - * of the left operand. - */ -class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } -} - -/** - * An instruction that shifts its left operand to the right by the number of bits specified by its - * right operand. - * - * Both operands must have an integer type. The result has the same type as the left operand. - * The leftmost bits are zero-filled. - */ -class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction { - UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight } -} - -/** - * An instruction that performs a binary arithmetic operation involving at least one pointer - * operand. - */ -class PointerArithmeticInstruction extends BinaryInstruction { - int elementSize; - - PointerArithmeticInstruction() { - this.getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Raw::getInstructionElementSize(this) - } - - final override string getImmediateString() { result = elementSize.toString() } - - /** - * Gets the size of the elements pointed to by the pointer operands, in bytes. - * - * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer - * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the - * element size to compute the actual number of bytes added to or subtracted from the pointer - * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), - * the result is computed by computing the difference between the two pointer byte addresses, then - * dividing that byte count by the element size. - */ - final int getElementSize() { result = elementSize } -} - -/** - * An instruction that adds or subtracts an integer offset from a pointer. - */ -class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } -} - -/** - * An instruction that adds an integer offset to a pointer. - * - * The result is the byte address computed by adding the value of the right (integer) operand, - * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer - * overflow is undefined. - */ -class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } -} - -/** - * An instruction that subtracts an integer offset from a pointer. - * - * The result is the byte address computed by subtracting the value of the right (integer) operand, - * multiplied by the element size, from the value of the left (pointer) operand. The result of - * pointer underflow is undefined. - */ -class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } -} - -/** - * An instruction that computes the difference between two pointers. - * - * Both operands must have the same pointer type. The result must have an integer type whose size is - * the same as that of the pointer operands. The result is computed by subtracting the byte address - * in the right operand from the byte address in the left operand, and dividing by the element size. - * If the difference in byte addresses is not divisible by the element size, the result is - * undefined. - */ -class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } -} - -/** - * An instruction whose result is computed from a single operand. - */ -class UnaryInstruction extends Instruction { - UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } - - /** - * Gets the sole operand of this instruction. - */ - final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the sole operand of this instruction. - */ - final Instruction getUnary() { result = this.getUnaryOperand().getDef() } -} - -/** - * An instruction that converts the value of its operand to a value of a different type. - */ -class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } -} - -/** - * An instruction that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or - * `as` expression. - */ -class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } -} - -/** - * An instruction that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast - * expression. - */ -class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } -} - -/** - * An instruction that returns the address of the complete object that contains the subobject - * pointed to by its operand. - * - * If the operand holds a null address, the result is a null address. - * - * This instruction is used to represent `dynamic_cast` in C++, which returns the pointer to - * the most-derived object. - */ -class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } -} - -/** - * An instruction that converts the address of an object to the address of a different subobject of - * the same object, without any type checking at runtime. - */ -class InheritanceConversionInstruction extends UnaryInstruction { - Language::Class baseClass; - Language::Class derivedClass; - - InheritanceConversionInstruction() { - Raw::getInstructionInheritance(this, baseClass, derivedClass) - } - - final override string getImmediateString() { - result = derivedClass.toString() + " : " + baseClass.toString() - } - - /** - * Gets the `ClassDerivation` for the inheritance relationship between - * the base and derived classes. This predicate does not hold if the - * conversion is to an indirect virtual base class. - */ - final Language::ClassDerivation getDerivation() { - result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass - } - - /** - * Gets the base class of the conversion. This will be either a direct - * base class of the derived class, or a virtual base class of the - * derived class. - */ - final Language::Class getBaseClass() { result = baseClass } - - /** - * Gets the derived class of the conversion. - */ - final Language::Class getDerivedClass() { result = derivedClass } -} - -/** - * An instruction that converts from the address of a derived class to the address of a base class. - */ -class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } -} - -/** - * An instruction that converts from the address of a derived class to the address of a direct - * non-virtual base class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { - this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase - } -} - -/** - * An instruction that converts from the address of a derived class to the address of a virtual base - * class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } -} - -/** - * An instruction that converts from the address of a base class to the address of a direct - * non-virtual derived class. - * - * If the operand holds a null address, the result is a null address. - */ -class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } -} - -/** - * An instruction that computes the bitwise complement of its operand. - * - * The operand must have an integer type, which will also be the result type. - */ -class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } -} - -/** - * An instruction that computes the logical complement of its operand. - * - * The operand must have a Boolean type, which will also be the result type. - */ -class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } -} - -/** - * An instruction that compares two numeric operands. - */ -class CompareInstruction extends BinaryInstruction { - CompareInstruction() { this.getOpcode() instanceof CompareOpcode } -} - -/** - * An instruction that returns a `true` result if its operands are equal. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are - * unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } -} - -/** - * An instruction that returns a `true` result if its operands are not equal. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if `left != right` or if the two operands are unordered, and `false` if - * `left == right`. Floating-point comparison is performed according to IEEE-754. - */ -class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } -} - -/** - * An instruction that does a relative comparison of two values, such as `<` or `>=`. - */ -class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } - - /** - * Gets the operand on the "greater" (or "greater-or-equal") side - * of this relational instruction, that is, the side that is larger - * if the overall instruction evaluates to `true`; for example on - * `x <= 20` this is the `20`, and on `y > 0` it is `y`. - */ - Instruction getGreater() { none() } - - /** - * Gets the operand on the "lesser" (or "lesser-or-equal") side - * of this relational instruction, that is, the side that is smaller - * if the overall instruction evaluates to `true`; for example on - * `x <= 20` this is `x`, and on `y > 0` it is the `0`. - */ - Instruction getLesser() { none() } - - /** - * Holds if this relational instruction is strict (is not an "or-equal" instruction). - */ - predicate isStrict() { none() } -} - -/** - * An instruction that returns a `true` result if its left operand is less than its right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - - override Instruction getLesser() { result = this.getLeft() } - - override Instruction getGreater() { result = this.getRight() } - - override predicate isStrict() { any() } -} - -/** - * An instruction that returns a `true` result if its left operand is greater than its right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - - override Instruction getLesser() { result = this.getRight() } - - override Instruction getGreater() { result = this.getLeft() } - - override predicate isStrict() { any() } -} - -/** - * An instruction that returns a `true` result if its left operand is less than or equal to its - * right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - - override Instruction getLesser() { result = this.getLeft() } - - override Instruction getGreater() { result = this.getRight() } - - override predicate isStrict() { none() } -} - -/** - * An instruction that returns a `true` result if its left operand is greater than or equal to its - * right operand. - * - * Both operands must have the same numeric or address type. The result must have a Boolean type. - * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands - * are unordered. Floating-point comparison is performed according to IEEE-754. - */ -class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - - override Instruction getLesser() { result = this.getRight() } - - override Instruction getGreater() { result = this.getLeft() } - - override predicate isStrict() { none() } -} - -/** - * An instruction that branches to one of multiple successor instructions based on the value of an - * integer operand. - * - * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each - * representing the branch that will be taken if the controlling expression is within the range - * specified for that case edge. The range of a case edge must be disjoint from the range of each - * other case edge. - * - * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, - * representing the branch that will be taken if the controlling expression is not within the range - * of any case edge. - */ -class SwitchInstruction extends Instruction { - SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } - - /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } - - /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = this.getExpressionOperand().getDef() } - - /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } - - /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } -} - -/** - * An instruction that calls a function. - */ -class CallInstruction extends Instruction { - CallInstruction() { this.getOpcode() instanceof Opcode::Call } - - final override string getImmediateString() { - result = this.getStaticCallTarget().toString() - or - not exists(this.getStaticCallTarget()) and result = "?" - } - - /** - * Gets the operand the specifies the target function of the call. - */ - final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } - - /** - * Gets the `Instruction` that computes the target function of the call. This is usually a - * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a - * function pointer. - */ - final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } - - /** - * Gets all of the argument operands of the call, including the `this` pointer, if any. - */ - final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } - - /** - * Gets the `Function` that the call targets, if this is statically known. - */ - final Language::Function getStaticCallTarget() { - result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() - } - - /** - * Gets all of the arguments of the call, including the `this` pointer, if any. - */ - final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } - - /** - * Gets the `this` pointer argument operand of the call, if any. - */ - final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } - - /** - * Gets the `this` pointer argument of the call, if any. - */ - final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } - - /** - * Gets the argument operand at the specified index. - */ - pragma[noinline] - final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = this.getAnOperand() and - result.getIndex() = index - } - - /** - * Gets the argument at the specified index. - */ - pragma[noinline] - final Instruction getPositionalArgument(int index) { - result = this.getPositionalArgumentOperand(index).getDef() - } - - /** - * Gets the argument operand at the specified index, or `this` if `index` is `-1`. - */ - pragma[noinline] - final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = this.getPositionalArgumentOperand(index) - or - index = -1 and result = this.getThisArgumentOperand() - } - - /** - * Gets the argument at the specified index, or `this` if `index` is `-1`. - */ - pragma[noinline] - final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } - - /** - * Gets the number of arguments of the call, including the `this` pointer, if any. - */ - final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) } - - /** - * Holds if the result is a side effect for the argument at the specified index, or `this` if - * `index` is `-1`. - * - * This helper predicate makes it easy to join on both of these columns at once, avoiding - * pathological join orders in case the argument index should get joined first. - */ - pragma[noinline] - final SideEffectInstruction getAParameterSideEffect(int index) { - this = result.getPrimaryInstruction() and - index = result.(IndexedInstruction).getIndex() - } -} - -/** - * An instruction representing a side effect of a function call. - */ -class SideEffectInstruction extends Instruction { - SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } - - /** - * Gets the instruction whose execution causes this side effect. - */ - final Instruction getPrimaryInstruction() { - result = Construction::getPrimaryInstructionForSideEffect(this) - } -} - -/** - * An instruction representing the side effect of a function call on any memory that might be - * accessed by that call. - */ -class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } -} - -/** - * An instruction representing the side effect of a function call on any memory - * that might be read by that call. - * - * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the - * call target cannot write to escaped memory. - */ -class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } -} - -/** - * An instruction representing a read side effect of a function call on a - * specific parameter. - */ -class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } - - /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } - - /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } - - /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = this.getAnOperand() } - - /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } -} - -/** - * An instruction representing the read of an indirect parameter within a function call. - */ -class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } -} - -/** - * An instruction representing the read of an indirect buffer parameter within a function call. - */ -class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } -} - -/** - * An instruction representing the read of an indirect buffer parameter within a function call. - */ -class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { - SizedBufferReadSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect - } - - /** - * Gets the operand that holds the number of bytes read from the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes read from the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing a write side effect of a function call on a - * specific parameter. - */ -class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } - - /** - * Get the operand that holds the address of the memory to be written. - */ - final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the address of the memory to be written. - */ - Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } -} - -/** - * An instruction representing the write of an indirect parameter within a function call. - */ -class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - IndirectMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. - */ -class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. - */ -class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { - SizedBufferMustWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect - } - - /** - * Gets the operand that holds the number of bytes written to the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes written to the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing the potential write of an indirect parameter within a function call. - * - * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. - * written. - */ -class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - IndirectMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. - * - * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. - */ -class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } -} - -/** - * An instruction representing the write of an indirect buffer parameter within a function call. - * - * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. - */ -class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - SizedBufferMayWriteSideEffectInstruction() { - this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect - } - - /** - * Gets the operand that holds the number of bytes written to the buffer. - */ - final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } - - /** - * Gets the instruction whose result provides the number of bytes written to the buffer. - */ - final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } -} - -/** - * An instruction representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. - */ -class InitializeDynamicAllocationInstruction extends SideEffectInstruction { - InitializeDynamicAllocationInstruction() { - this.getOpcode() instanceof Opcode::InitializeDynamicAllocation - } - - /** - * Gets the operand that represents the address of the allocation this instruction is initializing. - */ - final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the address for the allocation this instruction is initializing. - */ - final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } -} - -/** - * An instruction representing a GNU or MSVC inline assembly statement. - */ -class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } -} - -/** - * An instruction that throws an exception. - */ -class ThrowInstruction extends Instruction { - ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } -} - -/** - * An instruction that throws a new exception. - */ -class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } - - /** - * Gets the address operand of the exception thrown by this instruction. - */ - final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } - - /** - * Gets the address of the exception thrown by this instruction. - */ - final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } - - /** - * Gets the operand for the exception thrown by this instruction. - */ - final LoadOperand getExceptionOperand() { result = this.getAnOperand() } - - /** - * Gets the exception thrown by this instruction. - */ - final Instruction getException() { result = this.getExceptionOperand().getDef() } -} - -/** - * An instruction that re-throws the current exception. - */ -class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } -} - -/** - * An instruction that exits the current function by propagating an exception. - */ -class UnwindInstruction extends Instruction { - UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } -} - -/** - * An instruction that starts a `catch` handler. - */ -class CatchInstruction extends Instruction { - CatchInstruction() { this.getOpcode() instanceof CatchOpcode } -} - -/** - * An instruction that catches an exception of a specific type. - */ -class CatchByTypeInstruction extends CatchInstruction { - Language::LanguageType exceptionType; - - CatchByTypeInstruction() { - this.getOpcode() instanceof Opcode::CatchByType and - exceptionType = Raw::getInstructionExceptionType(this) - } - - final override string getImmediateString() { result = exceptionType.toString() } - - /** - * Gets the type of exception to be caught. - */ - final Language::LanguageType getExceptionType() { result = exceptionType } -} - -/** - * An instruction that catches any exception. - */ -class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } -} - -/** - * An instruction that initializes all escaped memory. - */ -class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } -} - -/** - * An instruction that consumes all escaped memory on exit from the function. - */ -class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } -} - -/** - * An instruction representing the choice of one of multiple input values based on control flow. - * - * A `PhiInstruction` is inserted at the beginning of a block whenever two different definitions of - * the same variable reach that block. The `PhiInstruction` will have one operand corresponding to - * each control flow predecessor of the block, with that operand representing the version of the - * variable that flows from that predecessor. The result value of the `PhiInstruction` will be - * a copy of whichever operand corresponds to the actual predecessor that entered the block at - * runtime. - */ -class PhiInstruction extends Instruction { - PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } - - /** - * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. - */ - final PhiInputOperand getAnInputOperand() { result = this.getAnOperand() } - - /** - * Gets an instruction that defines the input to one of the operands of this - * instruction. It's possible for more than one operand to have the same - * defining instruction, so this predicate will have the same number of - * results as `getAnInputOperand()` or fewer. - */ - pragma[noinline] - final Instruction getAnInput() { result = this.getAnInputOperand().getDef() } - - /** - * Gets the input operand representing the value that flows from the specified predecessor block. - */ - final PhiInputOperand getInputOperand(IRBlock predecessorBlock) { - result = this.getAnOperand() and - result.getPredecessorBlock() = predecessorBlock - } -} - -/** - * An instruction representing the effect that a write to a memory may have on potential aliases of - * that memory. - * - * A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The - * `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents - * the previous state of all of the memory that might be aliased by the memory write. The second - * operand, given by `getPartialOperand()`, represents the memory that was actually modified by the - * memory write. The result of the `ChiInstruction` represents the same memory as - * `getTotalOperand()`, updated to include the changes due to the value that was actually stored by - * the memory write. - * - * As an example, suppose that variable `p` and `q` are pointers that may or may not point to the - * same memory: - * ``` - * *p = 5; - * x = *q; - * ``` - * - * The IR would look like: - * ``` - * r1_1 = VariableAddress[p] - * r1_2 = Load r1_1, m0_0 // Load the value of `p` - * r1_3 = Constant[5] - * m1_4 = Store r1_2, r1_3 // Store to `*p` - * m1_5 = ^Chi m0_1, m1_4 // Side effect of the previous Store on aliased memory - * r1_6 = VariableAddress[x] - * r1_7 = VariableAddress[q] - * r1_8 = Load r1_7, m0_2 // Load the value of `q` - * r1_9 = Load r1_8, m1_5 // Load the value of `*q` - * m1_10 = Store r1_6, r1_9 // Store to x - * ``` - * - * Note the `Chi` instruction after the store to `*p`. The indicates that the previous contents of - * aliased memory (`m0_1`) are merged with the new value written by the store (`m1_4`), producing a - * new version of aliased memory (`m1_5`). On the subsequent load from `*q`, the source operand of - * `*q` is `m1_5`, indicating that the store to `*p` may (or may not) have updated the memory - * pointed to by `q`. - * - * For more information about how `Chi` instructions are used to model memory side effects, see - * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. - */ -class ChiInstruction extends Instruction { - ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } - - /** - * Gets the operand that represents the previous state of all memory that might be aliased by the - * memory write. - */ - final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that represents the previous state of all memory that might be aliased by the - * memory write. - */ - final Instruction getTotal() { result = this.getTotalOperand().getDef() } - - /** - * Gets the operand that represents the new value written by the memory write. - */ - final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } - - /** - * Gets the operand that represents the new value written by the memory write. - */ - final Instruction getPartial() { result = this.getPartialOperand().getDef() } - - /** - * Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`. - * This means that the `ChiPartialOperand` will not override the entire memory associated with the - * `ChiTotalOperand`. - */ - final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) } -} - -/** - * An instruction representing unreachable code. - * - * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` - * or `Switch` instruction where that particular edge is infeasible. - */ -class UnreachedInstruction extends Instruction { - UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } -} - -/** - * An instruction representing a built-in operation. - * - * This is used to represent a variety of intrinsic operations provided by the compiler - * implementation, such as vector arithmetic. - */ -class BuiltInOperationInstruction extends Instruction { - Language::BuiltInOperation operation; - - BuiltInOperationInstruction() { - this.getOpcode() instanceof BuiltInOperationOpcode and - operation = Raw::getInstructionBuiltInOperation(this) - } - - /** - * Gets the language-specific `BuiltInOperation` object that specifies the operation that is - * performed by this instruction. - */ - final Language::BuiltInOperation getBuiltInOperation() { result = operation } -} - -/** - * An instruction representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. - */ -class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - - final override string getImmediateString() { result = this.getBuiltInOperation().toString() } -} - -/** - * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. - * - * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` - * parameter. The result is a `va_list` that initially refers to the first argument that was passed - * to the `...` parameter. - */ -class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } -} - -/** - * An instruction that cleans up a `va_list` after it is no longer in use. - * - * The operand specifies the address of the `va_list` to clean up. This instruction does not return - * a result. - */ -class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } -} - -/** - * An instruction that returns the address of the argument currently pointed to by a `va_list`. - * - * The operand is the `va_list` that points to the argument. The result is the address of the - * argument. - */ -class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } -} - -/** - * An instruction that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. - * - * The operand is the current `va_list`. The result is an updated `va_list` that points to the next - * argument of the `...` parameter. - */ -class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } -} - -/** - * An instruction that allocates a new object on the managed heap. - * - * This instruction is used to represent the allocation of a new object in C# using the `new` - * expression. This instruction does not invoke a constructor for the object. Instead, there will be - * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the - * result of the `NewObj` as the `this` argument. - * - * The result is the address of the newly allocated object. - */ -class NewObjInstruction extends Instruction { - NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll deleted file mode 100644 index c1743acdbae..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ /dev/null @@ -1,499 +0,0 @@ -/** - * Provides classes that represent the input values of IR instructions. - */ - -private import internal.IRInternal -private import Instruction -private import IRBlock -private import internal.OperandImports as Imports -private import Imports::MemoryAccessKind -private import Imports::IRType -private import Imports::Overlap -private import Imports::OperandTag -private import Imports::TOperand -private import internal.OperandInternal - -/** - * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches - * of `TOperand` that are used in this stage. - */ -private class TStageOperand = - TRegisterOperand or TNonSsaMemoryOperand or TPhiOperand or TChiOperand; - -/** - * A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as - * opposed to testing `not loc isntanceof UnknownLocation` - */ -private class KnownLocation extends Language::Location { - KnownLocation() { not this instanceof Language::UnknownLocation } -} - -/** - * An operand of an `Instruction`. The operand represents a use of the result of one instruction - * (the defining instruction) in another instruction (the use instruction) - */ -class Operand extends TStageOperand { - cached - Operand() { - // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) - or - exists(Instruction use | this = nonSsaMemoryOperand(use, _)) - or - exists(Instruction use, Instruction def, IRBlock predecessorBlock | - this = phiOperand(use, def, predecessorBlock, _) or - this = reusedPhiOperand(use, def, predecessorBlock, _) - ) - or - this = chiOperand(_, _) - } - - /** Gets a textual representation of this element. */ - string toString() { result = "Operand" } - - /** - * Gets the location of the source code for this operand. - * By default this is where the operand is used, but some subclasses may override this - * using `getAnyDef()` if it makes more sense. - */ - Language::Location getLocation() { result = this.getUse().getLocation() } - - /** - * Gets the function that contains this operand. - */ - final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } - - /** - * Gets the `Instruction` that consumes this operand. - */ - Instruction getUse() { none() } - - /** - * Gets the `Instruction` whose result is the value of the operand. Unlike - * `getDef`, this also has a result when `isDefinitionInexact` holds, which - * means that the resulting instruction may only _partially_ or _potentially_ - * be the value of this operand. - */ - Instruction getAnyDef() { none() } - - /** - * Gets the `Instruction` whose result is the value of the operand. Unlike - * `getAnyDef`, this also has no result when `isDefinitionInexact` holds, - * which means that the resulting instruction must always be exactly the be - * the value of this operand. - */ - final Instruction getDef() { - result = this.getAnyDef() and - this.getDefinitionOverlap() instanceof MustExactlyOverlap - } - - /** - * Gets the overlap relationship between the operand's definition and its use. - */ - Overlap getDefinitionOverlap() { none() } - - /** - * Holds if the result of the definition instruction does not exactly overlap this use. - */ - final predicate isDefinitionInexact() { - not this.getDefinitionOverlap() instanceof MustExactlyOverlap - } - - /** - * Gets a prefix to use when dumping the operand in an operand list. - */ - string getDumpLabel() { result = "" } - - /** - * Gets a string that uniquely identifies this operand on its use instruction. - */ - string getDumpId() { result = "" } - - /** - * Gets a string describing this operand, suitable for display in IR dumps. This consists of the - * result ID of the instruction consumed by the operand, plus a label identifying the operand - * kind. - * - * For example: `this:r3_5` - */ - final string getDumpString() { - result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() - } - - /** - * Gets a string containing the identifier of the definition of this use, or `m?` if the - * definition is not modeled in SSA. - */ - private string getDefinitionId() { - result = this.getAnyDef().getResultId() - or - not exists(this.getAnyDef()) and result = "m?" - } - - /** - * Gets a string prefix to prepend to the operand's definition ID in an IR dump, specifying whether the operand is - * an exact or inexact use of its definition. For an inexact use, the prefix is "~". For an exact use, the prefix is - * the empty string. - */ - private string getInexactSpecifier() { - if this.isDefinitionInexact() then result = "~" else result = "" - } - - /** - * Get the order in which the operand should be sorted in the operand list. - */ - int getDumpSortOrder() { result = -1 } - - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } - - /** - * Gets the language-neutral type of the value consumed by this operand. This is usually the same - * as the result type of the definition instruction consumed by this operand. For register - * operands, this is always the case. For some memory operands, the operand type may be different - * from the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final IRType getIRType() { result = this.getLanguageType().getIRType() } - - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { this.getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { this.getLanguageType().hasType(_, true) } - - /** - * Gets the size of the value consumed by this operand, in bytes. If the operand does not have - * a known constant size, this predicate does not hold. - */ - final int getSize() { result = this.getLanguageType().getByteSize() } -} - -/** - * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). - */ -class MemoryOperand extends Operand { - cached - MemoryOperand() { - this instanceof TNonSsaMemoryOperand or - this instanceof TPhiOperand or - this instanceof TChiOperand - } - - /** - * Gets the kind of memory access performed by the operand. - */ - MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } - - /** - * Holds if the memory access performed by this operand will not always read from every bit in the - * memory location. This is most commonly used for memory accesses that may or may not actually - * occur depending on runtime state (for example, the write side effect of an output parameter - * that is not written to on all paths), or for accesses where the memory location is a - * conservative estimate of the memory that might actually be accessed at runtime (for example, - * the global side effects of a function call). - */ - predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } - - /** - * Returns the operand that holds the memory address from which the current operand loads its - * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` - * is `r1`. - */ - final AddressOperand getAddressOperand() { - this.getMemoryAccess().usesAddressOperand() and - result.getUse() = this.getUse() - } -} - -/** - * An operand that is not an operand of a `PhiInstruction`. - */ -class NonPhiOperand extends Operand { - Instruction useInstr; - OperandTag tag; - - NonPhiOperand() { - this = registerOperand(useInstr, tag, _) or - this = nonSsaMemoryOperand(useInstr, tag) or - this = chiOperand(useInstr, tag) - } - - final override Instruction getUse() { result = useInstr } - - final override string getDumpLabel() { result = tag.getLabel() } - - final override string getDumpId() { result = tag.getId() } - - final override int getDumpSortOrder() { result = tag.getSortOrder() } - - /** - * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. - */ - final OperandTag getOperandTag() { result = tag } -} - -/** - * An operand that consumes a register (non-memory) result. - */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { - override RegisterOperandTag tag; - Instruction defInstr; - - cached - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } - - final override string toString() { result = tag.toString() } - - // most `RegisterOperands` have a more meaningful location at the definition - // the only exception are specific cases of `ThisArgumentOperand` - override Language::Location getLocation() { result = this.getAnyDef().getLocation() } - - final override Instruction getAnyDef() { result = defInstr } - - final override Overlap getDefinitionOverlap() { - // All register results overlap exactly with their uses. - result instanceof MustExactlyOverlap - } -} - -/** - * A memory operand other than the operand of a `Phi` instruction. - */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { - override MemoryOperandTag tag; - - cached - NonPhiMemoryOperand() { - this = nonSsaMemoryOperand(useInstr, tag) - or - this = chiOperand(useInstr, tag) - } - - final override string toString() { result = tag.toString() } - - final override Instruction getAnyDef() { - result = unique(Instruction defInstr | this.hasDefinition(defInstr, _)) - } - - final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } - - pragma[noinline] - private predicate hasDefinition(Instruction defInstr, Overlap overlap) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - } - - /** - * Holds if the operand totally overlaps with its definition and consumes the - * bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition. - */ - predicate getUsedInterval(int startBitOffset, int endBitOffset) { - Construction::getUsedInterval(this, startBitOffset, endBitOffset) - } -} - -/** - * A memory operand whose type may be different from the type of the result of its definition. - */ -class TypedOperand extends NonPhiMemoryOperand { - override TypedOperandTag tag; - - final override Language::LanguageType getLanguageType() { - result = Construction::getInstructionOperandType(useInstr, tag) - } -} - -/** - * The address operand of an instruction that loads or stores a value from - * memory (e.g. `Load`, `Store`). - */ -class AddressOperand extends RegisterOperand { - override AddressOperandTag tag; -} - -/** - * The buffer size operand of an instruction that represents a read or write of - * a buffer. - */ -class BufferSizeOperand extends RegisterOperand { - override BufferSizeOperandTag tag; -} - -/** - * The source value operand of an instruction that loads a value from memory (e.g. `Load`, - * `ReturnValue`, `ThrowValue`). - */ -class LoadOperand extends TypedOperand { - override LoadOperandTag tag; -} - -/** - * The source value operand of a `Store` instruction. - */ -class StoreValueOperand extends RegisterOperand { - override StoreValueOperandTag tag; -} - -/** - * The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`). - */ -class UnaryOperand extends RegisterOperand { - override UnaryOperandTag tag; -} - -/** - * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). - */ -class LeftOperand extends RegisterOperand { - override LeftOperandTag tag; -} - -/** - * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). - */ -class RightOperand extends RegisterOperand { - override RightOperandTag tag; -} - -/** - * The condition operand of a `ConditionalBranch` or `Switch` instruction. - */ -class ConditionOperand extends RegisterOperand { - override ConditionOperandTag tag; -} - -/** - * The operand representing the target function of an `Call` instruction. - */ -class CallTargetOperand extends RegisterOperand { - override CallTargetOperandTag tag; -} - -/** - * An operand representing an argument to a function call. This includes both - * positional arguments (represented by `PositionalArgumentOperand`) and the - * implicit `this` argument, if any (represented by `ThisArgumentOperand`). - */ -class ArgumentOperand extends RegisterOperand { - override ArgumentOperandTag tag; - - /** Gets the `CallInstruction` for which this is an argument. */ - CallInstruction getCall() { result.getAnArgumentOperand() = this } -} - -/** - * An operand representing the implicit `this` argument to a member function - * call. - */ -class ThisArgumentOperand extends ArgumentOperand { - override ThisArgumentOperandTag tag; - - // in most cases the def location makes more sense, but in some corner cases it - // has an unknown location: in those cases we fall back to the use location - override Language::Location getLocation() { - if this.getAnyDef().getLocation() instanceof KnownLocation - then result = this.getAnyDef().getLocation() - else result = this.getUse().getLocation() - } -} - -/** - * An operand representing an argument to a function call. - */ -class PositionalArgumentOperand extends ArgumentOperand { - override PositionalArgumentOperandTag tag; - - /** - * Gets the zero-based index of the argument. - */ - final int getIndex() { result = tag.getArgIndex() } -} - -/** - * An operand representing memory read as a side effect of evaluating another instruction. - */ -class SideEffectOperand extends TypedOperand { - override SideEffectOperandTag tag; -} - -/** - * An operand of a `PhiInstruction`. - */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { - PhiInstruction useInstr; - Instruction defInstr; - IRBlock predecessorBlock; - Overlap overlap; - - cached - PhiInputOperand() { - this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) - or - this = reusedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) - } - - override string toString() { result = "Phi" } - - final override PhiInstruction getUse() { result = useInstr } - - final override Instruction getAnyDef() { result = defInstr } - - final override Overlap getDefinitionOverlap() { result = overlap } - - final override int getDumpSortOrder() { - result = 11 + this.getPredecessorBlock().getDisplayIndex() - } - - final override string getDumpLabel() { - result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" - } - - final override string getDumpId() { - result = this.getPredecessorBlock().getDisplayIndex().toString() - } - - /** - * Gets the predecessor block from which this value comes. - */ - final IRBlock getPredecessorBlock() { result = predecessorBlock } - - final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess } -} - -/** - * The total operand of a Chi node, representing the previous value of the memory. - */ -class ChiTotalOperand extends NonPhiMemoryOperand { - override ChiTotalOperandTag tag; - - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } -} - -/** - * The partial operand of a Chi node, representing the value being written to part of the memory. - */ -class ChiPartialOperand extends NonPhiMemoryOperand { - override ChiPartialOperandTag tag; - - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql deleted file mode 100644 index 83e2e37234b..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Print SSA IR - * @description Outputs a representation of the SSA IR graph - * @id cpp/print-ssa-ir - * @kind graph - */ - -import PrintIR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll deleted file mode 100644 index c4b18d9cb61..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll +++ /dev/null @@ -1,342 +0,0 @@ -/** - * Outputs a representation of the IR as a control flow graph. - * - * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small - * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintIR.qll`, extends - * `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations - * to dump. - */ - -private import internal.IRInternal -private import IR -private import internal.PrintIRImports as Imports -import Imports::IRConfiguration - -private newtype TPrintIRConfiguration = MkPrintIRConfiguration() - -/** - * The query can extend this class to control which declarations are printed. - */ -class PrintIRConfiguration extends TPrintIRConfiguration { - /** Gets a textual representation of this configuration. */ - string toString() { result = "PrintIRConfiguration" } - - /** - * Holds if the IR for `func` should be printed. By default, holds for all - * functions, global and namespace variables, and static local variables. - */ - predicate shouldPrintDeclaration(Language::Declaration decl) { any() } -} - -/** - * Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped. - */ -private class FilteredIRConfiguration extends IRConfiguration { - override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { - shouldPrintDeclaration(func) - } -} - -private predicate shouldPrintDeclaration(Language::Declaration decl) { - exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl)) -} - -private predicate shouldPrintInstruction(Instruction i) { - exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i)) -} - -private predicate shouldPrintOperand(Operand operand) { - exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand)) -} - -private string getAdditionalInstructionProperty(Instruction instr, string key) { - exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key)) -} - -private string getAdditionalBlockProperty(IRBlock block, string key) { - exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) -} - -/** - * Gets the properties of an operand from any active property providers. - */ -private string getAdditionalOperandProperty(Operand operand, string key) { - exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key)) -} - -/** - * Gets a string listing the properties of the operand and their corresponding values. If the - * operand has no properties, this predicate has no result. - */ -private string getOperandPropertyListString(Operand operand) { - result = - strictconcat(string key, string value | - value = getAdditionalOperandProperty(operand, key) - | - key + ":" + value, ", " - ) -} - -/** - * Gets a string listing the properties of the operand and their corresponding values. The list is - * surrounded by curly braces. If the operand has no properties, this predicate returns an empty - * string. - */ -private string getOperandPropertyString(Operand operand) { - result = "{" + getOperandPropertyListString(operand) + "}" - or - not exists(getOperandPropertyListString(operand)) and result = "" -} - -private newtype TPrintableIRNode = - TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or - TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or - TPrintableInstruction(Instruction instr) { - shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction()) - } - -/** - * A node to be emitted in the IR graph. - */ -abstract private class PrintableIRNode extends TPrintableIRNode { - abstract string toString(); - - /** - * Gets the location to be emitted for the node. - */ - abstract Language::Location getLocation(); - - /** - * Gets the label to be emitted for the node. - */ - abstract string getLabel(); - - /** - * Gets the order in which the node appears in its parent node. - */ - abstract int getOrder(); - - /** - * Gets the parent of this node. - */ - abstract PrintableIRNode getParent(); - - /** - * Gets the kind of graph represented by this node ("graph" or "tree"). - */ - string getGraphKind() { none() } - - /** - * Holds if this node should always be rendered as text, even in a graphical - * viewer. - */ - predicate forceText() { none() } - - /** - * Gets the value of the node property with the specified key. - */ - string getProperty(string key) { - key = "semmle.label" and result = this.getLabel() - or - key = "semmle.order" and result = this.getOrder().toString() - or - key = "semmle.graphKind" and result = this.getGraphKind() - or - key = "semmle.forceText" and this.forceText() and result = "true" - } -} - -/** - * An IR graph node representing a `IRFunction` object. - */ -private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { - IRFunction irFunc; - - PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } - - override string toString() { result = irFunc.toString() } - - override Language::Location getLocation() { result = irFunc.getLocation() } - - override string getLabel() { - result = Imports::LanguageDebug::getIdentityString(irFunc.getFunction()) - } - - override int getOrder() { - this = - rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location | - location = orderedFunc.getIRFunction().getLocation() - | - orderedFunc - order by - location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), - orderedFunc.getLabel() - ) - } - - final override PrintableIRNode getParent() { none() } - - final IRFunction getIRFunction() { result = irFunc } -} - -/** - * An IR graph node representing an `IRBlock` object. - */ -private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { - IRBlock block; - - PrintableIRBlock() { this = TPrintableIRBlock(block) } - - override string toString() { result = this.getLabel() } - - override Language::Location getLocation() { result = block.getLocation() } - - override string getLabel() { result = "Block " + block.getDisplayIndex().toString() } - - override int getOrder() { result = block.getDisplayIndex() } - - final override string getGraphKind() { result = "tree" } - - final override predicate forceText() { any() } - - final override PrintableIRFunction getParent() { - result.getIRFunction() = block.getEnclosingIRFunction() - } - - override string getProperty(string key) { - result = PrintableIRNode.super.getProperty(key) or - result = getAdditionalBlockProperty(block, key) - } - - final IRBlock getBlock() { result = block } -} - -/** - * An IR graph node representing an `Instruction`. - */ -private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { - Instruction instr; - - PrintableInstruction() { this = TPrintableInstruction(instr) } - - override string toString() { result = instr.toString() } - - override Language::Location getLocation() { result = instr.getLocation() } - - override string getLabel() { - exists(IRBlock block | - instr = block.getAnInstruction() and - exists( - string resultString, string operationString, string operandsString, int resultWidth, - int operationWidth - | - resultString = instr.getResultString() and - operationString = instr.getOperationString() and - operandsString = this.getOperandsString() and - columnWidths(block, resultWidth, operationWidth) and - result = - resultString + getPaddingString(resultWidth - resultString.length()) + " = " + - operationString + getPaddingString(operationWidth - operationString.length()) + " : " + - operandsString - ) - ) - } - - override int getOrder() { result = instr.getDisplayIndexInBlock() } - - final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() } - - final Instruction getInstruction() { result = instr } - - override string getProperty(string key) { - result = PrintableIRNode.super.getProperty(key) or - result = getAdditionalInstructionProperty(instr, key) - } - - /** - * Gets the string representation of the operand list. This is the same as - * `Instruction::getOperandsString()`, except that each operand is annotated with any properties - * provided by active `IRPropertyProvider` instances. - */ - private string getOperandsString() { - result = - concat(Operand operand | - operand = instr.getAnOperand() and - shouldPrintOperand(operand) - | - operand.getDumpString() + getOperandPropertyString(operand), ", " - order by - operand.getDumpSortOrder() - ) - } -} - -private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { - resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and - operationWidth = - max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length()) -} - -private int maxColumnWidth() { - result = - max(Instruction instr, int width | - width = instr.getResultString().length() or - width = instr.getOperationString().length() or - width = instr.getOperandsString().length() - | - width - ) -} - -private string getPaddingString(int n) { - n = 0 and result = "" - or - n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " -} - -/** - * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. - */ -query predicate nodes(PrintableIRNode node, string key, string value) { - value = node.getProperty(key) -} - -private int getSuccessorIndex(IRBlock pred, IRBlock succ) { - succ = - rank[result + 1](IRBlock aSucc, EdgeKind kind | - aSucc = pred.getSuccessor(kind) - | - aSucc order by kind.toString() - ) -} - -/** - * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` - * has the given `value`. - */ -query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | - predBlock = pred.getBlock() and - succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and - ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() - ) - or - key = "semmle.order" and - value = getSuccessorIndex(predBlock, succBlock).toString() - ) - ) -} - -/** - * Holds if `parent` is the parent node of `child` in the output graph. - */ -query predicate parents(PrintableIRNode child, PrintableIRNode parent) { - parent = child.getParent() -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll deleted file mode 100644 index c50e8385c99..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ /dev/null @@ -1,54 +0,0 @@ -private import internal.ConstantAnalysisInternal -private import experimental.ir.internal.IntegerPartial -private import IR - -language[monotonicAggregates] -int getConstantValue(Instruction instr) { - result = instr.(IntegerConstantInstruction).getValue().toInt() - or - result = getBinaryInstructionValue(instr) - or - result = neg(getConstantValue(instr.(NegateInstruction).getUnary())) - or - result = getConstantValue(instr.(CopyInstruction).getSourceValue()) - or - exists(PhiInstruction phi | - phi = instr and - result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and - result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) - ) -} - -pragma[noinline] -private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) { - left = getConstantValue(instr.getLeft()) and - right = getConstantValue(instr.getRight()) -} - -pragma[noinline] -private int getBinaryInstructionValue(BinaryInstruction instr) { - exists(int left, int right | - binaryInstructionOperands(instr, left, right) and - ( - instr instanceof AddInstruction and result = add(left, right) - or - instr instanceof SubInstruction and result = sub(left, right) - or - instr instanceof MulInstruction and result = mul(left, right) - or - instr instanceof DivInstruction and result = div(left, right) - or - instr instanceof CompareEQInstruction and result = compareEQ(left, right) - or - instr instanceof CompareNEInstruction and result = compareNE(left, right) - or - instr instanceof CompareLTInstruction and result = compareLT(left, right) - or - instr instanceof CompareGTInstruction and result = compareGT(left, right) - or - instr instanceof CompareLEInstruction and result = compareLE(left, right) - or - instr instanceof CompareGEInstruction and result = compareGE(left, right) - ) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll deleted file mode 100644 index 53f9295be4f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ /dev/null @@ -1,11 +0,0 @@ -private import internal.ConstantAnalysisInternal -private import experimental.ir.internal.IntegerConstant -private import ConstantAnalysis -import IR - -private class ConstantAnalysisPropertyProvider extends IRPropertyProvider { - override string getInstructionProperty(Instruction instr, string key) { - key = "ConstantValue" and - result = getValue(getConstantValue(instr)).toString() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll deleted file mode 100644 index c70b240fe42..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll deleted file mode 100644 index a7fb1b3c07e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll +++ /dev/null @@ -1,17 +0,0 @@ -private import internal.ValueNumberingImports -private import ValueNumbering - -/** - * Provides additional information about value numbering in IR dumps. - */ -class ValueNumberPropertyProvider extends IRPropertyProvider { - override string getInstructionProperty(Instruction instr, string key) { - exists(ValueNumber vn | - vn = valueNumber(instr) and - key = "valnum" and - if strictcount(vn.getAnInstruction()) > 1 - then result = vn.getDebugString() - else result = "unique" - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll deleted file mode 100644 index 2a46e16c52f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ /dev/null @@ -1,90 +0,0 @@ -private import internal.ValueNumberingInternal -private import internal.ValueNumberingImports - -/** - * The value number assigned to a particular set of instructions that produce equivalent results. - */ -class ValueNumber extends TValueNumber { - final string toString() { result = "GVN" } - - final string getDebugString() { - result = strictconcat(this.getAnInstruction().getResultId(), ", ") - } - - final Language::Location getLocation() { - if - exists(Instruction i | - i = this.getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation - ) - then - result = - min(Language::Location l | - l = this.getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation - | - l - order by - l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), - l.getEndColumn() - ) - else result instanceof Language::UnknownDefaultLocation - } - - /** - * Gets the instructions that have been assigned this value number. This will always produce at - * least one result. - */ - final Instruction getAnInstruction() { this = valueNumber(result) } - - /** - * Gets one of the instructions that was assigned this value number. The chosen instruction is - * deterministic but arbitrary. Intended for use only in debugging. - */ - final Instruction getExampleInstruction() { - result = - min(Instruction instr | - instr = this.getAnInstruction() - | - instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() - ) - } - - /** - * Gets an `Operand` whose definition is exact and has this value number. - */ - final Operand getAUse() { this = valueNumber(result.getDef()) } - - final string getKind() { - this instanceof TVariableAddressValueNumber and result = "VariableAddress" - or - this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" - or - this instanceof TConstantValueNumber and result = "Constant" - or - this instanceof TStringConstantValueNumber and result = "StringConstant" - or - this instanceof TFieldAddressValueNumber and result = "FieldAddress" - or - this instanceof TBinaryValueNumber and result = "Binary" - or - this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic" - or - this instanceof TUnaryValueNumber and result = "Unary" - or - this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion" - or - this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap" - or - this instanceof TUniqueValueNumber and result = "Unique" - } -} - -/** - * Gets the value number assigned to `instr`, if any. Returns at most one result. - */ -ValueNumber valueNumber(Instruction instr) { result = tvalueNumber(instr) } - -/** - * Gets the value number assigned to the exact definition of `op`, if any. - * Returns at most one result. - */ -ValueNumber valueNumberOfOperand(Operand op) { result = tvalueNumberOfOperand(op) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll deleted file mode 100644 index 34bd754692d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.internal.Overlap -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll deleted file mode 100644 index ec003891774..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ /dev/null @@ -1,356 +0,0 @@ -private import ValueNumberingImports - -newtype TValueNumber = - TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { - variableAddressValueNumber(_, irFunc, ast) - } or - TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { - initializeParameterValueNumber(_, irFunc, var) - } or - TConstantValueNumber(IRFunction irFunc, IRType type, string value) { - constantValueNumber(_, irFunc, type, value) - } or - TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { - stringConstantValueNumber(_, irFunc, type, value) - } or - TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { - fieldAddressValueNumber(_, irFunc, field, objectAddress) - } or - TBinaryValueNumber( - IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand - ) { - binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand) - } or - TPointerArithmeticValueNumber( - IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand, - TValueNumber rightOperand - ) { - pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand) - } or - TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) { - unaryValueNumber(_, irFunc, opcode, operand) - } or - TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - TValueNumber operand - ) { - inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) - } or - TLoadTotalOverlapValueNumber( - IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand - ) { - loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand) - } or - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - -/** - * A `CopyInstruction` whose source operand's value is congruent to the definition of that source - * operand. - * For example: - * ``` - * Point p = { 1, 2 }; - * Point q = p; - * int a = p.x; - * ``` - * The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that - * definition because it accesses the exact same memory. - * The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not - * congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`. - */ -class CongruentCopyInstruction extends CopyInstruction { - CongruentCopyInstruction() { - this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap - } -} - -class LoadTotalOverlapInstruction extends LoadInstruction { - LoadTotalOverlapInstruction() { - this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap - } -} - -/** - * Holds if this library knows how to assign a value number to the specified instruction, other than - * a `unique` value number that is never shared by multiple instructions. - */ -private predicate numberableInstruction(Instruction instr) { - instr instanceof VariableAddressInstruction - or - instr instanceof InitializeParameterInstruction - or - instr instanceof ConstantInstruction - or - instr instanceof StringConstantInstruction - or - instr instanceof FieldAddressInstruction - or - instr instanceof BinaryInstruction - or - instr instanceof UnaryInstruction and not instr instanceof CopyInstruction - or - instr instanceof PointerArithmeticInstruction - or - instr instanceof CongruentCopyInstruction - or - instr instanceof LoadTotalOverlapInstruction -} - -private predicate filteredNumberableInstruction(Instruction instr) { - // count rather than strictcount to handle missing AST elements - // separate instanceof and inline casts to avoid failed casts with a count of 0 - instr instanceof VariableAddressInstruction and - count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1 - or - instr instanceof ConstantInstruction and - count(instr.getResultIRType()) != 1 - or - instr instanceof FieldAddressInstruction and - count(instr.(FieldAddressInstruction).getField()) != 1 - or - instr instanceof InheritanceConversionInstruction and - ( - count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or - count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1 - ) -} - -private predicate variableAddressValueNumber( - VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast -) { - instr.getEnclosingIRFunction() = irFunc and - // The underlying AST element is used as value-numbering key instead of the - // `IRVariable` to work around a problem where a variable or expression with - // multiple types gives rise to multiple `IRVariable`s. - unique( | | instr.getIRVariable().getAst()) = ast -} - -private predicate initializeParameterValueNumber( - InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var -) { - instr.getEnclosingIRFunction() = irFunc and - // The underlying AST element is used as value-numbering key instead of the - // `IRVariable` to work around a problem where a variable or expression with - // multiple types gives rise to multiple `IRVariable`s. - instr.getIRVariable().getAst() = var -} - -private predicate constantValueNumber( - ConstantInstruction instr, IRFunction irFunc, IRType type, string value -) { - instr.getEnclosingIRFunction() = irFunc and - unique( | | instr.getResultIRType()) = type and - instr.getValue() = value -} - -private predicate stringConstantValueNumber( - StringConstantInstruction instr, IRFunction irFunc, IRType type, string value -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and - instr.getValue().getValue() = value -} - -private predicate fieldAddressValueNumber( - FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, - TValueNumber objectAddress -) { - instr.getEnclosingIRFunction() = irFunc and - unique( | | instr.getField()) = field and - tvalueNumber(instr.getObjectAddress()) = objectAddress -} - -pragma[nomagic] -private predicate binaryValueNumber0( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, boolean isLeft, - TValueNumber valueNumber -) { - not instr instanceof PointerArithmeticInstruction and - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - ( - isLeft = true and - tvalueNumber(instr.getLeft()) = valueNumber - or - isLeft = false and - tvalueNumber(instr.getRight()) = valueNumber - ) -} - -private predicate binaryValueNumber( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, - TValueNumber rightOperand -) { - binaryValueNumber0(instr, irFunc, opcode, true, leftOperand) and - binaryValueNumber0(instr, irFunc, opcode, false, rightOperand) -} - -pragma[nomagic] -private predicate pointerArithmeticValueNumber0( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, - boolean isLeft, TValueNumber valueNumber -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - instr.getElementSize() = elementSize and - ( - isLeft = true and - tvalueNumber(instr.getLeft()) = valueNumber - or - isLeft = false and - tvalueNumber(instr.getRight()) = valueNumber - ) -} - -private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, - TValueNumber leftOperand, TValueNumber rightOperand -) { - pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, true, leftOperand) and - pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, false, rightOperand) -} - -private predicate unaryValueNumber( - UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand -) { - instr.getEnclosingIRFunction() = irFunc and - not instr instanceof InheritanceConversionInstruction and - not instr instanceof CopyInstruction and - not instr instanceof FieldAddressInstruction and - instr.getOpcode() = opcode and - tvalueNumber(instr.getUnary()) = operand -} - -private predicate inheritanceConversionValueNumber( - InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, - Language::Class baseClass, Language::Class derivedClass, TValueNumber operand -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getOpcode() = opcode and - tvalueNumber(instr.getUnary()) = operand and - unique( | | instr.getBaseClass()) = baseClass and - unique( | | instr.getDerivedClass()) = derivedClass -} - -pragma[nomagic] -private predicate loadTotalOverlapValueNumber0( - LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber, - boolean isAddress -) { - instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and - ( - isAddress = true and - tvalueNumberOfOperand(instr.getSourceAddressOperand()) = valueNumber - or - isAddress = false and - tvalueNumber(instr.getSourceValueOperand().getAnyDef()) = valueNumber - ) -} - -private predicate loadTotalOverlapValueNumber( - LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand, - TValueNumber operand -) { - loadTotalOverlapValueNumber0(instr, irFunc, type, operand, true) and - loadTotalOverlapValueNumber0(instr, irFunc, type, memOperand, false) -} - -/** - * Holds if `instr` should be assigned a unique value number because this library does not know how - * to determine if two instances of that instruction are equivalent. - */ -private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc and - not instr.getResultIRType() instanceof IRVoidType and - ( - not numberableInstruction(instr) - or - filteredNumberableInstruction(instr) - ) -} - -/** - * Gets the value number assigned to `instr`, if any. Returns at most one result. - */ -cached -TValueNumber tvalueNumber(Instruction instr) { - result = nonUniqueValueNumber(instr) - or - exists(IRFunction irFunc | - uniqueValueNumber(instr, irFunc) and - result = TUniqueValueNumber(irFunc, instr) - ) -} - -/** - * Gets the value number assigned to the exact definition of `op`, if any. - * Returns at most one result. - */ -TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) } - -/** - * Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique - * value number. - */ -private TValueNumber nonUniqueValueNumber(Instruction instr) { - exists(IRFunction irFunc | - irFunc = instr.getEnclosingIRFunction() and - ( - exists(Language::AST ast | - variableAddressValueNumber(instr, irFunc, ast) and - result = TVariableAddressValueNumber(irFunc, ast) - ) - or - exists(Language::AST var | - initializeParameterValueNumber(instr, irFunc, var) and - result = TInitializeParameterValueNumber(irFunc, var) - ) - or - exists(string value, IRType type | - constantValueNumber(instr, irFunc, type, value) and - result = TConstantValueNumber(irFunc, type, value) - ) - or - exists(IRType type, string value | - stringConstantValueNumber(instr, irFunc, type, value) and - result = TStringConstantValueNumber(irFunc, type, value) - ) - or - exists(Language::Field field, TValueNumber objectAddress | - fieldAddressValueNumber(instr, irFunc, field, objectAddress) and - result = TFieldAddressValueNumber(irFunc, field, objectAddress) - ) - or - exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand | - binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and - result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand) - ) - or - exists(Opcode opcode, TValueNumber operand | - unaryValueNumber(instr, irFunc, opcode, operand) and - result = TUnaryValueNumber(irFunc, opcode, operand) - ) - or - exists( - Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand - | - inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and - result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) - ) - or - exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand | - pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and - result = - TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand) - ) - or - exists(IRType type, TValueNumber memOperand, TValueNumber operand | - loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and - result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand) - ) - or - // The value number of a copy is just the value number of its source value. - result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll deleted file mode 100644 index 23a7c1e77fd..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ /dev/null @@ -1,474 +0,0 @@ -private import AliasAnalysisInternal -private import InputIR -private import AliasAnalysisImports - -private class IntValue = Ints::IntValue; - -/** - * If `instr` is a `SideEffectInstruction`, gets the primary `CallInstruction` that caused the side - * effect. If `instr` is a `CallInstruction`, gets that same `CallInstruction`. - */ -private CallInstruction getPrimaryCall(Instruction instr) { - result = instr - or - result = instr.(SideEffectInstruction).getPrimaryInstruction() -} - -/** - * Holds if `operand` serves as an input argument (or indirection) to `call`, in the position - * specified by `input`. - */ -private predicate isCallInput( - CallInstruction call, Operand operand, AliasModels::FunctionInput input -) { - call = getPrimaryCall(operand.getUse()) and - ( - exists(int index | - input.isParameterOrQualifierAddress(index) and - operand = call.getArgumentOperand(index) - ) - or - exists(int index, ReadSideEffectInstruction read | - input.isParameterDerefOrQualifierObject(index) and - read = call.getAParameterSideEffect(index) and - operand = read.getSideEffectOperand() - ) - ) -} - -/** - * Holds if `instr` serves as a return value or output argument indirection for `call`, in the - * position specified by `output`. - */ -private predicate isCallOutput( - CallInstruction call, Instruction instr, AliasModels::FunctionOutput output -) { - call = getPrimaryCall(instr) and - ( - output.isReturnValue() and instr = call - or - exists(int index, WriteSideEffectInstruction write | - output.isParameterDerefOrQualifierObject(index) and - write = call.getAParameterSideEffect(index) and - instr = write - ) - ) -} - -/** - * Holds if the address in `operand` flows directly to the result of `resultInstr` due to modeled - * address flow through a function call. - */ -private predicate hasAddressFlowThroughCall(Operand operand, Instruction resultInstr) { - exists( - CallInstruction call, AliasModels::FunctionInput input, AliasModels::FunctionOutput output - | - call.getStaticCallTarget().(AliasModels::AliasFunction).hasAddressFlow(input, output) and - isCallInput(call, operand, input) and - isCallOutput(call, resultInstr, output) - ) -} - -/** - * Holds if the operand `tag` of instruction `instr` is used in a way that does - * not result in any address held in that operand from escaping beyond the - * instruction. - */ -private predicate operandIsConsumedWithoutEscaping(Operand operand) { - // The source/destination address of a Load/Store does not escape (but the - // loaded/stored value could). - operand instanceof AddressOperand - or - exists(Instruction instr | - instr = operand.getUse() and - ( - // Neither operand of a Compare escapes. - instr instanceof CompareInstruction - or - // Neither operand of a PointerDiff escapes. - instr instanceof PointerDiffInstruction - or - // Converting an address to a `bool` does not escape the address. - instr.(ConvertInstruction).getResultIRType() instanceof IRBooleanType - or - instr instanceof CallInstruction and - not exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis()) - ) - ) - or - // Some standard function arguments never escape - isNeverEscapesArgument(operand) -} - -private predicate operandEscapesDomain(Operand operand) { - not operandIsConsumedWithoutEscaping(operand) and - not operandIsPropagated(operand, _, _) and - not isArgumentForParameter(_, operand, _) and - not isOnlyEscapesViaReturnArgument(operand) and - not operand.getUse() instanceof ReturnValueInstruction and - not operand.getUse() instanceof ReturnIndirectionInstruction and - not operand instanceof PhiInputOperand -} - -/** - * If the result of instruction `instr` is an integer constant, returns the - * value of that constant. Otherwise, returns unknown. - */ -IntValue getConstantValue(Instruction instr) { - if instr instanceof IntegerConstantInstruction - then result = instr.(IntegerConstantInstruction).getValue().toInt() - else result = Ints::unknown() -} - -/** - * Computes the offset, in bits, by which the result of `instr` differs from the - * pointer argument to `instr`, if that offset is a constant. Otherwise, returns - * unknown. - */ -IntValue getPointerBitOffset(PointerOffsetInstruction instr) { - exists(IntValue bitOffset | - bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRight()), instr.getElementSize()), 8) and - ( - instr instanceof PointerAddInstruction and result = bitOffset - or - instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset) - ) - ) -} - -/** - * Holds if any address held in operand `operand` is propagated to the result of `instr`, offset by - * the number of bits in `bitOffset`. If the address is propagated, but the offset is not known to - * be a constant, then `bitOffset` is `unknown()`. - */ -private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instruction instr) { - // Some functions are known to propagate an argument - hasAddressFlowThroughCall(operand, instr) and - bitOffset = 0 - or - instr = operand.getUse() and - ( - // Converting to a non-virtual base class adds the offset of the base class. - exists(ConvertToNonVirtualBaseInstruction convert | - convert = instr and - bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) - ) - or - // Conversion using dynamic_cast results in an unknown offset - instr instanceof CheckedConvertOrNullInstruction and - bitOffset = Ints::unknown() - or - // Converting to a derived class subtracts the offset of the base class. - exists(ConvertToDerivedInstruction convert | - convert = instr and - bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8)) - ) - or - // Converting to a virtual base class adds an unknown offset. - instr instanceof ConvertToVirtualBaseInstruction and - bitOffset = Ints::unknown() - or - // Conversion to another pointer type propagates the source address. - exists(ConvertInstruction convert, IRType resultType | - convert = instr and - resultType = convert.getResultIRType() and - resultType instanceof IRAddressType and - bitOffset = 0 - ) - or - // Adding an integer to or subtracting an integer from a pointer propagates - // the address with an offset. - exists(PointerOffsetInstruction ptrOffset | - ptrOffset = instr and - operand = ptrOffset.getLeftOperand() and - bitOffset = getPointerBitOffset(ptrOffset) - ) - or - // Computing a field address from a pointer propagates the address plus the - // offset of the field. - bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField()) - or - // A copy propagates the source value. - operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 - ) -} - -private predicate operandEscapesNonReturn(Operand operand) { - exists(Instruction instr | - // The address is propagated to the result of the instruction, and that result itself is returned - operandIsPropagated(operand, _, instr) and resultEscapesNonReturn(instr) - ) - or - // The operand is used in a function call which returns it, and the return value is then returned - exists(CallInstruction ci, Instruction init | - isArgumentForParameter(ci, operand, init) and - ( - resultMayReachReturn(init) and - resultEscapesNonReturn(ci) - or - resultEscapesNonReturn(init) - ) - ) - or - isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) - or - operand instanceof PhiInputOperand and - resultEscapesNonReturn(operand.getUse()) - or - operandEscapesDomain(operand) -} - -private predicate operandMayReachReturn(Operand operand) { - exists(Instruction instr | - // The address is propagated to the result of the instruction, and that result itself is returned - operandIsPropagated(operand, _, instr) and - resultMayReachReturn(instr) - ) - or - // The operand is used in a function call which returns it, and the return value is then returned - exists(CallInstruction ci, Instruction init | - isArgumentForParameter(ci, operand, init) and - resultMayReachReturn(init) and - resultMayReachReturn(ci) - ) - or - // The address is returned - operand.getUse() instanceof ReturnValueInstruction - or - isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) - or - operand instanceof PhiInputOperand and - resultMayReachReturn(operand.getUse()) -} - -private predicate operandReturned(Operand operand, IntValue bitOffset) { - // The address is propagated to the result of the instruction, and that result itself is returned - exists(Instruction instr, IntValue bitOffset1, IntValue bitOffset2 | - operandIsPropagated(operand, bitOffset1, instr) and - resultReturned(instr, bitOffset2) and - bitOffset = Ints::add(bitOffset1, bitOffset2) - ) - or - // The operand is used in a function call which returns it, and the return value is then returned - exists(CallInstruction ci, Instruction init, IntValue bitOffset1, IntValue bitOffset2 | - isArgumentForParameter(ci, operand, init) and - resultReturned(init, bitOffset1) and - resultReturned(ci, bitOffset2) and - bitOffset = Ints::add(bitOffset1, bitOffset2) - ) - or - // The address is returned - operand.getUse() instanceof ReturnValueInstruction and - bitOffset = 0 - or - isOnlyEscapesViaReturnArgument(operand) and - resultReturned(operand.getUse(), _) and - bitOffset = Ints::unknown() -} - -pragma[nomagic] -private predicate initializeParameterInstructionHasVariable( - IRVariable var, InitializeParameterInstruction init -) { - init.getIRVariable() = var -} - -private predicate instructionInitializesThisInFunction( - Language::Function f, InitializeParameterInstruction init -) { - initializeParameterInstructionHasVariable(any(IRThisVariable var), pragma[only_bind_into](init)) and - init.getEnclosingFunction() = f -} - -private predicate isArgumentForParameter( - CallInstruction ci, Operand operand, InitializeParameterInstruction init -) { - exists(Language::Function f | - ci = operand.getUse() and - f = ci.getStaticCallTarget() and - ( - init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) - or - instructionInitializesThisInFunction(f, init) and - operand instanceof ThisArgumentOperand - ) and - not Language::isFunctionVirtual(f) and - not f instanceof AliasModels::AliasFunction - ) -} - -private predicate isOnlyEscapesViaReturnArgument(Operand operand) { - exists(AliasModels::AliasFunction f | - f = operand.getUse().(CallInstruction).getStaticCallTarget() and - ( - f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex()) - or - f.parameterEscapesOnlyViaReturn(-1) and - operand instanceof ThisArgumentOperand - ) - ) -} - -private predicate isNeverEscapesArgument(Operand operand) { - exists(AliasModels::AliasFunction f | - f = operand.getUse().(CallInstruction).getStaticCallTarget() and - ( - f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex()) - or - f.parameterNeverEscapes(-1) and - operand instanceof ThisArgumentOperand - ) - ) -} - -private predicate resultReturned(Instruction instr, IntValue bitOffset) { - operandReturned(instr.getAUse(), bitOffset) -} - -private predicate resultMayReachReturn(Instruction instr) { operandMayReachReturn(instr.getAUse()) } - -/** - * Holds if any address held in the result of instruction `instr` escapes - * outside the domain of the analysis. - */ -private predicate resultEscapesNonReturn(Instruction instr) { - // The result escapes if it has at least one use that escapes. - operandEscapesNonReturn(instr.getAUse()) - or - // The result also escapes if it is not modeled in SSA, because we do not know where it might be - // used. - not instr.isResultModeled() -} - -/** - * Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur - * either because the allocation's address is taken within the function and escapes, or because the - * allocation is marked as always escaping via `alwaysEscapes()`. - */ -predicate allocationEscapes(Configuration::Allocation allocation) { - allocation.alwaysEscapes() - or - exists(IREscapeAnalysisConfiguration config | - config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction()) - ) - or - Configuration::phaseNeedsSoundEscapeAnalysis() and - resultEscapesNonReturn(allocation.getABaseInstruction()) -} - -/** - * Equivalent to `operandIsPropagated()`, but includes interprocedural propagation. - */ -private predicate operandIsPropagatedIncludingByCall( - Operand operand, IntValue bitOffset, Instruction instr -) { - operandIsPropagated(operand, bitOffset, instr) - or - exists(CallInstruction call, Instruction init | - isArgumentForParameter(call, operand, init) and - resultReturned(init, bitOffset) and - instr = call - ) -} - -/** - * Holds if `addrOperand` is at offset `bitOffset` from the value of instruction `base`. The offset - * may be `unknown()`. - */ -private predicate hasBaseAndOffset(AddressOperand addrOperand, Instruction base, IntValue bitOffset) { - base = addrOperand.getDef() and bitOffset = 0 // Base case - or - exists( - Instruction middle, int previousBitOffset, Operand middleOperand, IntValue additionalBitOffset - | - // We already have an offset from `middle`. - hasBaseAndOffset(addrOperand, middle, previousBitOffset) and - // `middle` is propagated from `base`. - operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset, middle) and - base = middleOperand.getDef() and - bitOffset = Ints::add(previousBitOffset, additionalBitOffset) - ) -} - -/** - * Holds if `addrOperand` is at constant offset `bitOffset` from the value of instruction `base`. - * Only holds for the `base` with the longest chain of propagation to `addrOperand`. - */ -predicate addressOperandBaseAndConstantOffset( - AddressOperand addrOperand, Instruction base, int bitOffset -) { - hasBaseAndOffset(addrOperand, base, bitOffset) and - Ints::hasValue(bitOffset) and - not exists(Instruction previousBase, int previousBitOffset | - hasBaseAndOffset(addrOperand, previousBase, previousBitOffset) and - previousBase = base.getAnOperand().getDef() and - Ints::hasValue(previousBitOffset) - ) -} - -/** - * Gets the allocation into which `addrOperand` points, if known. - */ -Configuration::Allocation getAddressOperandAllocation(AddressOperand addrOperand) { - addressOperandAllocationAndOffset(addrOperand, result, _) -} - -/** - * Holds if `addrOperand` is at offset `bitOffset` from a base instruction of `allocation`. The - * offset may be `unknown()`. - */ -predicate addressOperandAllocationAndOffset( - AddressOperand addrOperand, Configuration::Allocation allocation, IntValue bitOffset -) { - exists(Instruction base | - allocation.getABaseInstruction() = base and - hasBaseAndOffset(addrOperand, base, bitOffset) and - not exists(Instruction previousBase | - hasBaseAndOffset(addrOperand, pragma[only_bind_out](previousBase), _) and - previousBase = base.getAnOperand().getDef() - ) - ) -} - -/** - * Predicates used only for printing annotated IR dumps. These should not be used in production - * queries. - */ -module Print { - string getOperandProperty(Operand operand, string key) { - key = "alloc" and - result = - strictconcat(Configuration::Allocation allocation, IntValue bitOffset | - addressOperandAllocationAndOffset(operand, allocation, bitOffset) - | - allocation.toString() + Ints::getBitOffsetString(bitOffset), ", " - ) - or - key = "prop" and - result = - strictconcat(Instruction destInstr, IntValue bitOffset, string value | - operandIsPropagatedIncludingByCall(operand, bitOffset, destInstr) and - if destInstr = operand.getUse() - then value = "@" + Ints::getBitOffsetString(bitOffset) + "->result" - else value = "@" + Ints::getBitOffsetString(bitOffset) + "->" + destInstr.getResultId() - | - value, ", " - ) - } - - string getInstructionProperty(Instruction instr, string key) { - key = "prop" and - result = - strictconcat(IntValue bitOffset, Operand sourceOperand, string value | - operandIsPropagatedIncludingByCall(sourceOperand, bitOffset, instr) and - if instr = sourceOperand.getUse() - then value = sourceOperand.getDumpId() + Ints::getBitOffsetString(bitOffset) + "->@" - else - value = - sourceOperand.getUse().getResultId() + "." + sourceOperand.getDumpId() + - Ints::getBitOffsetString(bitOffset) + "->@" - | - value, ", " - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll deleted file mode 100644 index 78dcdc95af0..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ /dev/null @@ -1,269 +0,0 @@ -private import csharp -import experimental.ir.implementation.IRConfiguration -import experimental.ir.internal.IntegerConstant as Ints - -module AliasModels { - class ParameterIndex = int; - - /** - * An input to a function. This can be: - * - The value of one of the function's parameters - * - The value pointed to by one of function's pointer or reference parameters - * - The value of the function's `this` pointer - * - The value pointed to by the function's `this` pointer - */ - abstract class FunctionInput extends string { - FunctionInput() { none() } - - /** - * Holds if this is the input value of the parameter with index `index`. - * - * Example: - * ``` - * void func(int n, char* p, float& r); - * ``` - * - `isParameter(0)` holds for the `FunctionInput` that represents the value of `n` (with type - * `int`) on entry to the function. - * - `isParameter(1)` holds for the `FunctionInput` that represents the value of `p` (with type - * `char*`) on entry to the function. - * - `isParameter(2)` holds for the `FunctionInput` that represents the "value" of the reference - * `r` (with type `float&`) on entry to the function, _not_ the value of the referred-to - * `float`. - */ - predicate isParameter(ParameterIndex index) { none() } - - /** - * Holds if this is the input value pointed to by a pointer parameter to a function, or the input - * value referred to by a reference parameter to a function, where the parameter has index - * `index`. - * - * Example: - * ``` - * void func(int n, char* p, float& r); - * ``` - * - `isParameterDeref(1)` holds for the `FunctionInput` that represents the value of `*p` (with - * type `char`) on entry to the function. - * - `isParameterDeref(2)` holds for the `FunctionInput` that represents the value of `r` (with type - * `float`) on entry to the function. - * - There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a - * pointer nor a reference. - */ - predicate isParameterDeref(ParameterIndex index) { none() } - - /** - * Holds if this is the input value pointed to by the `this` pointer of an instance member - * function. - * - * Example: - * ``` - * struct C { - * void mfunc(int n, char* p, float& r) const; - * }; - * ``` - * - `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` - * (with type `C const`) on entry to the function. - */ - predicate isQualifierObject() { none() } - - /** - * Holds if this is the input value of the `this` pointer of an instance member function. - * - * Example: - * ``` - * struct C { - * void mfunc(int n, char* p, float& r) const; - * }; - * ``` - * - `isQualifierAddress()` holds for the `FunctionInput` that represents the value of `this` - * (with type `C const *`) on entry to the function. - */ - predicate isQualifierAddress() { none() } - - /** - * Holds if `i >= 0` and `isParameter(i)` holds for this value, or - * if `i = -1` and `isQualifierAddress()` holds for this value. - */ - final predicate isParameterOrQualifierAddress(ParameterIndex i) { - i >= 0 and this.isParameter(i) - or - i = -1 and this.isQualifierAddress() - } - - /** - * Holds if this is the input value pointed to by the return value of a - * function, if the function returns a pointer, or the input value referred - * to by the return value of a function, if the function returns a reference. - * - * Example: - * ``` - * char* getPointer(); - * float& getReference(); - * int getInt(); - * ``` - * - `isReturnValueDeref()` holds for the `FunctionInput` that represents the - * value of `*getPointer()` (with type `char`). - * - `isReturnValueDeref()` holds for the `FunctionInput` that represents the - * value of `getReference()` (with type `float`). - * - There is no `FunctionInput` of `getInt()` for which - * `isReturnValueDeref()` holds because the return type of `getInt()` is - * neither a pointer nor a reference. - * - * Note that data flows in through function return values are relatively - * rare, but they do occur when a function returns a reference to itself, - * part of itself, or one of its other inputs. - */ - predicate isReturnValueDeref() { none() } - - /** - * Holds if `i >= 0` and `isParameterDeref(i)` holds for this value, or - * if `i = -1` and `isQualifierObject()` holds for this value. - */ - final predicate isParameterDerefOrQualifierObject(ParameterIndex i) { - i >= 0 and this.isParameterDeref(i) - or - i = -1 and this.isQualifierObject() - } - } - - /** - * An output from a function. This can be: - * - The value pointed to by one of function's pointer or reference parameters - * - The value pointed to by the function's `this` pointer - * - The function's return value - * - The value pointed to by the function's return value, if the return value is a pointer or - * reference - */ - abstract class FunctionOutput extends string { - FunctionOutput() { none() } - - /** - * Holds if this is the output value pointed to by a pointer parameter to a function, or the - * output value referred to by a reference parameter to a function, where the parameter has - * index `index`. - * - * Example: - * ``` - * void func(int n, char* p, float& r); - * ``` - * - `isParameterDeref(1)` holds for the `FunctionOutput` that represents the value of `*p` (with - * type `char`) on return from the function. - * - `isParameterDeref(2)` holds for the `FunctionOutput` that represents the value of `r` (with - * type `float`) on return from the function. - * - There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a - * pointer nor a reference. - */ - predicate isParameterDeref(ParameterIndex index) { none() } - - /** - * Holds if this is the output value pointed to by the `this` pointer of an instance member - * function. - * - * Example: - * ``` - * struct C { - * void mfunc(int n, char* p, float& r); - * }; - * ``` - * - `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` - * (with type `C`) on return from the function. - */ - predicate isQualifierObject() { none() } - - /** - * Holds if this is the value returned by a function. - * - * Example: - * ``` - * int getInt(); - * char* getPointer(); - * float& getReference(); - * ``` - * - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by - * `getInt()` (with type `int`). - * - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by - * `getPointer()` (with type `char*`). - * - `isReturnValue()` holds for the `FunctionOutput` that represents the "value" of the reference - * returned by `getReference()` (with type `float&`), _not_ the value of the referred-to - * `float`. - */ - predicate isReturnValue() { none() } - - /** - * Holds if this is the output value pointed to by the return value of a function, if the function - * returns a pointer, or the output value referred to by the return value of a function, if the - * function returns a reference. - * - * Example: - * ``` - * char* getPointer(); - * float& getReference(); - * int getInt(); - * ``` - * - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of - * `*getPointer()` (with type `char`). - * - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of - * `getReference()` (with type `float`). - * - There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the - * return type of `getInt()` is neither a pointer nor a reference. - */ - predicate isReturnValueDeref() { none() } - - /** - * Holds if `i >= 0` and `isParameterDeref(i)` holds for this is the value, or - * if `i = -1` and `isQualifierObject()` holds for this value. - */ - final predicate isParameterDerefOrQualifierObject(ParameterIndex i) { - i >= 0 and this.isParameterDeref(i) - or - i = -1 and this.isQualifierObject() - } - } - - /** - * Models the aliasing behavior of a library function. - */ - abstract class AliasFunction extends Callable { - /** - * Holds if the address passed to the parameter at the specified index is never retained after - * the function returns. - * - * Example: - * ```csharp - * int* g; - * int* func(int* p, int* q, int* r, int* s, int n) { - * *s = 1; // `s` does not escape. - * g = p; // Stored in global. `p` escapes. - * if (rand()) { - * return q; // `q` escapes via the return value. - * } - * else { - * return r + n; // `r` escapes via the return value, even though an offset has been added. - * } - * } - * ``` - * - * For the above function, the following terms hold: - * - `parameterEscapesOnlyViaReturn(1)` - * - `parameterEscapesOnlyViaReturn(2)` - * - `parameterNeverEscapes(3)` - */ - abstract predicate parameterNeverEscapes(int index); - - /** - * Holds if the address passed to the parameter at the specified index escapes via the return - * value of the function, but does not otherwise escape. See the comment for - * `parameterNeverEscapes` for an example. - */ - abstract predicate parameterEscapesOnlyViaReturn(int index); - - /** - * Holds if the function always returns the value of the parameter at the specified index. - */ - abstract predicate parameterIsAlwaysReturned(int index); - - /** - * Holds if the address passed in via `input` is always propagated to `output`. - */ - abstract predicate hasAddressFlow(FunctionInput input, FunctionOutput output); - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll deleted file mode 100644 index f3f2d14ab43..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import experimental.ir.implementation.raw.IR as InputIR -import AliasConfiguration as Configuration diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll deleted file mode 100644 index 110e673e1d2..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll +++ /dev/null @@ -1,18 +0,0 @@ -private import AliasConfigurationImports - -/** - * A memory allocation that can be tracked by the SimpleSSA alias analysis. - * All automatic variables are tracked. - */ -class Allocation extends IRAutomaticVariable { - VariableAddressInstruction getABaseInstruction() { result.getIRVariable() = this } - - final string getAllocationString() { result = this.toString() } - - predicate alwaysEscapes() { - // An automatic variable only escapes if its address is taken and escapes. - none() - } -} - -predicate phaseNeedsSoundEscapeAnalysis() { any() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll deleted file mode 100644 index fc29c0d77dd..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.raw.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll deleted file mode 100644 index c80761a68cf..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRConsistencyImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRConsistencyImports.qll deleted file mode 100644 index f43546fe76d..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRConsistencyImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguageDebug as LanguageDebug diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll deleted file mode 100644 index 4e9a7d9f3ae..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll deleted file mode 100644 index 14dad7400b2..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll deleted file mode 100644 index eaf33e0800f..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ /dev/null @@ -1,4 +0,0 @@ -import experimental.ir.internal.IRCSharpLanguage as Language -import SSAConstruction as Construction -import experimental.ir.implementation.IRConfiguration as IRConfiguration -import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll deleted file mode 100644 index bdb4377cbdc..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.TempVariableTag as TempVariableTag -import experimental.ir.internal.IRUtilities as IRUtilities -import experimental.ir.internal.TempVariableTag as TTempVariableTag -import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll deleted file mode 100644 index 4bcd2e127c1..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ /dev/null @@ -1,6 +0,0 @@ -import experimental.ir.implementation.EdgeKind as EdgeKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind -import experimental.ir.implementation.Opcode as Opcode -import experimental.ir.implementation.internal.OperandTag as OperandTag -import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll deleted file mode 100644 index 65676caf724..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind -import experimental.ir.implementation.IRType as IRType -import experimental.ir.internal.Overlap as Overlap -import experimental.ir.implementation.internal.OperandTag as OperandTag -import experimental.ir.implementation.internal.TOperand as TOperand diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll deleted file mode 100644 index e522599abe9..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -private import experimental.ir.implementation.internal.TOperand -import UnaliasedSsaOperands diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll deleted file mode 100644 index 0c5337d57de..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.IRConfiguration as IRConfiguration -import experimental.ir.internal.IRCSharpLanguageDebug as LanguageDebug diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll deleted file mode 100644 index c7487872512..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ /dev/null @@ -1,157 +0,0 @@ -private import SSAConstructionInternal -private import OldIR -private import Alias -private import SSAConstruction -private import DebugSsa - -bindingset[offset] -private string getKeySuffixForOffset(int offset) { - offset >= 0 and - if offset % 2 = 0 then result = "" else result = "_Chi" -} - -bindingset[offset] -private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } - -/** - * Property provide that dumps the memory access of each result. Useful for debugging SSA - * construction. - */ -class PropertyProvider extends IRPropertyProvider { - override string getInstructionProperty(Instruction instruction, string key) { - key = "ResultMemoryLocation" and - result = - strictconcat(MemoryLocation loc | - loc = getResultMemoryLocation(instruction) - | - loc.toString(), "," - ) - or - key = "ResultVirtualVariable" and - result = - strictconcat(MemoryLocation loc | - loc = getResultMemoryLocation(instruction) - | - loc.getVirtualVariable().toString(), "," - ) - or - key = "OperandMemoryLocation" and - result = - strictconcat(MemoryLocation loc | - loc = getOperandMemoryLocation(instruction.getAnOperand()) - | - loc.toString(), "," - ) - or - key = "OperandVirtualVariable" and - result = - strictconcat(MemoryLocation loc | - loc = getOperandMemoryLocation(instruction.getAnOperand()) - | - loc.getVirtualVariable().toString(), "," - ) - or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and - defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and - key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and - result = defRank.toString() - ) - or - exists(MemoryLocation useLocation, IRBlock useBlock, int useRank | - hasUseAtRank(useLocation, useBlock, useRank, instruction) and - key = "UseRank[" + useLocation.toString() + "]" and - result = useRank.toString() - ) - or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and - defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and - key = - "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + - "]" and - result = - strictconcat(IRBlock useBlock, int useRank, int useIndex | - exists(Instruction useInstruction | - hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and - useBlock.getInstruction(useIndex) = useInstruction and - definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) - ) - | - useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " - order by - useBlock.getDisplayIndex(), useIndex - ) - ) - } - - override string getBlockProperty(IRBlock block, string key) { - exists(MemoryLocation useLocation, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, block, defRank, defIndex) and - defIndex = -1 and - key = "DefinitionRank(Phi)[" + useLocation.toString() + "]" and - result = defRank.toString() - ) - or - exists(MemoryLocation useLocation, MemoryLocation defLocation, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, defLocation, block, defRank, defIndex) and - defIndex = -1 and - key = "DefinitionReachesUse(Phi)[" + useLocation.toString() + "]" and - result = - strictconcat(IRBlock useBlock, int useRank, int useIndex | - exists(Instruction useInstruction | - hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and - useBlock.getInstruction(useIndex) = useInstruction and - definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and - exists(getOverlap(defLocation, useLocation)) - ) - | - useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " - order by - useBlock.getDisplayIndex(), useIndex - ) - ) - or - exists( - MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap - | - hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex) and - key = - "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() + "]" and - result = - defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() + ")" - ) - or - key = "LiveOnEntry" and - result = - strictconcat(MemoryLocation useLocation | - locationLiveOnEntryToBlock(useLocation, block) - | - useLocation.toString(), ", " order by useLocation.toString() - ) - or - key = "LiveOnExit" and - result = - strictconcat(MemoryLocation useLocation | - locationLiveOnExitFromBlock(useLocation, block) - | - useLocation.toString(), ", " order by useLocation.toString() - ) - or - key = "DefsLiveOnEntry" and - result = - strictconcat(MemoryLocation defLocation | - definitionLiveOnEntryToBlock(defLocation, block) - | - defLocation.toString(), ", " order by defLocation.toString() - ) - or - key = "DefsLiveOnExit" and - result = - strictconcat(MemoryLocation defLocation | - definitionLiveOnExitFromBlock(defLocation, block) - | - defLocation.toString(), ", " order by defLocation.toString() - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql deleted file mode 100644 index d4d8e29fb31..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Unaliased SSA Consistency Check - * @description Performs consistency checks on the SSA construction. This query should have no results. - * @kind table - * @id cs/unaliased-ssa-consistency-check - */ - -import SSAConsistency diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll deleted file mode 100644 index 0fb108f0b56..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll +++ /dev/null @@ -1,55 +0,0 @@ -import SsaConsistency -import SSAConsistencyImports - -module SsaConsistency { - /** - * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. - */ - query predicate multipleOperandMemoryLocations( - OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText - ) { - exists(int locationCount | - locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and - locationCount > 1 and - func = operand.getEnclosingIRFunction() and - funcText = LanguageDebug::getIdentityString(func.getFunction()) and - message = - operand.getUse().toString() + " " + "Operand has " + locationCount.toString() + - " memory accesses in function '$@': " + - strictconcat(Alias::getOperandMemoryLocation(operand).toString(), ", ") - ) - } - - /** - * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. - */ - query predicate missingVirtualVariableForMemoryLocation( - Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText - ) { - not exists(location.getVirtualVariable()) and - func = location.getIRFunction() and - funcText = LanguageDebug::getIdentityString(func.getFunction()) and - message = "Memory location has no virtual variable in function '$@'." - } - - /** - * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. - */ - query predicate multipleVirtualVariablesForMemoryLocation( - Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText - ) { - exists(int vvarCount | - vvarCount = strictcount(location.getVirtualVariable()) and - vvarCount > 1 and - func = location.getIRFunction() and - funcText = LanguageDebug::getIdentityString(func.getFunction()) and - message = - "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + - concat(Alias::VirtualVariable vvar | - vvar = location.getVirtualVariable() - | - vvar.toString(), ", " - ) + ")." - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistencyImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistencyImports.qll deleted file mode 100644 index 70b803a818e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistencyImports.qll +++ /dev/null @@ -1,3 +0,0 @@ -import experimental.ir.implementation.raw.IR as OldIR -import SimpleSSA as Alias -import experimental.ir.internal.IRCSharpLanguageDebug as LanguageDebug diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll deleted file mode 100644 index 209c42726b7..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ /dev/null @@ -1,1056 +0,0 @@ -import SSAConstructionInternal -private import SSAConstructionImports as Imports -private import Imports::Opcode -private import Imports::OperandTag -private import Imports::Overlap -private import Imports::TInstruction -private import Imports::RawIR as RawIR -private import SsaInstructions -private import SsaOperands -private import NewIR - -private class OldBlock = Reachability::ReachableBlock; - -private class OldInstruction = Reachability::ReachableInstruction; - -import Cached - -cached -private module Cached { - cached - predicate hasPhiInstructionCached( - OldInstruction blockStartInstr, Alias::MemoryLocation defLocation - ) { - exists(OldBlock oldBlock | - definitionHasPhiNode(defLocation, oldBlock) and - blockStartInstr = oldBlock.getFirstInstruction() - ) - } - - cached - predicate hasChiInstructionCached(OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) - } - - cached - predicate hasUnreachedInstructionCached(IRFunction irFunc) { - exists(OldIR::Instruction oldInstruction | - irFunc = oldInstruction.getEnclosingIRFunction() and - ( - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - or - oldInstruction.getOpcode() instanceof Opcode::Unreached - ) - ) - } - - class TStageInstruction = - TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - - /** - * If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block, - * this predicate returns the `PhiInputOperand` corresponding to that predecessor block. - * Otherwise, this predicate does not hold. - */ - private OldIR::PhiInputOperand getDegeneratePhiOperand(OldInstruction oldInstruction) { - result = - unique(OldIR::PhiInputOperand operand | - operand = oldInstruction.(OldIR::PhiInstruction).getAnInputOperand() and - operand.getPredecessorBlock() instanceof OldBlock - ) - } - - cached - predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction and instr instanceof OldInstruction - or - instr = phiInstruction(_, _) - or - instr = reusedPhiInstruction(_) and - // Check that the phi instruction is *not* degenerate, but we can't use - // getDegeneratePhiOperand in the first stage with phi instructions - not exists( - unique(OldIR::PhiInputOperand operand | - operand = instr.(OldIR::PhiInstruction).getAnInputOperand() and - operand.getPredecessorBlock() instanceof OldBlock - ) - ) - or - instr instanceof TChiInstruction - or - instr instanceof TUnreachedInstruction - } - - cached - IRBlock getNewBlock(OldBlock oldBlock) { - exists(Instruction newEnd, OldIR::Instruction oldEnd | - ( - result.getLastInstruction() = newEnd and - not newEnd instanceof ChiInstruction - or - newEnd = result.getLastInstruction().(ChiInstruction).getAPredecessor() // does this work? - ) and - ( - oldBlock.getLastInstruction() = oldEnd and - not oldEnd instanceof OldIR::ChiInstruction - or - oldEnd = oldBlock.getLastInstruction().(OldIR::ChiInstruction).getAPredecessor() // does this work? - ) and - oldEnd = getNewInstruction(newEnd) - ) - } - - /** - * Gets the block from the old IR that corresponds to `newBlock`. - */ - private OldBlock getOldBlock(IRBlock newBlock) { getNewBlock(result) = newBlock } - - /** - * Holds if this iteration of SSA can model the def/use information for the result of - * `oldInstruction`, either because alias analysis has determined a memory location for that - * result, or because a previous iteration of the IR already computed that def/use information - * completely. - */ - private predicate canModelResultForOldInstruction(OldInstruction oldInstruction) { - // We're modeling the result's memory location ourselves. - exists(Alias::getResultMemoryLocation(oldInstruction)) - or - // This result was already modeled by a previous iteration of SSA. - Alias::canReuseSsaForOldResult(oldInstruction) - } - - cached - predicate hasModeledMemoryResult(Instruction instruction) { - canModelResultForOldInstruction(getOldInstruction(instruction)) or - instruction instanceof PhiInstruction or // Phis always have modeled results - instruction instanceof ChiInstruction // Chis always have modeled results - } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - or - // Chi instructions track virtual variables, and therefore a chi instruction is - // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | - Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof - Alias::AliasedVirtualVariable - ) - or - // Phi instructions track locations, and therefore a phi instruction is - // conflated if it's associated with a conflated location. - exists(Alias::MemoryLocation location | - instruction = getPhi(_, location) and - not exists(location.getAllocation()) - ) - } - - pragma[noopt] - private predicate hasMemoryOperandDefinition( - OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap, - Instruction instr - ) { - oldOperand = oldInstruction.getAnOperand() and - oldOperand instanceof OldIR::NonPhiMemoryOperand and - exists( - OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation, - Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, - Alias::MemoryLocation actualDefLocation - | - useLocation = Alias::getOperandMemoryLocation(oldOperand) and - hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and - definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and - hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and - instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and - overlap = Alias::getOverlap(actualDefLocation, useLocation) - ) - } - - /** - * Gets the new definition instruction for `oldOperand` based on `oldOperand`'s definition in the - * old IR. Usually, this will just get the old definition of `oldOperand` and map it to the - * corresponding new instruction. However, if the old definition of `oldOperand` is a `Phi` - * instruction that is now degenerate due all but one of its predecessor branches being - * unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the - * true definition. - */ - private Instruction getNewDefinitionFromOldSsa(OldIR::MemoryOperand oldOperand, Overlap overlap) { - exists(Overlap originalOverlap | - originalOverlap = oldOperand.getDefinitionOverlap() and - ( - result = getNewInstruction(oldOperand.getAnyDef()) and - overlap = originalOverlap - or - exists(OldIR::PhiInputOperand phiOperand, Overlap phiOperandOverlap | - phiOperand = getDegeneratePhiOperand(oldOperand.getAnyDef()) and - result = getNewDefinitionFromOldSsa(phiOperand, phiOperandOverlap) and - overlap = - combineOverlap(pragma[only_bind_out](phiOperandOverlap), - pragma[only_bind_out](originalOverlap)) - ) - ) - ) - } - - cached - private Instruction getMemoryOperandDefinition0( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand | - oldInstruction = getOldInstruction(instruction) and - oldOperand = oldInstruction.getAnOperand() and - tag = oldOperand.getOperandTag() and - hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - ) - or - instruction = getChi(getOldInstruction(result)) and - tag instanceof ChiPartialOperandTag and - overlap instanceof MustExactlyOverlap - or - tag instanceof ChiTotalOperandTag and - result = getChiInstructionTotalOperand(instruction) and - overlap instanceof MustExactlyOverlap - } - - cached - Instruction getMemoryOperandDefinition( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - // getMemoryOperandDefinition0 currently has a bug where it can match with multiple overlaps. - // This predicate ensures that the chosen overlap is the most conservative if there's any doubt. - result = getMemoryOperandDefinition0(instruction, tag, overlap) and - not ( - overlap instanceof MustExactlyOverlap and - exists(MustTotallyOverlap o | exists(getMemoryOperandDefinition0(instruction, tag, o))) - ) - or - exists(OldIR::NonPhiMemoryOperand oldOperand | - result = getNewDefinitionFromOldSsa(oldOperand, overlap) and - oldOperand.getUse() = instruction and - tag = oldOperand.getOperandTag() - ) - } - - /** - * Holds if `operand` totally overlaps with its definition and consumes the bit range - * `[startBitOffset, endBitOffset)`. - */ - cached - predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) { - exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand | - oldOperand = operand.getUse().(OldInstruction).getAnOperand() and - location = Alias::getOperandMemoryLocation(oldOperand) and - startBitOffset = Alias::getStartBitOffset(location) and - endBitOffset = Alias::getEndBitOffset(location) - ) - } - - /** - * Holds if the `ChiPartialOperand` only partially overlaps with the `ChiTotalOperand`. - * This means that the `ChiPartialOperand` will not override the entire memory associated - * with the `ChiTotalOperand`. - */ - cached - predicate chiOnlyPartiallyUpdatesLocation(ChiInstruction chi) { - exists(Alias::MemoryLocation location, OldInstruction oldInstruction | - oldInstruction = getOldInstruction(chi.getPartial()) and - location = Alias::getResultMemoryLocation(oldInstruction) - | - Alias::getStartBitOffset(location) != 0 or - Alias::getEndBitOffset(location) != 8 * location.getType().getByteSize() - ) - } - - /** - * Holds if `instr` is part of a cycle in the operand graph that doesn't go - * through a phi instruction and therefore should be impossible. - * - * For performance reasons, this predicate is not implemented (never holds) - * for the SSA stages of the IR. - */ - cached - predicate isInCycle(Instruction instr) { none() } - - cached - Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { - exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | - oldInstruction = getOldInstruction(instr) and - oldOperand = oldInstruction.getAnOperand() and - tag = oldOperand.getOperandTag() and - result = oldOperand.getLanguageType() - ) - } - - /** - * Gets the new definition instruction for the operand of `instr` that flows from the block - * `newPredecessorBlock`, based on that operand's definition in the old IR. - */ - private Instruction getNewPhiOperandDefinitionFromOldSsa( - Instruction instr, IRBlock newPredecessorBlock, Overlap overlap - ) { - exists(OldIR::PhiInstruction oldPhi, OldIR::PhiInputOperand oldOperand | - oldPhi = getOldInstruction(instr) and - oldOperand = oldPhi.getInputOperand(getOldBlock(newPredecessorBlock)) and - result = getNewDefinitionFromOldSsa(oldOperand, overlap) - ) - } - - pragma[noopt] - cached - Instruction getPhiOperandDefinition( - Instruction instr, IRBlock newPredecessorBlock, Overlap overlap - ) { - exists( - Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, - OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation - | - hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = getPhi(phiBlock, useLocation) and - newPredecessorBlock = getNewBlock(predBlock) and - result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and - overlap = Alias::getOverlap(actualDefLocation, useLocation) - ) - or - result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap) - } - - cached - Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) { - exists( - Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock, int defRank, - int defOffset, OldBlock useBlock, int useRank - | - chiInstr = getChi(oldInstr) and - vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and - hasDefinitionAtRank(vvar, _, defBlock, defRank, defOffset) and - hasUseAtRank(vvar, useBlock, useRank, oldInstr) and - definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and - result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _) - ) - } - - cached - Instruction getPhiInstructionBlockStart(PhiInstruction instr) { - exists(OldBlock oldBlock | - ( - instr = getPhi(oldBlock, _) - or - // Any `Phi` that we propagated from the previous iteration stays in the same block. - getOldInstruction(instr).getBlock() = oldBlock - ) and - result = getNewInstruction(oldBlock.getFirstInstruction()) - ) - } - - /* - * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, - * that node is its successor in the new successor relation, and the Chi node's successors are - * the new instructions generated from the successors of the old instruction - */ - - cached - Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { - if hasChiNode(_, getOldInstruction(instruction)) - then - result = getChi(getOldInstruction(instruction)) and - kind instanceof GotoEdge - else - exists(OldInstruction oldInstruction | - ( - oldInstruction = getOldInstruction(instruction) - or - instruction = getChi(oldInstruction) - ) and - ( - if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = unreachedInstruction(instruction.getEnclosingIRFunction()) - else result = getNewInstruction(oldInstruction.getSuccessor(kind)) - ) - ) - } - - cached - Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { - exists(OldInstruction oldInstruction | - not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and - // There is only one case for the translation into `result` because the - // SSA construction never inserts extra instructions _before_ an existing - // instruction. - getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and - // There are two cases for the translation into `instruction` because the - // SSA construction might have inserted a chi node _after_ - // `oldInstruction`, in which case the back edge should come out of the - // chi node instead. - if hasChiNode(_, oldInstruction) - then instruction = getChi(oldInstruction) - else instruction = getNewInstruction(oldInstruction) - ) - } - - cached - Language::AST getInstructionAst(Instruction instr) { - result = getOldInstruction(instr).getAst() - or - exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(blockStartInstr, _) and - result = blockStartInstr.getAst() - ) - or - exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(primaryInstr) and - result = primaryInstr.getAst() - ) - or - exists(IRFunctionBase irFunc | - instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() - ) - } - - cached - Language::LanguageType getInstructionResultType(Instruction instr) { - result = instr.(RawIR::Instruction).getResultLanguageType() - or - exists(Alias::MemoryLocation defLocation | - instr = phiInstruction(_, defLocation) and - result = defLocation.getType() - ) - or - exists(Instruction primaryInstr, Alias::VirtualVariable vvar | - instr = chiInstruction(primaryInstr) and - hasChiNode(vvar, primaryInstr) and - result = vvar.getType() - ) - or - instr = reusedPhiInstruction(_) and - result = instr.(OldInstruction).getResultLanguageType() - or - instr = unreachedInstruction(_) and result = Language::getVoidType() - } - - /** - * Holds if `opcode` is the opcode that specifies the operation performed by `instr`. - * - * The parameters are ordered such that they produce a clean join (with no need for reordering) - * in the characteristic predicates of the `Instruction` subclasses. - */ - cached - predicate getInstructionOpcode(Opcode opcode, Instruction instr) { - opcode = getOldInstruction(instr).getOpcode() - or - instr = phiInstruction(_, _) and opcode instanceof Opcode::Phi - or - instr = chiInstruction(_) and opcode instanceof Opcode::Chi - or - instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached - } - - cached - IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - result = getOldInstruction(instr).getEnclosingIRFunction() - or - exists(OldInstruction blockStartInstr | - instr = phiInstruction(blockStartInstr, _) and - result = blockStartInstr.getEnclosingIRFunction() - ) - or - exists(OldInstruction primaryInstr | - instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() - ) - or - instr = unreachedInstruction(result) - } - - cached - Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { - exists(OldIR::SideEffectInstruction oldInstruction | - oldInstruction = getOldInstruction(instruction) and - result = getNewInstruction(oldInstruction.getPrimaryInstruction()) - ) - or - exists(OldIR::Instruction oldInstruction | - instruction = getChi(oldInstruction) and - result = getNewInstruction(oldInstruction) - ) - } -} - -private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } - -private OldInstruction getOldInstruction(Instruction instr) { instr = result } - -private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } - -private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(defBlock.getFirstInstruction(), defLocation) -} - -/** - * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition - * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the - * original definition location is a member. - */ -private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) { - exists(Alias::MemoryLocation defLocation | - defLocation = Alias::getResultMemoryLocation(def) and - defLocation.getVirtualVariable() = vvar and - // If the definition totally (or exactly) overlaps the virtual variable, then there's no need for a `Chi` - // instruction. - Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap - ) -} - -private import PhiInsertion - -/** - * Module to handle insertion of `Phi` instructions at the correct blocks. We insert a `Phi` instruction at the - * beginning of a block for a given location when that block is on the dominance frontier of a definition of the - * location and there is a use of that location reachable from that block without an intervening definition of the - * location. - * Within the approach outlined above, we treat a location slightly differently depending on whether or not it is a - * virtual variable. For a virtual variable, we will insert a `Phi` instruction on the dominance frontier if there is - * a use of any member location of that virtual variable that is reachable from the `Phi` instruction. For a location - * that is not a virtual variable, we insert a `Phi` instruction only if there is an exactly-overlapping use of the - * location reachable from the `Phi` instruction. This ensures that we insert a `Phi` instruction for a non-virtual - * variable only if doing so would allow dataflow analysis to get a more precise result than if we just used a `Phi` - * instruction for the virtual variable as a whole. - */ -private module PhiInsertion { - /** - * Holds if `phiBlock` is a block in the dominance frontier of a block that has a definition of the - * memory location `defLocation`. - */ - pragma[noinline] - private predicate dominanceFrontierOfDefinition( - Alias::MemoryLocation defLocation, OldBlock phiBlock - ) { - exists(OldBlock defBlock | - phiBlock = Dominance::getDominanceFrontier(defBlock) and - definitionHasDefinitionInBlock(defLocation, defBlock) - ) - } - - /** - * Holds if a `Phi` instruction needs to be inserted for location `defLocation` at the beginning of block `phiBlock`. - */ - predicate definitionHasPhiNode(Alias::MemoryLocation defLocation, OldBlock phiBlock) { - dominanceFrontierOfDefinition(defLocation, phiBlock) and - /* We can also eliminate those nodes where the definition is not live on any incoming edge */ - definitionLiveOnEntryToBlock(defLocation, phiBlock) - } - - /** - * Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing - * instruction, a `Phi` node, or a `Chi` node. - */ - private predicate definitionHasDefinitionInBlock(Alias::MemoryLocation defLocation, OldBlock block) { - definitionHasPhiNode(defLocation, block) - or - exists(OldInstruction def, Alias::MemoryLocation resultLocation | - def.getBlock() = block and - resultLocation = Alias::getResultMemoryLocation(def) and - ( - defLocation = resultLocation - or - // For a virtual variable, any definition of a member location will either generate a `Chi` node that defines - // the virtual variable, or will totally overlap the virtual variable. Either way, treat this as a definition of - // the virtual variable. - defLocation = resultLocation.getVirtualVariable() - ) - ) - } - - /** - * Holds if there is a use at (`block`, `index`) that could consume the result of a `Phi` instruction for - * `defLocation`. - */ - private predicate definitionHasUse(Alias::MemoryLocation defLocation, OldBlock block, int index) { - exists(OldInstruction use | - block.getInstruction(index) = use and - if defLocation instanceof Alias::VirtualVariable - then ( - exists(Alias::MemoryLocation useLocation | - // For a virtual variable, any use of a location that is a member of the virtual variable counts as a use. - useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and - defLocation = useLocation.getVirtualVariable() - ) - or - // A `Chi` instruction consumes the enclosing virtual variable of its use location. - hasChiNode(defLocation, use) - ) else ( - // For other locations, only an exactly-overlapping use of the same location counts as a use. - defLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and - Alias::getOverlap(defLocation, defLocation) instanceof MustExactlyOverlap - ) - ) - } - - /** - * Holds if the location `defLocation` is redefined at (`block`, `index`). A location is considered "redefined" if - * there is a definition that would prevent a previous definition of `defLocation` from being consumed as the operand - * of a `Phi` node that occurs after the redefinition. - */ - private predicate definitionHasRedefinition( - Alias::MemoryLocation defLocation, OldBlock block, int index - ) { - exists(OldInstruction redef, Alias::MemoryLocation redefLocation | - block.getInstruction(index) = redef and - redefLocation = Alias::getResultMemoryLocation(redef) and - if defLocation instanceof Alias::VirtualVariable - then - // For a virtual variable, the definition may be consumed by any use of a location that is a member of the - // virtual variable. Thus, the definition is live until a subsequent redefinition of the entire virtual - // variable. - exists(Overlap overlap | - overlap = Alias::getOverlap(redefLocation, defLocation) and - not overlap instanceof MayPartiallyOverlap - ) - else - // For other locations, the definition may only be consumed by an exactly-overlapping use of the same location. - // Thus, the definition is live until a subsequent definition of any location that may overlap the original - // definition location. - exists(Alias::getOverlap(redefLocation, defLocation)) - ) - } - - /** - * Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at - * least one use of that definition before any intervening instruction that redefines the definition location. - */ - predicate definitionLiveOnEntryToBlock(Alias::MemoryLocation defLocation, OldBlock block) { - exists(int firstAccess | - definitionHasUse(defLocation, block, firstAccess) and - firstAccess = - min(int index | - definitionHasUse(defLocation, block, index) - or - definitionHasRedefinition(defLocation, block, index) - ) - ) - or - definitionLiveOnExitFromBlock(defLocation, block) and - not definitionHasRedefinition(defLocation, block, _) - } - - /** - * Holds if the definition `defLocation` is live on exit from block `block`. The definition is live on exit if it is - * live on entry to any of the successors of `block`. - */ - pragma[noinline] - predicate definitionLiveOnExitFromBlock(Alias::MemoryLocation defLocation, OldBlock block) { - definitionLiveOnEntryToBlock(defLocation, block.getAFeasibleSuccessor()) - } -} - -private import DefUse - -/** - * Module containing the predicates that connect uses to their reaching definition. The reaching definitions are - * computed separately for each unique use `MemoryLocation`. An instruction is treated as a definition of a use location - * if the defined location overlaps the use location in any way. Thus, a single instruction may serve as a definition - * for multiple use locations, since a single definition location may overlap many use locations. - * - * Definitions and uses are identified by a block and an integer "offset". An offset of -1 indicates the definition - * from a `Phi` instruction at the beginning of the block. An offset of 2*i indicates a definition or use on the - * instruction at index `i` in the block. An offset of 2*i+1 indicates a definition or use on the `Chi` instruction that - * will be inserted immediately after the instruction at index `i` in the block. - * - * For a given use location, each definition and use is also assigned a "rank" within its block. The rank is simply the - * one-based index of that definition or use within the list of definitions and uses of that location within the block, - * ordered by offset. The rank allows the various reachability predicates to be computed more efficiently than they - * would if based solely on offset, since the set of possible ranks is dense while the set of possible offsets is - * potentially very sparse. - */ -module DefUse { - /** - * Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`. - */ - Instruction getDefinitionOrChiInstruction( - OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation, - Alias::MemoryLocation actualDefLocation - ) { - exists(OldInstruction oldInstr, int oldOffset | - oldInstr = defBlock.getInstruction(oldOffset) and - oldOffset >= 0 - | - // An odd offset corresponds to the `Chi` instruction. - defOffset = oldOffset * 2 + 1 and - result = getChi(oldInstr) and - ( - defLocation = Alias::getResultMemoryLocation(oldInstr) or - defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() - ) and - actualDefLocation = defLocation.getVirtualVariable() - or - // An even offset corresponds to the original instruction. - defOffset = oldOffset * 2 and - result = getNewInstruction(oldInstr) and - ( - defLocation = Alias::getResultMemoryLocation(oldInstr) or - defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() - ) and - actualDefLocation = defLocation - ) - or - defOffset = -1 and - hasDefinition(_, defLocation, defBlock, defOffset) and - result = getPhi(defBlock, defLocation) and - actualDefLocation = defLocation - } - - /** - * Gets the rank index of a hypothetical use one instruction past the end of - * the block. This index can be used to determine if a definition reaches the - * end of the block, even if the definition is the last instruction in the - * block. - */ - private int exitRank(Alias::MemoryLocation useLocation, OldBlock block) { - result = max(int rankIndex | defUseRank(useLocation, block, rankIndex, _)) + 1 - } - - /** - * Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at - * (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and - * `useBlock` are the same block. - */ - private predicate definitionReachesUseWithinBlock( - Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock, - int useRank - ) { - defBlock = useBlock and - hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and - hasUseAtRank(useLocation, useBlock, useRank, _) and - definitionReachesRank(useLocation, defBlock, defRank, useRank) - } - - /** - * Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at - * (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`. - */ - predicate definitionReachesUse( - Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock, - int useRank - ) { - hasUseAtRank(useLocation, useBlock, useRank, _) and - ( - definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock, useRank) - or - definitionReachesEndOfBlock(useLocation, defBlock, defRank, useBlock.getAFeasiblePredecessor()) and - not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank) - ) - } - - /** - * Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank - * index `reachesRank` in block `block`. - */ - private predicate definitionReachesRank( - Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank - ) { - // The def always reaches the next use, even if there is also a def on the - // use instruction. - hasDefinitionAtRank(useLocation, _, block, defRank, _) and - reachesRank = defRank + 1 - or - // If the def reached the previous rank, it also reaches the current rank, - // unless there was another def at the previous rank. - exists(int prevRank | - reachesRank = prevRank + 1 and - definitionReachesRank(useLocation, block, defRank, prevRank) and - not prevRank = exitRank(useLocation, block) and - not hasDefinitionAtRank(useLocation, _, block, prevRank, _) - ) - } - - /** - * Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of - * block `block` without any intervening definitions that overlap `useLocation`. - */ - predicate definitionReachesEndOfBlock( - Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock block - ) { - hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and - ( - // If we're looking at the def's own block, just see if it reaches the exit - // rank of the block. - block = defBlock and - locationLiveOnExitFromBlock(useLocation, defBlock) and - definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock)) - or - exists(OldBlock idom | - definitionReachesEndOfBlock(useLocation, defBlock, defRank, idom) and - noDefinitionsSinceIDominator(useLocation, idom, block) - ) - ) - } - - pragma[noinline] - private predicate noDefinitionsSinceIDominator( - Alias::MemoryLocation useLocation, OldBlock idom, OldBlock block - ) { - Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above. - locationLiveOnExitFromBlock(useLocation, block) and - not hasDefinition(useLocation, _, block, _) - } - - /** - * Holds if the specified `useLocation` is live on entry to `block`. This holds if there is a use of `useLocation` - * that is reachable from the start of `block` without passing through a definition that overlaps `useLocation`. - * Note that even a partially-overlapping definition blocks liveness, because such a definition will insert a `Chi` - * instruction whose result totally overlaps the location. - */ - predicate locationLiveOnEntryToBlock(Alias::MemoryLocation useLocation, OldBlock block) { - definitionHasPhiNode(useLocation, block) - or - exists(int firstAccess | - hasUse(useLocation, block, firstAccess, _) and - firstAccess = - min(int offset | - hasUse(useLocation, block, offset, _) - or - hasNonPhiDefinition(useLocation, _, block, offset) - ) - ) - or - locationLiveOnExitFromBlock(useLocation, block) and - not hasNonPhiDefinition(useLocation, _, block, _) - } - - /** - * Holds if the specified `useLocation` is live on exit from `block`. - */ - pragma[noinline] - predicate locationLiveOnExitFromBlock(Alias::MemoryLocation useLocation, OldBlock block) { - locationLiveOnEntryToBlock(useLocation, block.getAFeasibleSuccessor()) - } - - /** - * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. - * This predicate does not include definitions for Phi nodes. - */ - private predicate hasNonPhiDefinition( - Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset - ) { - exists(OldInstruction def, Overlap overlap, int index | - defLocation = Alias::getResultMemoryLocation(def) and - block.getInstruction(index) = def and - overlap = Alias::getOverlap(defLocation, useLocation) and - if overlap instanceof MayPartiallyOverlap - then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. - else offset = index * 2 // The use will be connected to the definition on the original instruction. - ) - } - - /** - * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. - * This predicate includes definitions for Phi nodes (at offset -1). - */ - private predicate hasDefinition( - Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset - ) { - ( - // If there is a Phi node for the use location itself, treat that as a definition at offset -1. - offset = -1 and - if definitionHasPhiNode(useLocation, block) - then defLocation = useLocation - else ( - definitionHasPhiNode(defLocation, block) and - defLocation = useLocation.getVirtualVariable() and - // Handle the unusual case where a virtual variable does not overlap one of its member - // locations. For example, a definition of the virtual variable representing all aliased - // memory does not overlap a use of a string literal, because the contents of a string - // literal can never be redefined. The string literal's location could still be a member of - // the `AliasedVirtualVariable` due to something like: - // ``` - // char s[10]; - // strcpy(s, p); - // const char* p = b ? "SomeLiteral" : s; - // return p[3]; - // ``` - // In the above example, `p[3]` may access either the string literal or the local variable - // `s`, so both of those locations must be members of the `AliasedVirtualVariable`. - exists(Alias::getOverlap(defLocation, useLocation)) - ) - ) - or - hasNonPhiDefinition(useLocation, defLocation, block, offset) - } - - /** - * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. - * `rankIndex` is the rank of the definition as computed by `defUseRank()`. - */ - predicate hasDefinitionAtRank( - Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, - int rankIndex, int offset - ) { - hasDefinition(useLocation, defLocation, block, offset) and - defUseRank(useLocation, block, rankIndex, offset) - } - - /** - * Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`. - */ - private predicate hasUse( - Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use - ) { - exists(int index | - block.getInstruction(index) = use and - ( - // A direct use of the location. - useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2 - or - // A `Chi` instruction will include a use of the virtual variable. - hasChiNode(useLocation, use) and offset = (index * 2) + 1 - ) - ) - } - - /** - * Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the - * rank of the use use as computed by `defUseRank`. - */ - predicate hasUseAtRank( - Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use - ) { - exists(int offset | - hasUse(useLocation, block, offset, use) and - defUseRank(useLocation, block, rankIndex, offset) - ) - } - - /** - * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or - * a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition - * or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`. - */ - private predicate defUseRank( - Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset - ) { - offset = - rank[rankIndex](int j | - hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _) - ) - } - - /** - * Holds if the `Phi` instruction for location `useLocation` at the beginning of block `phiBlock` has an operand along - * the incoming edge from `predBlock`, where that operand's definition is at offset `defOffset` in block `defBlock`. - */ - pragma[noopt] - predicate hasPhiOperandDefinition( - Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, - OldBlock predBlock, OldBlock defBlock, int defOffset - ) { - exists(int defRank | - definitionHasPhiNode(useLocation, phiBlock) and - predBlock = phiBlock.getAFeasiblePredecessor() and - definitionReachesEndOfBlock(useLocation, defBlock, defRank, predBlock) and - hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and - exists(Alias::getOverlap(defLocation, useLocation)) - ) - } -} - -predicate canReuseSsaForMemoryResult(Instruction instruction) { - exists(OldInstruction oldInstruction | - oldInstruction = getOldInstruction(instruction) and - ( - // The previous iteration said it was reusable, so we should mark it as reusable as well. - Alias::canReuseSsaForOldResult(oldInstruction) - or - // The current alias analysis says it is reusable. - Alias::getResultMemoryLocation(oldInstruction).canReuseSsa() - ) - ) - or - exists(Alias::MemoryLocation defLocation | - // This is a `Phi` for a reusable location, so the result of the `Phi` is reusable as well. - instruction = phiInstruction(_, defLocation) and - defLocation.canReuseSsa() - ) - // We don't support reusing SSA for any location that could create a `Chi` instruction. -} - -/** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the - * `DebugSsa` module, which is then imported by PrintSSA. - */ -module DebugSsa { - import PhiInsertion - import DefUse -} - -import CachedForDebugging - -cached -private module CachedForDebugging { - cached - string getTempVariableUniqueId(IRTempVariable var) { - result = getOldTempVariable(var).getUniqueId() - } - - cached - string getInstructionUniqueId(Instruction instr) { - exists(OldInstruction oldInstr | - oldInstr = getOldInstruction(instr) and - result = "NonSSA: " + oldInstr.getUniqueId() - ) - or - exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = getPhi(phiBlock, location) and - result = - "Phi Block(" + phiBlock.getFirstInstruction().getUniqueId() + ")[" + specificity + "]: " + - location.getUniqueId() and - if location instanceof Alias::VirtualVariable - then - // Sort Phi nodes for virtual variables before Phi nodes for member locations. - specificity = "g" - else specificity = "s" - ) - or - instr = unreachedInstruction(_) and - result = "Unreached" - } - - private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) { - result.getEnclosingFunction() = var.getEnclosingFunction() and - result.getAst() = var.getAst() and - result.getTag() = var.getTag() - } - - cached - predicate instructionHasSortKeys(Instruction instr, int key1, int key2) { - exists(OldInstruction oldInstr | - oldInstr = getOldInstruction(instr) and - oldInstr.hasSortKeys(key1, key2) - ) - or - instr instanceof TUnreachedInstruction and - key1 = maxValue() and - key2 = maxValue() - } - - /** - * Returns the value of the maximum representable integer. - */ - cached - int maxValue() { result = 2147483647 } -} - -/** - * Provides the portion of the parameterized IR interface that is used to construct the SSA stages - * of the IR. The raw stage of the IR does not expose these predicates. - * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures - * that all of SSA construction will be evaluated in the same stage. - */ -module Ssa { - class MemoryLocation = Alias::MemoryLocation; - - predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; - - predicate hasChiInstruction = Cached::hasChiInstructionCached/1; - - predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll deleted file mode 100644 index bf9b18d0b17..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ /dev/null @@ -1,5 +0,0 @@ -import experimental.ir.implementation.Opcode as Opcode -import experimental.ir.implementation.internal.OperandTag as OperandTag -import experimental.ir.internal.Overlap as Overlap -import experimental.ir.implementation.internal.TInstruction as TInstruction -import experimental.ir.implementation.raw.IR as RawIR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll deleted file mode 100644 index cad1a3dd2de..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ /dev/null @@ -1,9 +0,0 @@ -import experimental.ir.implementation.raw.IR as OldIR -import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance -import experimental.ir.implementation.unaliased_ssa.IR as NewIR -import experimental.ir.implementation.raw.internal.IRConstruction as RawStage -import experimental.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SsaInstructions -import experimental.ir.internal.IRCSharpLanguage as Language -import SimpleSSA as Alias -import experimental.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SsaOperands diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll deleted file mode 100644 index 5c33ecf5f99..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ /dev/null @@ -1,111 +0,0 @@ -import AliasAnalysis -private import SimpleSSAImports -import SimpleSSAPublicImports -private import AliasConfiguration - -private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) { - exists(Instruction constantBase, int bitOffset | - addressOperandBaseAndConstantOffset(addrOperand, constantBase, bitOffset) and - bitOffset = 0 and - constantBase = var.getABaseInstruction() and - type = var.getIRType() - ) -} - -/** - * Holds if the specified variable should be modeled in SSA form. For unaliased SSA, we only model a - * variable if its address never escapes and all reads and writes of that variable access the entire - * variable using the original type of the variable. - */ -predicate isVariableModeled(Allocation var) { - not allocationEscapes(var) and - forall(Instruction instr, AddressOperand addrOperand, IRType type | - addrOperand = instr.getResultAddressOperand() and - type = instr.getResultIRType() and - var = getAddressOperandAllocation(addrOperand) - | - isTotalAccess(var, addrOperand, type) and not instr.hasResultMayMemoryAccess() - ) and - forall(MemoryOperand memOperand, AddressOperand addrOperand, IRType type | - addrOperand = memOperand.getAddressOperand() and - type = memOperand.getIRType() and - var = getAddressOperandAllocation(addrOperand) - | - isTotalAccess(var, addrOperand, type) and not memOperand.hasMayReadMemoryAccess() - ) -} - -/** - * Holds if the SSA use/def chain for the specified variable can be safely reused by later - * iterations of SSA construction. This will hold only if we modeled the variable soundly, so that - * subsequent iterations will recompute SSA for any variable that we assumed did not escape, but - * actually would have escaped if we had used a sound escape analysis. - */ -predicate canReuseSsaForVariable(IRAutomaticVariable var) { - isVariableModeled(var) and - not allocationEscapes(var) -} - -private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) } - -private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var } - -class MemoryLocation extends TMemoryLocation { - Allocation var; - - MemoryLocation() { this = MkMemoryLocation(var) } - - final string toString() { result = var.getAllocationString() } - - final Allocation getAllocation() { result = var } - - final Language::Location getLocation() { result = var.getLocation() } - - final IRFunction getIRFunction() { result = var.getEnclosingIRFunction() } - - final VirtualVariable getVirtualVariable() { result = this } - - final Language::LanguageType getType() { result = var.getLanguageType() } - - final string getUniqueId() { result = var.getUniqueId() } - - final predicate canReuseSsa() { canReuseSsaForVariable(var) } - - /** DEPRECATED: Alias for canReuseSsa */ - deprecated predicate canReuseSSA() { this.canReuseSsa() } -} - -predicate canReuseSsaForOldResult(Instruction instr) { none() } - -/** - * Represents a set of `MemoryLocation`s that cannot overlap with - * `MemoryLocation`s outside of the set. The `VirtualVariable` will be - * represented by a `MemoryLocation` that totally overlaps all other - * `MemoryLocations` in the set. - */ -class VirtualVariable extends MemoryLocation { } - -/** A virtual variable that groups all escaped memory within a function. */ -class AliasedVirtualVariable extends VirtualVariable { - AliasedVirtualVariable() { none() } -} - -Overlap getOverlap(MemoryLocation def, MemoryLocation use) { - def = use and result instanceof MustExactlyOverlap - or - none() // Avoid compiler error in SSAConstruction -} - -MemoryLocation getResultMemoryLocation(Instruction instr) { - result = getMemoryLocation(getAddressOperandAllocation(instr.getResultAddressOperand())) -} - -MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { - result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand())) -} - -/** Gets the start bit offset of a `MemoryLocation`, if any. */ -int getStartBitOffset(MemoryLocation location) { none() } - -/** Gets the end bit offset of a `MemoryLocation`, if any. */ -int getEndBitOffset(MemoryLocation location) { none() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll deleted file mode 100644 index 80a1c7c36fd..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll +++ /dev/null @@ -1,4 +0,0 @@ -import experimental.ir.implementation.raw.IR -import experimental.ir.internal.IntegerConstant as Ints -import experimental.ir.implementation.internal.OperandTag -import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll deleted file mode 100644 index 047d4923039..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll +++ /dev/null @@ -1 +0,0 @@ -import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll deleted file mode 100644 index cddc3e23d7e..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll +++ /dev/null @@ -1,22 +0,0 @@ -private import DominanceInternal - -predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) = - idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block) - -predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) { - blockImmediatelyDominates+(dominator, block) -} - -predicate blockDominates(Graph::Block dominator, Graph::Block block) { - blockStrictlyDominates(dominator, block) or dominator = block -} - -Graph::Block getDominanceFrontier(Graph::Block dominator) { - Graph::blockSuccessor(dominator, result) and - not blockImmediatelyDominates(dominator, result) - or - exists(Graph::Block prev | result = getDominanceFrontier(prev) | - blockImmediatelyDominates(dominator, prev) and - not blockImmediatelyDominates(dominator, result) - ) -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll deleted file mode 100644 index aaa4cc7bd53..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll +++ /dev/null @@ -1,7 +0,0 @@ -private import ReachableBlock as Reachability - -module Graph { - import Reachability::Graph - - class Block = Reachability::ReachableBlock; -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll deleted file mode 100644 index f26565bc278..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll +++ /dev/null @@ -1,22 +0,0 @@ -private import DominanceInternal -private import ReachableBlockInternal -private import Dominance -import IR - -private class DominancePropertyProvider extends IRPropertyProvider { - override string getBlockProperty(IRBlock block, string key) { - exists(IRBlock dominator | - blockImmediatelyDominates(dominator, block) and - key = "ImmediateDominator" and - result = "Block " + dominator.getDisplayIndex().toString() - ) - or - key = "DominanceFrontier" and - result = - strictconcat(IRBlock frontierBlock | - frontierBlock = getDominanceFrontier(block) - | - frontierBlock.getDisplayIndex().toString(), ", " order by frontierBlock.getDisplayIndex() - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll deleted file mode 100644 index 6befad72336..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll +++ /dev/null @@ -1,17 +0,0 @@ -private import ReachableBlockInternal -private import ReachableBlock -import IR - -private class ReachableBlockPropertyProvider extends IRPropertyProvider { - override string getBlockProperty(IRBlock block, string key) { - not block instanceof ReachableBlock and - key = "Unreachable" and - result = "true" - or - exists(EdgeKind kind | - isInfeasibleEdge(block, kind) and - key = "Infeasible(" + kind.toString() + ")" and - result = "true" - ) - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll deleted file mode 100644 index 25a53bbefe8..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll +++ /dev/null @@ -1,53 +0,0 @@ -private import ReachableBlockInternal -private import IR -private import ConstantAnalysis - -predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) { - exists(int conditionValue | - conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and - if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge - ) -} - -pragma[noinline] -predicate isInfeasibleEdge(IRBlockBase block, EdgeKind kind) { - isInfeasibleInstructionSuccessor(block.getLastInstruction(), kind) -} - -private IRBlock getAFeasiblePredecessorBlock(IRBlock successor) { - exists(EdgeKind kind | - result.getSuccessor(kind) = successor and - not isInfeasibleEdge(result, kind) - ) -} - -private predicate isBlockReachable(IRBlock block) { - exists(IRFunction f | getAFeasiblePredecessorBlock*(block) = f.getEntryBlock()) -} - -/** - * An IR block that is reachable from the entry block of the function, considering only feasible - * edges. - */ -class ReachableBlock extends IRBlockBase { - ReachableBlock() { isBlockReachable(this) } - - final ReachableBlock getAFeasiblePredecessor() { result = getAFeasiblePredecessorBlock(this) } - - final ReachableBlock getAFeasibleSuccessor() { this = getAFeasiblePredecessorBlock(result) } -} - -/** - * An instruction that is contained in a reachable block. - */ -class ReachableInstruction extends Instruction { - ReachableInstruction() { this.getBlock() instanceof ReachableBlock } -} - -module Graph { - predicate isEntryBlock(ReachableBlock block) { exists(IRFunction f | block = f.getEntryBlock()) } - - predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) { - succ = pred.getAFeasibleSuccessor() - } -} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll deleted file mode 100644 index e435289cbfc..00000000000 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll +++ /dev/null @@ -1,2 +0,0 @@ -import experimental.ir.implementation.unaliased_ssa.IR as IR -import experimental.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/internal/CSharpType.qll b/csharp/ql/src/experimental/ir/internal/CSharpType.qll deleted file mode 100644 index 1cf87b8fbbb..00000000000 --- a/csharp/ql/src/experimental/ir/internal/CSharpType.qll +++ /dev/null @@ -1,365 +0,0 @@ -private import csharp -private import experimental.ir.implementation.IRType -private import IRCSharpLanguage as Language - -int getTypeSize(Type type) { - // REVIEW: Is this complete? - result = type.(SimpleType).getSize() - or - result = getTypeSize(type.(Enum).getUnderlyingType()) - or - // TODO: Generate a reasonable size - type instanceof Struct and result = 16 - or - type instanceof RefType and result = getPointerSize() - or - type instanceof PointerType and result = getPointerSize() - or - result = getTypeSize(type.(TupleType).getUnderlyingType()) - or - // TODO: Add room for extra field - result = getTypeSize(type.(NullableType).getUnderlyingType()) - or - type instanceof VoidType and result = 0 -} - -int getPointerSize() { result = 8 } - -/** - * Holds if an `IRErrorType` should exist. - */ -predicate hasErrorType() { exists(UnknownType t) } - -/** - * Holds if an `IRBooleanType` with the specified `byteSize` should exist. - */ -predicate hasBooleanType(int byteSize) { byteSize = getTypeSize(any(BoolType type)) } - -private predicate isSignedIntegerType(ValueType type) { - type instanceof SignedIntegralType or - type.(Enum).getUnderlyingType() instanceof SignedIntegralType -} - -private predicate isUnsignedIntegerType(ValueType type) { - type instanceof UnsignedIntegralType or - type instanceof CharType or - type.(Enum).getUnderlyingType() instanceof UnsignedIntegralType -} - -/** - * Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist. - */ -predicate hasSignedIntegerType(int byteSize) { - byteSize = getTypeSize(any(ValueType type | isSignedIntegerType(type))) -} - -/** - * Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist. - */ -predicate hasUnsignedIntegerType(int byteSize) { - byteSize = getTypeSize(any(ValueType type | isUnsignedIntegerType(type))) -} - -/** - * Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist. - */ -predicate hasFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { - byteSize = any(FloatingPointType type).getSize() and - base = 2 and - domain instanceof Language::RealDomain -} - -private predicate isPointerIshType(Type type) { - type instanceof PointerType or - type instanceof RefType -} - -/** - * Holds if an `IRAddressType` with the specified `byteSize` should exist. - */ -predicate hasAddressType(int byteSize) { - // This covers all pointers, all references, and because it also looks at `NullType`, it - // should always return a result that makes sense for arbitrary glvalues as well. - byteSize = getTypeSize(any(Type type | isPointerIshType(type))) -} - -/** - * Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist. - */ -predicate hasFunctionAddressType(int byteSize) { byteSize = getTypeSize(any(NullType type)) } - -private predicate isOpaqueType(ValueOrRefType type) { - type instanceof Struct or - type instanceof NullableType or - type instanceof DecimalType -} - -/** - * Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist. - */ -predicate hasOpaqueType(Type tag, int byteSize) { - isOpaqueType(tag) and byteSize = getTypeSize(tag) -} - -private Type getRepresentationType(Type type) { - result = type.(Enum).getUnderlyingType() - or - result = type.(TupleType).getUnderlyingType() - or - not type instanceof Enum and not type instanceof TupleType and result = type -} - -/** - * Gets the `IRType` that represents a prvalue of the specified `Type`. - */ -private IRType getIRTypeForPRValue(Type type) { - exists(Type repType | repType = getRepresentationType(type) | - exists(IROpaqueType opaqueType | opaqueType = result | - opaqueType.getByteSize() = getTypeSize(repType) and - opaqueType.getTag() = repType - ) - or - result.(IRBooleanType).getByteSize() = repType.(BoolType).getSize() - or - isSignedIntegerType(repType) and - result.(IRSignedIntegerType).getByteSize() = getTypeSize(repType) - or - isUnsignedIntegerType(repType) and - result.(IRUnsignedIntegerType).getByteSize() = getTypeSize(repType) - or - result.(IRFloatingPointType).getByteSize() = repType.(FloatingPointType).getSize() - or - isPointerIshType(repType) and result.(IRAddressType).getByteSize() = getTypeSize(repType) - or - repType instanceof VoidType and result instanceof IRVoidType - or - repType instanceof UnknownType and result instanceof IRErrorType - ) -} - -string getOpaqueTagIdentityString(Type tag) { result = tag.getFullyQualifiedName() } - -cached -private newtype TCSharpType = - TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or - TGLValueAddressType(Type type) { any() } or - TFunctionAddressType() or - TUnknownType() - -class CSharpType extends TCSharpType { - abstract string toString(); - - /** Gets a string used in IR dumps */ - string getDumpString() { result = this.toString() } - - /** Gets the size of the type in bytes, if known. */ - final int getByteSize() { result = this.getIRType().getByteSize() } - - /** - * Gets the `IRType` that represents this `CSharpType`. Many different `CSharpType`s can map to a - * single `IRType`. - */ - cached - abstract IRType getIRType(); - - /** - * Holds if the `CSharpType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or - * if it represents a glvalue of type `Type` (if `isGLValue` is `true`). - */ - abstract predicate hasType(Type type, boolean isGLValue); - - final predicate hasUnspecifiedType(Type type, boolean isGLValue) { this.hasType(type, isGLValue) } -} - -/** - * A `CSharpType` that wraps an existing `Type` (either as a prvalue or a glvalue). - */ -private class CSharpWrappedType extends CSharpType { - Type cstype; - - CSharpWrappedType() { - this = TPRValueType(cstype) or - this = TGLValueAddressType(cstype) - } - - abstract override string toString(); - - abstract override IRType getIRType(); - - abstract override predicate hasType(Type type, boolean isGLValue); -} - -/** - * A `CSharpType` that represents a prvalue of an existing `Type`. - */ -private class CSharpPRValueType extends CSharpWrappedType, TPRValueType { - final override string toString() { result = cstype.toString() } - - final override IRType getIRType() { result = getIRTypeForPRValue(cstype) } - - final override predicate hasType(Type type, boolean isGLValue) { - type = cstype and - isGLValue = false - } -} - -/** - * A `CSharpType` that represents a glvalue of an existing `Type`. - */ -private class CSharpGLValueAddressType extends CSharpWrappedType, TGLValueAddressType { - final override string toString() { result = "glval<" + cstype.toString() + ">" } - - final override IRAddressType getIRType() { result.getByteSize() = getPointerSize() } - - final override predicate hasType(Type type, boolean isGLValue) { - type = cstype and - isGLValue = true - } -} - -/** - * A `CSharpType` that represents a function address. - */ -private class CSharpFunctionAddressType extends CSharpType, TFunctionAddressType { - final override string toString() { result = "" } - - final override IRFunctionAddressType getIRType() { result.getByteSize() = getPointerSize() } - - final override predicate hasType(Type type, boolean isGLValue) { - type instanceof VoidType and isGLValue = true - } -} - -/** - * A `CSharpType` that represents an unknown type. - */ -private class CSharpUnknownType extends CSharpType, TUnknownType { - final override string toString() { result = "" } - - final override IRUnknownType getIRType() { any() } - - final override predicate hasType(Type type, boolean isGLValue) { - type instanceof VoidType and isGLValue = false - } -} - -/** - * Gets the single instance of `CSharpUnknownType`. - */ -CSharpUnknownType getUnknownType() { any() } - -/** - * Gets the `CSharpType` that represents a prvalue of type `void`. - */ -CSharpPRValueType getVoidType() { exists(VoidType voidType | result.hasType(voidType, false)) } - -/** - * Gets the `CSharpType` that represents a prvalue of type `type`. - */ -CSharpPRValueType getTypeForPRValue(Type type) { result.hasType(type, false) } - -/** - * Gets the `CSharpType` that represents a glvalue of type `type`. - */ -CSharpGLValueAddressType getTypeForGLValue(Type type) { result.hasType(type, true) } - -/** - * Gets the `CSharpType` that represents a prvalue of type `int`. - */ -CSharpPRValueType getIntType() { result.hasType(any(IntType t), false) } - -/** - * Gets the `CSharpType` that represents a prvalue of type `bool`. - */ -CSharpPRValueType getBoolType() { result.hasType(any(BoolType t), false) } - -/** - * Gets the `CSharpType` that represents a prvalue of `NullType`. - */ -CSharpPRValueType getNullType() { result.hasType(any(NullType t), false) } - -/** - * Gets the `CSharpType` that represents a function address. - */ -CSharpFunctionAddressType getFunctionAddressType() { any() } - -/** - * Gets the `CSharpType` that is the canonical type for an `IRBooleanType` with the specified - * `byteSize`. - */ -CSharpPRValueType getCanonicalBooleanType(int byteSize) { - exists(BoolType type | result = TPRValueType(type) and byteSize = type.getSize()) -} - -/** - * Gets the `CSharpType` that is the canonical type for an `IRSignedIntegerType` with the specified - * `byteSize`. - */ -CSharpPRValueType getCanonicalSignedIntegerType(int byteSize) { - result = TPRValueType(any(SignedIntegralType t | t.getSize() = byteSize)) -} - -/** - * Gets the `CSharpType` that is the canonical type for an `IRUnsignedIntegerType` with the specified - * `byteSize`. - */ -CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) { - result = TPRValueType(any(UnsignedIntegralType t | t.getSize() = byteSize)) -} - -/** - * Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified - * size, base, and type domain. - */ -CSharpPRValueType getCanonicalFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { - base = 2 and - domain instanceof Language::RealDomain and - result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize)) -} - -/** - * Gets the `CSharpType` that is the canonical type for an `IRAddressType` with the specified - * `byteSize`. - */ -CSharpPRValueType getCanonicalAddressType(int byteSize) { - // We just use `NullType`, since it should be unique. - result = TPRValueType(any(NullType type | getTypeSize(type) = byteSize)) -} - -/** - * Gets the `CSharpType` that is the canonical type for an `IRFunctionAddressType` with the specified - * `byteSize`. - */ -CSharpFunctionAddressType getCanonicalFunctionAddressType(int byteSize) { - result.getByteSize() = byteSize -} - -/** - * Gets the `CSharpType` that is the canonical type for `IRErrorType`. - */ -CSharpPRValueType getCanonicalErrorType() { result = TPRValueType(any(UnknownType type)) } - -/** - * Gets the `CSharpType` that is the canonical type for `IRUnknownType`. - */ -CSharpUnknownType getCanonicalUnknownType() { any() } - -/** - * Gets the `CSharpType` that is the canonical type for `IRVoidType`. - */ -CSharpPRValueType getCanonicalVoidType() { result = TPRValueType(any(VoidType type)) } - -/** - * Gets the `CSharpType` that is the canonical type for an `IROpaqueType` with the specified `tag` and - * `byteSize`. - */ -CSharpPRValueType getCanonicalOpaqueType(Type tag, int byteSize) { - isOpaqueType(tag) and - result = TPRValueType(tag) and - getTypeSize(tag) = byteSize -} - -module LanguageTypeConsistency { - // Nothing interesting here for C# yet, but the module still has to exist because it is imported - // by `IRTypeConsistency`. -} diff --git a/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll deleted file mode 100644 index f0137b9b5ce..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll +++ /dev/null @@ -1,162 +0,0 @@ -private import csharp as CSharp -private import IRUtilities -import CSharpType - -class LanguageType = CSharpType; - -class OpaqueTypeTag = CSharp::ValueOrRefType; - -class Function = CSharp::Callable; - -class GlobalVariable extends CSharp::Field { - GlobalVariable() { this.isStatic() } -} - -class Declaration = CSharp::Declaration; - -class Location = CSharp::Location; - -class UnknownLocation = CSharp::EmptyLocation; - -class UnknownDefaultLocation = CSharp::EmptyLocation; - -class File = CSharp::File; - -class AST = CSharp::Element; - -class Type = CSharp::Type; - -class UnknownType = CSharp::NullType; - -class VoidType = CSharp::VoidType; - -class IntegralType = CSharp::IntegralType; - -class FloatingPointType = CSharp::FloatingPointType; - -private newtype TTypeDomain = TRealDomain() - -/** - * The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or - * `ImaginaryDomain`. - */ -class TypeDomain extends TTypeDomain { - /** Gets a textual representation of this type domain. */ - string toString() { none() } -} - -/** - * The type domain of a floating-point type that represents a real number. - */ -class RealDomain extends TypeDomain, TRealDomain { - final override string toString() { result = "real" } -} - -/** - * The type domain of a floating-point type that represents a complex number. Not currently used in - * C#. - */ -class ComplexDomain extends TypeDomain { - ComplexDomain() { none() } - - final override string toString() { result = "complex" } -} - -/** - * The type domain of a floating-point type that represents an imaginary number. Not currently used - * in C#. - */ -class ImaginaryDomain extends TypeDomain { - ImaginaryDomain() { none() } - - final override string toString() { result = "imaginary" } -} - -private newtype TClassDerivation = - // Note that this is the `Class` type exported from this module, not CSharp::Class. - MkClassDerivation(Class base, Class derived) { derived.getABaseType() = base } - -private newtype TBuiltInOperation = NoOp() - -class BuiltInOperation extends TBuiltInOperation { - string toString() { result = "BuiltInOp" } -} - -class ClassDerivation extends MkClassDerivation { - Class baseClass; - Class derivedClass; - - ClassDerivation() { this = MkClassDerivation(baseClass, derivedClass) } - - string toString() { result = "ClassDerivation" } - - final Class getBaseClass() { result = baseClass } - - final Class getDerivedClass() { result = derivedClass } - - final int getByteOffset() { - // Inheritance never requires adjusting the `this` pointer in C#. - result = 0 - } -} - -class StringLiteral = CSharp::StringLiteral; - -class Variable = CSharp::Variable; - -class AutomaticVariable = CSharp::LocalScopeVariable; - -class StaticVariable = CSharp::Variable; - -class Parameter = CSharp::Parameter; - -class Field = CSharp::Field; - -// TODO: Remove necessity for these. -class Expr = CSharp::Expr; - -class Class = CSharp::ValueOrRefType; // Used for inheritance conversions - -predicate hasCaseEdge(string minValue, string maxValue) { - // TODO: Need to handle pattern matching - hasCaseEdge(_, minValue, maxValue) -} - -predicate hasPositionalArgIndex(int argIndex) { - exists(CSharp::MethodCall 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 - argIndex in [0 .. any(CSharp::Callable c).getNumberOfParameters() - 1] -} - -predicate hasAsmOperandIndex(int operandIndex) { none() } - -predicate isVariableAutomatic(Variable var) { var instanceof CSharp::LocalScopeVariable } - -string getStringLiteralText(StringLiteral s) { - // REVIEW: Is this the right escaping? - result = s.toString() -} - -predicate hasPotentialLoop(Function f) { - exists(CSharp::LoopStmt l | l.getEnclosingCallable() = f) or - exists(CSharp::GotoStmt s | s.getEnclosingCallable() = f) -} - -predicate hasGoto(Function f) { exists(CSharp::GotoStmt s | s.getEnclosingCallable() = f) } - -/** - * Gets the offset of field `field` in bits. - */ -int getFieldBitOffset(Field f) { - //REVIEW: Implement this once layout has been synthesized. - none() -} - -/** - * Holds if the specified `Function` can be overridden in a derived class. - */ -predicate isFunctionVirtual(Function f) { f.(CSharp::Overridable).isOverridableOrImplementable() } diff --git a/csharp/ql/src/experimental/ir/internal/IRCSharpLanguageDebug.qll b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguageDebug.qll deleted file mode 100644 index a7c2d79d949..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IRCSharpLanguageDebug.qll +++ /dev/null @@ -1,5 +0,0 @@ -private import csharp as CSharp - -class Function = CSharp::Callable; - -string getIdentityString(Function func) { result = func.getFullyQualifiedNameWithTypes() } diff --git a/csharp/ql/src/experimental/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll deleted file mode 100644 index 91e2208c6f7..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IRGuards.qll +++ /dev/null @@ -1,670 +0,0 @@ -import csharp -import semmle.code.csharp.controlflow.BasicBlocks -import experimental.ir.IR - -/** - * Holds if `block` consists of an `UnreachedInstruction`. - * - * We avoiding reporting an unreached block as being controlled by a guard. The unreached block - * has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock` - * and the `IRBlock`. - */ -private predicate isUnreachedBlock(IRBlock block) { - block.getFirstInstruction() instanceof UnreachedInstruction -} - -/** - * A Boolean condition in the AST that guards one or more basic blocks. This includes - * operands of logical operators but not switch statements. - */ -cached -class GuardCondition extends Expr { - cached - GuardCondition() { - exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression()) - or - // no binary operators in the IR - this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition - or - // the IR short-circuits if(!x) - // don't produce a guard condition for `y = !x` and other non-short-circuited cases - not exists(Instruction inst | this = inst.getAst()) and - exists(IRGuardCondition ir | this.(LogicalNotExpr).getOperand() = ir.getAst()) - } - - /** - * Holds if this condition controls `block`, meaning that `block` is only - * entered if the value of this condition is `testIsTrue`. - * - * Illustration: - * - * ``` - * [ (testIsTrue) ] - * [ this ----------------succ ---- controlled ] - * [ | | ] - * [ (testIsFalse) | ------ ... ] - * [ other ] - * ``` - * - * The predicate holds if all paths to `controlled` go via the `testIsTrue` - * edge of the control-flow graph. In other words, the `testIsTrue` edge - * must dominate `controlled`. This means that `controlled` must be - * dominated by both `this` and `succ` (the target of the `testIsTrue` - * edge). It also means that any other edge into `succ` must be a back-edge - * from a node which is dominated by `succ`. - * - * The short-circuit boolean operations have slightly surprising behavior - * here: because the operation itself only dominates one branch (due to - * being short-circuited) then it will only control blocks dominated by the - * true (for `&&`) or false (for `||`) branch. - */ - cached - predicate controls(BasicBlock controlled, boolean testIsTrue) { none() } - - /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ - cached - predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { - none() - } - - /** - * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. - * If `isLessThan = false` then this implies `left >= right + k`. - */ - cached - predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { none() } - - /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ - cached - predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { - none() - } - - /** - * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. - * If `areEqual = false` then this implies `left != right + k`. - */ - cached - predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { none() } -} - -/** - * Holds if the truth of the binary logical expression `blo` having value `wholeIsTrue` - * implies that the truth of the child expression `part` has truth value `partIsTrue`. - * - * For example if the binary operation: - * ```csharp - * x && y - * ``` - * is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and - * `impliesValue(y, true, true)` hold. - */ -private predicate impliesValue( - BinaryLogicalOperation blo, Expr part, boolean partIsTrue, boolean wholeIsTrue -) { - blo instanceof LogicalAndExpr and - ( - wholeIsTrue = true and partIsTrue = true and part = blo.getAnOperand() - or - wholeIsTrue = true and - impliesValue(blo.getAnOperand(), part, partIsTrue, true) - ) - or - blo instanceof LogicalOrExpr and - ( - wholeIsTrue = false and partIsTrue = false and part = blo.getAnOperand() - or - wholeIsTrue = false and - impliesValue(blo.getAnOperand(), part, partIsTrue, false) - ) -} - -/** - * A binary logical operator in the AST that guards one or more basic blocks. - */ -private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { - GuardConditionFromBinaryLogicalOperator() { - this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition - } - - override predicate controls(BasicBlock controlled, boolean testIsTrue) { - exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs | - this = binop and - lhs = binop.getLeftOperand() and - rhs = binop.getRightOperand() and - lhs.controls(controlled, testIsTrue) and - rhs.controls(controlled, testIsTrue) - ) - } - - override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { - exists(boolean partIsTrue, GuardCondition part | - impliesValue(this, part, partIsTrue, testIsTrue) - | - part.comparesLt(left, right, k, isLessThan, partIsTrue) - ) - } - - override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { - exists(boolean testIsTrue | - this.comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) - ) - } - - override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { - exists(boolean partIsTrue, GuardCondition part | - impliesValue(this, part, partIsTrue, testIsTrue) - | - part.comparesEq(left, right, k, areEqual, partIsTrue) - ) - } - - override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { - exists(boolean testIsTrue | - this.comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) - ) - } -} - -/** - * A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding - * IR instruction. - */ -private class GuardConditionFromShortCircuitNot extends GuardCondition, LogicalNotExpr { - GuardConditionFromShortCircuitNot() { - not exists(Instruction inst | this = inst.getAst()) and - exists(IRGuardCondition ir | this.getOperand() = ir.getAst()) - } - - override predicate controls(BasicBlock controlled, boolean testIsTrue) { - this.getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot()) - } - - override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { - this.getOperand() - .(GuardCondition) - .comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot()) - } - - override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { - this.getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot()) - } - - override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { - this.getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot()) - } - - override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { - this.getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot()) - } -} - -/** - * A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR - * instruction. - */ -private class GuardConditionFromIR extends GuardCondition { - IRGuardCondition ir; - - GuardConditionFromIR() { this = ir.getUnconvertedResultExpression() } - - override predicate controls(BasicBlock controlled, boolean testIsTrue) { - // This condition must determine the flow of control; that is, this - // node must be a top-level condition. - this.controlsBlock1(controlled, testIsTrue) - } - - /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ - override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { - exists(Instruction li, Instruction ri | - li.getUnconvertedResultExpression() = left and - ri.getUnconvertedResultExpression() = right and - ir.comparesLt(li.getAUse(), ri.getAUse(), k, isLessThan, testIsTrue) - ) - } - - /** - * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. - * If `isLessThan = false` then this implies `left >= right + k`. - */ - override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { - exists(Instruction li, Instruction ri, boolean testIsTrue | - li.getUnconvertedResultExpression() = left and - ri.getUnconvertedResultExpression() = right and - ir.comparesLt(li.getAUse(), ri.getAUse(), k, isLessThan, testIsTrue) and - this.controls(block, testIsTrue) - ) - } - - /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ - override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { - exists(Instruction li, Instruction ri | - li.getUnconvertedResultExpression() = left and - ri.getUnconvertedResultExpression() = right and - ir.comparesEq(li.getAUse(), ri.getAUse(), k, areEqual, testIsTrue) - ) - } - - /** - * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. - * If `areEqual = false` then this implies `left != right + k`. - */ - override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { - exists(Instruction li, Instruction ri, boolean testIsTrue | - li.getUnconvertedResultExpression() = left and - ri.getUnconvertedResultExpression() = right and - ir.comparesEq(li.getAUse(), ri.getAUse(), k, areEqual, testIsTrue) and - this.controls(block, testIsTrue) - ) - } - - /** - * Holds if this condition controls `block`, meaning that `block` is only - * entered if the value of this condition is `testIsTrue`. This helper - * predicate does not necessarily hold for binary logical operations like - * `&&` and `||`. See the detailed explanation on predicate `controls`. - */ - private predicate controlsBlock1(BasicBlock controlled, boolean testIsTrue) { - exists(IRBlock irb | - forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and - irb.getAnInstruction().getAst().(ControlFlowElement).getAControlFlowNode().getBasicBlock() = - controlled and - not isUnreachedBlock(irb) - ) - } -} - -/** - * A Boolean condition in the IR that guards one or more basic blocks. This includes - * operands of logical operators but not switch statements. Note that `&&` and `||` - * don't have an explicit representation in the IR, and therefore will not appear as - * IRGuardConditions. - */ -cached -class IRGuardCondition extends Instruction { - ConditionalBranchInstruction branch; - - cached - IRGuardCondition() { branch = get_branch_for_condition(this) } - - /** - * Holds if this condition controls `block`, meaning that `block` is only - * entered if the value of this condition is `testIsTrue`. - * - * Illustration: - * - * ``` - * [ (testIsTrue) ] - * [ this ----------------succ ---- controlled ] - * [ | | ] - * [ (testIsFalse) | ------ ... ] - * [ other ] - * ``` - * - * The predicate holds if all paths to `controlled` go via the `testIsTrue` - * edge of the control-flow graph. In other words, the `testIsTrue` edge - * must dominate `controlled`. This means that `controlled` must be - * dominated by both `this` and `succ` (the target of the `testIsTrue` - * edge). It also means that any other edge into `succ` must be a back-edge - * from a node which is dominated by `succ`. - * - * The short-circuit boolean operations have slightly surprising behavior - * here: because the operation itself only dominates one branch (due to - * being short-circuited) then it will only control blocks dominated by the - * true (for `&&`) or false (for `||`) branch. - */ - cached - predicate controls(IRBlock controlled, boolean testIsTrue) { - // This condition must determine the flow of control; that is, this - // node must be a top-level condition. - this.controlsBlock(controlled, testIsTrue) - or - exists(IRGuardCondition ne | - this = ne.(LogicalNotInstruction).getUnary() and - ne.controls(controlled, testIsTrue.booleanNot()) - ) - } - - cached - predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { - pred.getASuccessor() = succ and - this.controls(pred, testIsTrue) - or - this.hasBranchEdge(succ, testIsTrue) and - branch.getCondition() = this and - branch.getBlock() = pred - } - - /** - * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. - * - * This predicate is intended to help with situations in which an inference can only be made - * based on an edge between a block with multiple successors and a block with multiple - * predecessors. For example, in the following situation, an inference can be made about the - * value of `x` at the end of the `if` statement, but there is no block which is controlled by - * the `if` statement when `x >= y`. - * ```csharp - * if (x < y) { - * x = y; - * } - * return x; - * ``` - */ - private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) { - branch.getCondition() = this and - ( - testIsTrue = true and - succ.getFirstInstruction() = branch.getTrueSuccessor() - or - testIsTrue = false and - succ.getFirstInstruction() = branch.getFalseSuccessor() - ) - } - - /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ - cached - predicate comparesLt(Operand left, Operand right, int k, boolean isLessThan, boolean testIsTrue) { - compares_lt(this, left, right, k, isLessThan, testIsTrue) - } - - /** - * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. - * If `isLessThan = false` then this implies `left >= right + k`. - */ - cached - predicate ensuresLt(Operand left, Operand right, int k, IRBlock block, boolean isLessThan) { - exists(boolean testIsTrue | - compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) - ) - } - - /** - * Holds if (determined by this guard) `left < right + k` must be `isLessThan` on the edge from - * `pred` to `succ`. If `isLessThan = false` then this implies `left >= right + k`. - */ - cached - predicate ensuresLtEdge( - Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean isLessThan - ) { - exists(boolean testIsTrue | - compares_lt(this, left, right, k, isLessThan, testIsTrue) and - this.controlsEdge(pred, succ, testIsTrue) - ) - } - - /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ - cached - predicate comparesEq(Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue) { - compares_eq(this, left, right, k, areEqual, testIsTrue) - } - - /** - * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. - * If `areEqual = false` then this implies `left != right + k`. - */ - cached - predicate ensuresEq(Operand left, Operand right, int k, IRBlock block, boolean areEqual) { - exists(boolean testIsTrue | - compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) - ) - } - - /** - * Holds if (determined by this guard) `left == right + k` must be `areEqual` on the edge from - * `pred` to `succ`. If `areEqual = false` then this implies `left != right + k`. - */ - cached - predicate ensuresEqEdge( - Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean areEqual - ) { - exists(boolean testIsTrue | - compares_eq(this, left, right, k, areEqual, testIsTrue) and - this.controlsEdge(pred, succ, testIsTrue) - ) - } - - /** - * Holds if this condition controls `block`, meaning that `block` is only - * entered if the value of this condition is `testIsTrue`. This helper - * predicate does not necessarily hold for binary logical operations like - * `&&` and `||`. See the detailed explanation on predicate `controls`. - */ - private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { - not isUnreachedBlock(controlled) and - exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | - exists(IRBlock succ | - testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() - or - testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() - | - branch.getCondition() = this and - succ.dominates(controlled) and - forall(IRBlock pred | pred.getASuccessor() = succ | - pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() - ) - ) - ) - } -} - -private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) { - result.getCondition() = guard - or - exists(LogicalNotInstruction cond | - result = get_branch_for_condition(cond) and cond.getUnary() = guard - ) -} - -/** - * Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`. - * - * Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`. - */ -private predicate compares_eq( - Instruction test, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue -) { - /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */ - exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) | - areEqual = true and testIsTrue = eq - or - areEqual = false and testIsTrue = eq.booleanNot() - ) - or - // I think this is handled by forwarding in controlsBlock. - //or - //logical_comparison_eq(test, left, right, k, areEqual, testIsTrue) - /* a == b + k => b == a - k */ - exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue)) - or - complex_eq(test, left, right, k, areEqual, testIsTrue) - or - /* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */ - exists(boolean isFalse | testIsTrue = isFalse.booleanNot() | - compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, isFalse) - ) -} - -/** Rearrange various simple comparisons into `left == right + k` form. */ -private predicate simple_comparison_eq( - CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual -) { - left = cmp.getLeftOperand() and - cmp instanceof CompareEQInstruction and - right = cmp.getRightOperand() and - k = 0 and - areEqual = true - or - left = cmp.getLeftOperand() and - cmp instanceof CompareNEInstruction and - right = cmp.getRightOperand() and - k = 0 and - areEqual = false -} - -private predicate complex_eq( - CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue -) { - sub_eq(cmp, left, right, k, areEqual, testIsTrue) - or - add_eq(cmp, left, right, k, areEqual, testIsTrue) -} - -/* - * Simplification of inequality expressions - * Simplify conditions in the source to the canonical form l < r + k. - */ - -/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */ -private predicate compares_lt( - Instruction test, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue -) { - /* In the simple case, the test is the comparison, so isLt = testIsTrue */ - simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true - or - simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false - or - complex_lt(test, left, right, k, isLt, testIsTrue) - or - /* (not (left < right + k)) => (left >= right + k) */ - exists(boolean isGe | isLt = isGe.booleanNot() | - compares_ge(test, left, right, k, isGe, testIsTrue) - ) - or - /* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */ - exists(boolean isFalse | testIsTrue = isFalse.booleanNot() | - compares_lt(test.(LogicalNotInstruction).getUnary(), left, right, k, isLt, isFalse) - ) -} - -/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */ -private predicate compares_ge( - Instruction test, Operand left, Operand right, int k, boolean isGe, boolean testIsTrue -) { - exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue)) -} - -/** Rearrange various simple comparisons into `left < right + k` form. */ -private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Operand right, int k) { - left = cmp.getLeftOperand() and - cmp instanceof CompareLTInstruction and - right = cmp.getRightOperand() and - k = 0 - or - left = cmp.getLeftOperand() and - cmp instanceof CompareLEInstruction and - right = cmp.getRightOperand() and - k = 1 - or - right = cmp.getLeftOperand() and - cmp instanceof CompareGTInstruction and - left = cmp.getRightOperand() and - k = 0 - or - right = cmp.getLeftOperand() and - cmp instanceof CompareGEInstruction and - left = cmp.getRightOperand() and - k = 1 -} - -private predicate complex_lt( - CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue -) { - sub_lt(cmp, left, right, k, isLt, testIsTrue) - or - add_lt(cmp, left, right, k, isLt, testIsTrue) -} - -// left - x < right + c => left < right + (c+x) -// left < (right - x) + c => left < right + (c-x) -private predicate sub_lt( - CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue -) { - exists(SubInstruction lhs, int c, int x | - compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and - left = lhs.getLeftOperand() and - x = int_value(lhs.getRight()) and - k = c + x - ) - or - exists(SubInstruction rhs, int c, int x | - compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and - right = rhs.getLeftOperand() and - x = int_value(rhs.getRight()) and - k = c - x - ) -} - -// left + x < right + c => left < right + (c-x) -// left < (right + x) + c => left < right + (c+x) -private predicate add_lt( - CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue -) { - exists(AddInstruction lhs, int c, int x | - compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and - ( - left = lhs.getLeftOperand() and x = int_value(lhs.getRight()) - or - left = lhs.getRightOperand() and x = int_value(lhs.getLeft()) - ) and - k = c - x - ) - or - exists(AddInstruction rhs, int c, int x | - compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and - ( - right = rhs.getLeftOperand() and x = int_value(rhs.getRight()) - or - right = rhs.getRightOperand() and x = int_value(rhs.getLeft()) - ) and - k = c + x - ) -} - -// left - x == right + c => left == right + (c+x) -// left == (right - x) + c => left == right + (c-x) -private predicate sub_eq( - CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue -) { - exists(SubInstruction lhs, int c, int x | - compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and - left = lhs.getLeftOperand() and - x = int_value(lhs.getRight()) and - k = c + x - ) - or - exists(SubInstruction rhs, int c, int x | - compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and - right = rhs.getLeftOperand() and - x = int_value(rhs.getRight()) and - k = c - x - ) -} - -// left + x == right + c => left == right + (c-x) -// left == (right + x) + c => left == right + (c+x) -private predicate add_eq( - CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue -) { - exists(AddInstruction lhs, int c, int x | - compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and - ( - left = lhs.getLeftOperand() and x = int_value(lhs.getRight()) - or - left = lhs.getRightOperand() and x = int_value(lhs.getLeft()) - ) and - k = c - x - ) - or - exists(AddInstruction rhs, int c, int x | - compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and - ( - right = rhs.getLeftOperand() and x = int_value(rhs.getRight()) - or - right = rhs.getRightOperand() and x = int_value(rhs.getLeft()) - ) and - k = c + x - ) -} - -/** The int value of integer constant expression. */ -private int int_value(Instruction i) { result = i.(IntegerConstantInstruction).getValue().toInt() } diff --git a/csharp/ql/src/experimental/ir/internal/IRUtilities.qll b/csharp/ql/src/experimental/ir/internal/IRUtilities.qll deleted file mode 100644 index 1aeace91377..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IRUtilities.qll +++ /dev/null @@ -1,16 +0,0 @@ -private import csharp - -/** - * Get the actual type of the specified variable, as opposed to the declared - * type. - */ -Type getVariableType(Variable v) { - // C# doesn't seem to have any cases where the variable's actual type differs - // from its declared type. - result = v.getType() -} - -predicate hasCaseEdge(CaseStmt caseStmt, string minValue, string maxValue) { - minValue = caseStmt.getPattern().getValue() and - maxValue = minValue -} diff --git a/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll b/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll deleted file mode 100644 index 4af31745ab2..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Provides predicates for manipulating integer constants that are tracked by constant folding and - * similar analyses. - */ - -/** - * An alias used to represent the constant value of an integer, if one can be determined. If no - * single constant value can be determined, or if the constant value is out of the representable - * range, it will be represented as the special value `unknown()`. This allows `IntValue` to be used - * in contexts where there must always be a value for the `IntValue`, even if no constant value is - * known. - */ -class IntValue = int; - -/** - * Returns the value of the maximum representable integer. - */ -int maxValue() { result = 2147483647 } - -/** - * Returns the value of the minimum representable integer. - */ -int minValue() { result = -2147483647 } - -/** - * Returns a value representing an unknown integer. - */ -IntValue unknown() { result = -2147483648 } - -/** - * Holds if `n` has a known value. - */ -bindingset[n] -predicate hasValue(IntValue n) { n != unknown() } - -/** - * Returns a string representation of `n`. If `n` does not have a known value, the result is "??". - */ -bindingset[n] -string intValueToString(IntValue n) { if hasValue(n) then result = n.toString() else result = "??" } - -/** - * Holds if the value `f` is within the range of representable integers. - */ -bindingset[f] -pragma[inline] -private predicate isRepresentable(float f) { f >= minValue() and f <= maxValue() } - -/** - * Gets the value of `n`. Holds only if `n` has a known value. - */ -bindingset[n] -int getValue(IntValue n) { hasValue(n) and result = n } - -/** - * Returns `a + b`. If either input is unknown, or if the addition overflows, - * the result is unknown. - */ -bindingset[a, b] -IntValue add(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) and isRepresentable(a.(float) + b.(float)) - then result = a + b - else result = unknown() -} - -/** - * Returns `a - b`. If either input is unknown, or if the subtraction overflows, - * the result is unknown. - */ -bindingset[a, b] -IntValue sub(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) and isRepresentable(a.(float) - b.(float)) - then result = a - b - else result = unknown() -} - -/** - * Returns `a * b`. If the multiplication overflows, the result is unknown. If - * either input is unknown and the other input is non-zero, the result is - * unknown. - */ -bindingset[a, b] -IntValue mul(IntValue a, IntValue b) { - if a = 0 or b = 0 - then result = 0 - else - if hasValue(a) and hasValue(b) and isRepresentable(a.(float) * b.(float)) - then result = a * b - else result = unknown() -} - -/** - * Returns `a / b`. If either input is unknown, or if `b` is zero, the result is - * unknown. - */ -bindingset[a, b] -IntValue div(IntValue a, IntValue b) { - // Normally, integer division has to worry about overflow for INT_MIN/-1. - // However, since we use INT_MIN to represent an unknown value anyway, we only - // have to worry about division by zero. - if hasValue(a) and hasValue(b) and b != 0 then result = a / b else result = unknown() -} - -/** - * Returns `a == b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareEQ(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a = b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Returns `a != b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareNE(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a != b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Returns `a < b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareLT(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a < b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Returns `a > b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareGT(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a > b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Returns `a <= b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareLE(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a <= b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Returns `a >= b`. If either input is unknown, the result is unknown. - */ -bindingset[a, b] -IntValue compareGE(IntValue a, IntValue b) { - if hasValue(a) and hasValue(b) - then if a >= b then result = 1 else result = 0 - else result = unknown() -} - -/** - * Return `-a`. If `a` is unknown, the result is unknown. - */ -bindingset[a] -IntValue neg(IntValue a) { - result = -a // -INT_MIN = INT_MIN, so this preserves unknown -} - -/** - * Holds if `a` is equal to `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isEQ(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a = b } - -/** - * Holds if `a` is not equal to `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isNE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a != b } - -/** - * Holds if `a` is less than `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isLT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a < b } - -/** - * Holds if `a` is less than or equal to `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isLE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a <= b } - -/** - * Holds if `a` is greater than `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b } - -/** - * Holds if `a` is greater than or equal to `b`. Does not hold if either `a` or `b` is unknown. - */ -bindingset[a, b] -predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b } - -/** - * Converts the bit count in `bits` to a byte count and a bit count in the form - * "bytes:bits". If `bits` represents an integer number of bytes, the ":bits" section is omitted. - * If `bits` does not have a known value, the result is "?". - */ -bindingset[bits] -string bitsToBytesAndBits(IntValue bits) { - exists(int bytes, int leftoverBits | - hasValue(bits) and - bytes = bits / 8 and - leftoverBits = bits % 8 and - if leftoverBits = 0 then result = bytes.toString() else result = bytes + ":" + leftoverBits - ) - or - not hasValue(bits) and result = "?" -} - -/** - * Gets a printable string for a bit offset with possibly unknown value. - */ -bindingset[bitOffset] -string getBitOffsetString(IntValue bitOffset) { - if hasValue(bitOffset) - then - if bitOffset >= 0 - then result = "+" + bitsToBytesAndBits(bitOffset) - else result = "-" + bitsToBytesAndBits(neg(bitOffset)) - else result = "+?" -} diff --git a/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll b/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll deleted file mode 100644 index 4f8f4b4e672..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Support for integer intervals. - * An interval is represented as by its inclusive lower bound, `start`, and its exclusive upper bound, `end`. - * Either or both of `start` and `end` may have an unknown value. - */ - -import Overlap -private import IntegerConstant - -/** - * Gets the overlap relationship between the definition interval [`defStart`, `defEnd`) and the use interval - * [`useStart`, `useEnd`). - */ -bindingset[defStart, defEnd, useStart, useEnd] -Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntValue useEnd) { - if isEQ(defStart, useStart) and isEQ(defEnd, useEnd) - then result instanceof MustExactlyOverlap - else - if isLE(defStart, useStart) and isGE(defEnd, useEnd) - then result instanceof MustTotallyOverlap - else ( - not isLE(defEnd, useStart) and - not isGE(defStart, useEnd) and - result instanceof MayPartiallyOverlap - ) -} - -/** - * Gets a string representation of the interval [`start`, `end`). - */ -bindingset[start, end] -string getIntervalString(IntValue start, IntValue end) { - // We represent an interval has half-open, so print it as "[start..end)". - result = "[" + bitsToBytesAndBits(start) + ".." + bitsToBytesAndBits(end) + ")" -} diff --git a/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll b/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll deleted file mode 100644 index 0e24f283b17..00000000000 --- a/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Provides basic arithmetic operations that have no result if their result - * would overflow a 32-bit two's complement integer. - */ - -/** - * Gets the value of the maximum representable integer. - */ -int maxValue() { result = 2147483647 } - -/** - * Gets the value of the minimum representable integer. - */ -int minValue() { result = -2147483648 } - -/** - * Holds if the value `f` is within the range of representable integers. - */ -bindingset[f] -pragma[inline] -private predicate isRepresentable(float f) { f >= minValue() and f <= maxValue() } - -/** - * Returns `a + b`. If the addition overflows, there is no result. - */ -bindingset[a, b] -int add(int a, int b) { - isRepresentable(a.(float) + b.(float)) and - result = a + b -} - -/** - * Returns `a - b`. If the subtraction overflows, there is no result. - */ -bindingset[a, b] -int sub(int a, int b) { - isRepresentable(a.(float) - b.(float)) and - result = a - b -} - -/** - * Returns `a * b`. If the multiplication overflows, there is no result. If - * either input is not given, and the other input is non-zero, there is no - * result. - */ -bindingset[a, b] -int mul(int a, int b) { - a = 0 and - result = 0 - or - b = 0 and - result = 0 - or - isRepresentable(a.(float) * b.(float)) and - result = a * b -} - -/** - * Returns `a / b`. If the division overflows, there is no result. - */ -bindingset[a, b] -int div(int a, int b) { - b != 0 and - (a != minValue() or b != -1) and - result = a / b -} - -/** Returns `a == b`. */ -bindingset[a, b] -int compareEQ(int a, int b) { if a = b then result = 1 else result = 0 } - -/** Returns `a != b`. */ -bindingset[a, b] -int compareNE(int a, int b) { if a != b then result = 1 else result = 0 } - -/** Returns `a < b`. */ -bindingset[a, b] -int compareLT(int a, int b) { if a < b then result = 1 else result = 0 } - -/** Returns `a > b`. */ -bindingset[a, b] -int compareGT(int a, int b) { if a > b then result = 1 else result = 0 } - -/** Returns `a <= b`. */ -bindingset[a, b] -int compareLE(int a, int b) { if a <= b then result = 1 else result = 0 } - -/** Returns `a >= b`. */ -bindingset[a, b] -int compareGE(int a, int b) { if a >= b then result = 1 else result = 0 } - -/** - * Returns `-a`. If the negation would overflow, there is no result. - */ -bindingset[a] -int neg(int a) { - a != minValue() and - result = -a -} diff --git a/csharp/ql/src/experimental/ir/internal/Overlap.qll b/csharp/ql/src/experimental/ir/internal/Overlap.qll deleted file mode 100644 index ca643b56cbb..00000000000 --- a/csharp/ql/src/experimental/ir/internal/Overlap.qll +++ /dev/null @@ -1,70 +0,0 @@ -private newtype TOverlap = - TMayPartiallyOverlap() or - TMustTotallyOverlap() or - TMustExactlyOverlap() - -/** - * Represents a possible overlap between two memory ranges. - */ -abstract class Overlap extends TOverlap { - abstract string toString(); - - /** - * Gets a value representing how precise this overlap is. The higher the value, the more precise - * the overlap. The precision values are ordered as - * follows, from most to least precise: - * `MustExactlyOverlap` - * `MustTotallyOverlap` - * `MayPartiallyOverlap` - */ - abstract int getPrecision(); -} - -/** - * Represents a partial overlap between two memory ranges, which may or may not - * actually occur in practice. - */ -class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap { - final override string toString() { result = "MayPartiallyOverlap" } - - final override int getPrecision() { result = 0 } -} - -/** - * Represents an overlap in which the first memory range is known to include all - * bits of the second memory range, but may be larger or have a different type. - */ -class MustTotallyOverlap extends Overlap, TMustTotallyOverlap { - final override string toString() { result = "MustTotallyOverlap" } - - final override int getPrecision() { result = 1 } -} - -/** - * Represents an overlap between two memory ranges that have the same extent and - * the same type. - */ -class MustExactlyOverlap extends Overlap, TMustExactlyOverlap { - final override string toString() { result = "MustExactlyOverlap" } - - final override int getPrecision() { result = 2 } -} - -/** - * Gets the `Overlap` that best represents the relationship between two memory locations `a` and - * `c`, where `getOverlap(a, b) = previousOverlap` and `getOverlap(b, c) = newOverlap`, for some - * intermediate memory location `b`. - */ -Overlap combineOverlap(Overlap previousOverlap, Overlap newOverlap) { - // Note that it's possible that two less precise overlaps could combine to result in a more - // precise overlap. For example, both `previousOverlap` and `newOverlap` could be - // `MustTotallyOverlap` even though the actual relationship between `a` and `c` is - // `MustExactlyOverlap`. We will still return `MustTotallyOverlap` as the best conservative - // approximation we can make without additional input information. - result = - min(Overlap overlap | - overlap = [previousOverlap, newOverlap] - | - overlap order by overlap.getPrecision() - ) -} diff --git a/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll b/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll deleted file mode 100644 index 8950c2cd8a8..00000000000 --- a/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll +++ /dev/null @@ -1,32 +0,0 @@ -import csharp - -newtype TTempVariableTag = - ConditionValueTempVar() or - ReturnValueTempVar() or - ThrowTempVar() or - LambdaTempVar() or - ForeachEnumTempVar() or - LockedVarTemp() or - LockWasTakenTemp() or - EllipsisTempVar() or - ThisTempVar() - -string getTempVariableTagId(TTempVariableTag tag) { - tag = ConditionValueTempVar() and result = "CondVal" - or - tag = ReturnValueTempVar() and result = "Ret" - or - tag = ThrowTempVar() and result = "Throw" - or - tag = LambdaTempVar() and result = "Lambda" - or - tag = ForeachEnumTempVar() and result = "ForeachEnum" - or - tag = LockedVarTemp() and result = "LockedVarTemp" - or - tag = LockWasTakenTemp() and result = "LockWasTakenTemp" - or - tag = EllipsisTempVar() and result = "Ellipsis" - or - tag = ThisTempVar() and result = "This" -} diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll deleted file mode 100644 index 295c76a025d..00000000000 --- a/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll +++ /dev/null @@ -1,79 +0,0 @@ -import csharp -private import experimental.ir.IR -private import experimental.ir.ValueNumbering - -private newtype TBound = - TBoundZero() or - TBoundValueNumber(ValueNumber vn) { - exists(Instruction i | - vn.getAnInstruction() = i and - ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType - ) and - not vn.getAnInstruction() instanceof ConstantInstruction - | - i instanceof PhiInstruction - or - i instanceof InitializeParameterInstruction - or - i instanceof CallInstruction - or - i instanceof VariableAddressInstruction - or - i instanceof FieldAddressInstruction - or - i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction - or - i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction - or - i.getAUse() instanceof ArgumentOperand - ) - } - -/** - * A bound that may be inferred for an expression plus/minus an integer delta. - */ -abstract class Bound extends TBound { - abstract string toString(); - - /** Gets an expression that equals this bound plus `delta`. */ - abstract Instruction getInstruction(int delta); - - /** Gets an expression that equals this bound. */ - Instruction getInstruction() { result = this.getInstruction(0) } - - abstract Location getLocation(); -} - -/** - * The bound that corresponds to the integer 0. This is used to represent all - * integer bounds as bounds are always accompanied by an added integer delta. - */ -class ZeroBound extends Bound, TBoundZero { - override string toString() { result = "0" } - - override Instruction getInstruction(int delta) { - result.(ConstantValueInstruction).getValue().toInt() = delta - } - - override Location getLocation() { result instanceof EmptyLocation } -} - -/** - * A bound corresponding to the value of an `Instruction`. - */ -class ValueNumberBound extends Bound, TBoundValueNumber { - ValueNumber vn; - - ValueNumberBound() { this = TBoundValueNumber(vn) } - - /** Gets the SSA variable that equals this bound. */ - override Instruction getInstruction(int delta) { - this = TBoundValueNumber(valueNumber(result)) and delta = 0 - } - - override string toString() { result = vn.getExampleInstruction().toString() } - - override Location getLocation() { result = vn.getLocation() } -} diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll deleted file mode 100644 index 1febf611652..00000000000 --- a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll +++ /dev/null @@ -1,633 +0,0 @@ -/** - * Provides classes and predicates for range analysis. - * - * An inferred bound can either be a specific integer or a `ValueNumber` - * representing the abstract value of a set of `Instruction`s. - * - * If an inferred bound relies directly on a condition, then this condition is - * reported as the reason for the bound. - */ - -/* - * This library tackles range analysis as a flow problem. Consider e.g.: - * ```csharp - * len = arr.length; - * if (x < len) { ... y = x-1; ... y ... } - * ``` - * In this case we would like to infer `y <= arr.length - 2`, and this is - * accomplished by tracking the bound through a sequence of steps: - * ``` - * arr.length --> len = .. --> x < len --> x-1 --> y = .. --> y - * ``` - * - * In its simplest form the step relation `I1 --> I2` relates two `Instruction`s - * such that `I1 <= B` implies `I2 <= B` for any `B` (with a second separate - * step relation handling lower bounds). Examples of such steps include - * assignments `I2 = I1` and conditions `x <= I1` where `I2` is a use of `x` - * guarded by the condition. - * - * In order to handle subtractions and additions with constants, and strict - * comparisons, the step relation is augmented with an integer delta. With this - * generalization `I1 --(delta)--> I2` relates two `Instruction`s and an integer - * such that `I1 <= B` implies `I2 <= B + delta` for any `B`. This corresponds - * to the predicate `boundFlowStep`. - * - * The complete range analysis is then implemented as the transitive closure of - * the step relation summing the deltas along the way. If `I1` transitively - * steps to `I2`, `delta` is the sum of deltas along the path, and `B` is an - * interesting bound equal to the value of `I1` then `I2 <= B + delta`. This - * corresponds to the predicate `boundedInstruction`. - * - * Bounds come in two forms: either they are relative to zero (and thus provide - * a constant bound), or they are relative to some program value. This value is - * represented by the `ValueNumber` class, each instance of which represents a - * set of `Instructions` that must have the same value. - * - * Phi nodes need a little bit of extra handling. Consider `x0 = phi(x1, x2)`. - * There are essentially two cases: - * - If `x1 <= B + d1` and `x2 <= B + d2` then `x0 <= B + max(d1,d2)`. - * - If `x1 <= B + d1` and `x2 <= x0 + d2` with `d2 <= 0` then `x0 <= B + d1`. - * The first case is for whenever a bound can be proven without taking looping - * into account. The second case is relevant when `x2` comes from a back-edge - * where we can prove that the variable has been non-increasing through the - * loop-iteration as this means that any upper bound that holds prior to the - * loop also holds for the variable during the loop. - * This generalizes to a phi node with `n` inputs, so if - * `x0 = phi(x1, ..., xn)` and `xi <= B + delta` for one of the inputs, then we - * also have `x0 <= B + delta` if we can prove either: - * - `xj <= B + d` with `d <= delta` or - * - `xj <= x0 + d` with `d <= 0` - * for each input `xj`. - * - * As all inferred bounds can be related directly to a path in the source code - * the only source of non-termination is if successive redundant (and thereby - * increasingly worse) bounds are calculated along a loop in the source code. - * We prevent this by weakening the bound to a small finite set of bounds when - * a path follows a second back-edge (we postpone weakening till the second - * back-edge as a precise bound might require traversing a loop once). - */ - -import csharp -private import experimental.ir.IR -private import experimental.ir.internal.IRGuards -private import experimental.ir.ValueNumbering -private import RangeUtils -private import SignAnalysis -import Bound - -cached -private module RangeAnalysisCache { - cached - module RangeAnalysisPublic { - /** - * Holds if `b + delta` is a valid bound for `i`. - * - `upper = true` : `i <= b + delta` - * - `upper = false` : `i >= b + delta` - * - * The reason for the bound is given by `reason` and may be either a condition - * or `NoReason` if the bound was proven directly without the use of a bounding - * condition. - */ - cached - predicate boundedInstruction(Instruction i, Bound b, int delta, boolean upper, Reason reason) { - boundedInstruction(i, b, delta, upper, _, _, reason) - } - - /** - * Holds if `b + delta` is a valid bound for `op`. - * - `upper = true` : `op <= b + delta` - * - `upper = false` : `op >= b + delta` - * - * The reason for the bound is given by `reason` and may be either a condition - * or `NoReason` if the bound was proven directly without the use of a bounding - * condition. - */ - cached - predicate boundedOperand(Operand op, Bound b, int delta, boolean upper, Reason reason) { - boundedNonPhiOperand(op, b, delta, upper, _, _, reason) - or - boundedPhiOperand(op, b, delta, upper, _, _, reason) - } - } - - /** - * Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`. - */ - cached - predicate possibleReason(IRGuardCondition guard) { - guard = boundFlowCond(_, _, _, _, _) - or - guard = eqFlowCond(_, _, _, _, _) - } -} - -private import RangeAnalysisCache -import RangeAnalysisPublic - -/** - * Gets a condition that tests whether `vn` equals `bound + delta`. - * - * If the condition evaluates to `testIsTrue`: - * - `isEq = true` : `vn == bound + delta` - * - `isEq = false` : `vn != bound + delta` - */ -private IRGuardCondition eqFlowCond( - ValueNumber vn, Operand bound, int delta, boolean isEq, boolean testIsTrue -) { - result.comparesEq(vn.getAUse(), bound, delta, isEq, testIsTrue) -} - -/** - * Holds if `op1 + delta` is a valid bound for `op2`. - * - `upper = true` : `op2 <= op1 + delta` - * - `upper = false` : `op2 >= op1 + delta` - */ -private predicate boundFlowStepSsa( - NonPhiOperand op2, Operand op1, int delta, boolean upper, Reason reason -) { - exists(IRGuardCondition guard, boolean testIsTrue | - guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and - guard.controls(op2.getUse().getBlock(), testIsTrue) and - reason = TCondReason(guard) - ) -} - -/** - * Gets a condition that tests whether `vn` is bounded by `bound + delta`. - * - * If the condition evaluates to `testIsTrue`: - * - `upper = true` : `vn <= bound + delta` - * - `upper = false` : `vn >= bound + delta` - */ -private IRGuardCondition boundFlowCond( - ValueNumber vn, NonPhiOperand bound, int delta, boolean upper, boolean testIsTrue -) { - exists(int d | - result.comparesLt(vn.getAUse(), bound, d, upper, testIsTrue) and - // `comparesLt` provides bounds of the form `x < y + k` or `x >= y + k`, but we need - // `x <= y + k` so we strengthen here. `testIsTrue` has the same semantics in `comparesLt` as - // it does here, so we don't need to account for it. - if upper = true then delta = d - 1 else delta = d - ) - or - result = eqFlowCond(vn, bound, delta, true, testIsTrue) and - (upper = true or upper = false) -} - -private newtype TReason = - TNoReason() or - TCondReason(IRGuardCondition guard) { possibleReason(guard) } - -/** - * A reason for an inferred bound. This can either be `CondReason` if the bound - * is due to a specific condition, or `NoReason` if the bound is inferred - * without going through a bounding condition. - */ -abstract class Reason extends TReason { - abstract string toString(); -} - -class NoReason extends Reason, TNoReason { - override string toString() { result = "NoReason" } -} - -class CondReason extends Reason, TCondReason { - IRGuardCondition getCond() { this = TCondReason(result) } - - override string toString() { result = this.getCond().toString() } -} - -/** - * Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of - * range analysis. - */ -pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and - ( - fromtyp instanceof UnsignedIntegralType - or - totyp instanceof SignedIntegralType - ) - or - fromtyp.getSize() <= totyp.getSize() and - ( - fromtyp instanceof SignedIntegralType and - totyp instanceof SignedIntegralType - or - fromtyp instanceof UnsignedIntegralType and - totyp instanceof UnsignedIntegralType - ) -} - -private class SafeCastInstruction extends ConvertInstruction { - SafeCastInstruction() { - safeCast(this.getResultType(), this.getUnary().getResultType()) - or - this.getResultType() instanceof PointerType and - this.getUnary().getResultType() instanceof PointerType - } -} - -/** - * Holds if `typ` is a small integral type with the given lower and upper bounds. - */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ instanceof SignedIntegralType and - typ.getSize() = 1 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() - or - typ instanceof UnsignedIntegralType and - typ.getSize() = 1 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() - or - typ instanceof SignedIntegralType and - typ.getSize() = 2 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() - or - typ instanceof UnsignedIntegralType and - typ.getSize() = 2 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() -} - -/** - * A cast to a small integral type that may overflow or underflow. - */ -private class NarrowingCastInstruction extends ConvertInstruction { - NarrowingCastInstruction() { - not this instanceof SafeCastInstruction and - typeBound(this.getResultType(), _, _) - } - - /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(this.getResultType(), result, _) } - - /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(this.getResultType(), _, result) } -} - -/** - * Holds if `op + delta` is a valid bound for `i`. - * - `upper = true` : `i <= op + delta` - * - `upper = false` : `i >= op + delta` - */ -private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, boolean upper) { - valueFlowStep(i, op, delta) and - (upper = true or upper = false) - or - i.(SafeCastInstruction).getAnOperand() = op and - delta = 0 and - (upper = true or upper = false) - or - exists(Operand x | - i.(AddInstruction).getAnOperand() = op and - i.(AddInstruction).getAnOperand() = x and - op != x - | - not exists(getValue(getConstantValue(op.getUse()))) and - not exists(getValue(getConstantValue(x.getUse()))) and - if strictlyPositive(x) - then upper = false and delta = 1 - else - if positive(x) - then upper = false and delta = 0 - else - if strictlyNegative(x) - then upper = true and delta = -1 - else - if negative(x) - then upper = true and delta = 0 - else none() - ) - or - exists(Operand x | - exists(SubInstruction sub | - i = sub and - sub.getLeftOperand() = op and - sub.getRightOperand() = x - ) - | - // `x` with constant value is covered by valueFlowStep - not exists(getValue(getConstantValue(x.getUse()))) and - if strictlyPositive(x) - then upper = true and delta = -1 - else - if positive(x) - then upper = true and delta = 0 - else - if strictlyNegative(x) - then upper = false and delta = 1 - else - if negative(x) - then upper = false and delta = 0 - else none() - ) - or - i.(RemInstruction).getRightOperand() = op and positive(op) and delta = -1 and upper = true - or - i.(RemInstruction).getLeftOperand() = op and positive(op) and delta = 0 and upper = true - or - i.(BitAndInstruction).getAnOperand() = op and positive(op) and delta = 0 and upper = true - or - i.(BitOrInstruction).getAnOperand() = op and - positiveInstruction(i) and - delta = 0 and - upper = false - // TODO: min, max, rand -} - -private predicate boundFlowStepMul(Instruction i1, Operand op, int factor) { - exists(Instruction c, int k | k = getValue(getConstantValue(c)) and k > 0 | - i1.(MulInstruction).hasOperands(op, c.getAUse()) and factor = k - or - exists(ShiftLeftInstruction i | - i = i1 and i.getLeftOperand() = op and i.getRightOperand() = c.getAUse() and factor = 2.pow(k) - ) - ) -} - -private predicate boundFlowStepDiv(Instruction i1, Operand op, int factor) { - exists(Instruction c, int k | k = getValue(getConstantValue(c)) and k > 0 | - exists(DivInstruction i | - i = i1 and i.getLeftOperand() = op and i.getRight() = c and factor = k - ) - or - exists(ShiftRightInstruction i | - i = i1 and i.getLeftOperand() = op and i.getRight() = c and factor = 2.pow(k) - ) - ) -} - -/** - * Holds if `b` is a valid bound for `op` - */ -pragma[noinline] -private predicate boundedNonPhiOperand( - NonPhiOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, - Reason reason -) { - exists(NonPhiOperand op2, int d1, int d2 | - boundFlowStepSsa(op, op2, d1, upper, reason) and - boundedNonPhiOperand(op2, b, d2, upper, fromBackEdge, origdelta, _) and - delta = d1 + d2 - ) - or - boundedInstruction(op.getDef(), b, delta, upper, fromBackEdge, origdelta, reason) - or - exists(int d, Reason r1, Reason r2 | - boundedNonPhiOperand(op, b, d, upper, fromBackEdge, origdelta, r2) - | - unequalOperand(op, b, d, r1) and - ( - upper = true and delta = d - 1 - or - upper = false and delta = d + 1 - ) and - ( - reason = r1 - or - reason = r2 and not r2 instanceof NoReason - ) - ) -} - -/** - * Holds if `op1 + delta` is a valid bound for `op2`. - * - `upper = true` : `op2 <= op1 + delta` - * - `upper = false` : `op2 >= op1 + delta` - */ -private predicate boundFlowStepPhi( - PhiInputOperand op2, Operand op1, int delta, boolean upper, Reason reason -) { - op2.getDef().(CopyInstruction).getSourceValueOperand() = op1 and - (upper = true or upper = false) and - reason = TNoReason() and - delta = 0 - or - exists(IRGuardCondition guard, boolean testIsTrue | - guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and - guard.controlsEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and - reason = TCondReason(guard) - ) -} - -private predicate boundedPhiOperand( - PhiInputOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, - Reason reason -) { - exists(NonPhiOperand op2, int d1, int d2, Reason r1, Reason r2 | - boundFlowStepPhi(op, op2, d1, upper, r1) and - boundedNonPhiOperand(op2, b, d2, upper, fromBackEdge, origdelta, r2) and - delta = d1 + d2 and - (if r1 instanceof NoReason then reason = r2 else reason = r1) - ) - or - boundedInstruction(op.getDef(), b, delta, upper, fromBackEdge, origdelta, reason) - or - exists(int d, Reason r1, Reason r2 | - boundedInstruction(op.getDef(), b, d, upper, fromBackEdge, origdelta, r2) - | - unequalOperand(op, b, d, r1) and - ( - upper = true and delta = d - 1 - or - upper = false and delta = d + 1 - ) and - ( - reason = r1 - or - reason = r2 and not r2 instanceof NoReason - ) - ) -} - -/** Holds if `op2 != op1 + delta` at `pos`. */ -private predicate unequalFlowStep(Operand op2, Operand op1, int delta, Reason reason) { - exists(IRGuardCondition guard, boolean testIsTrue | - guard = eqFlowCond(valueNumberOfOperand(op2), op1, delta, false, testIsTrue) and - guard.controls(op2.getUse().getBlock(), testIsTrue) and - reason = TCondReason(guard) - ) -} - -/** - * Holds if `op != b + delta` at `pos`. - */ -private predicate unequalOperand(Operand op, Bound b, int delta, Reason reason) { - exists(Operand op2, int d1, int d2 | - unequalFlowStep(op, op2, d1, reason) and - boundedNonPhiOperand(op2, b, d2, true, _, _, _) and - boundedNonPhiOperand(op2, b, d2, false, _, _, _) and - delta = d1 + d2 - ) -} - -private predicate boundedPhiCandValidForEdge( - PhiInstruction phi, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, - Reason reason, PhiInputOperand op -) { - boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and - ( - exists(int d | boundedPhiInp1(phi, op, b, d, upper) | upper = true and d <= delta) - or - exists(int d | boundedPhiInp1(phi, op, b, d, upper) | upper = false and d >= delta) - or - selfBoundedPhiInp(phi, op, upper) - ) -} - -/** Weakens a delta to lie in the range `[-1..1]`. */ -bindingset[delta, upper] -private int weakenDelta(boolean upper, int delta) { - delta in [-1 .. 1] and result = delta - or - upper = true and result = -1 and delta < -1 - or - upper = false and result = 1 and delta > 1 -} - -private predicate boundedPhiInp( - PhiInstruction phi, PhiInputOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, - int origdelta, Reason reason -) { - phi.getAnOperand() = op and - exists(int d, boolean fromBackEdge0 | - boundedPhiOperand(op, b, d, upper, fromBackEdge0, origdelta, reason) - or - b.(ValueNumberBound).getInstruction() = op.getDef() and - d = 0 and - (upper = true or upper = false) and - fromBackEdge0 = false and - origdelta = 0 and - reason = TNoReason() - | - if backEdge(phi, op) - then - fromBackEdge = true and - ( - fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta - or - fromBackEdge0 = false and delta = d - ) - else ( - delta = d and fromBackEdge = fromBackEdge0 - ) - ) -} - -pragma[noinline] -private predicate boundedPhiInp1( - PhiInstruction phi, PhiInputOperand op, Bound b, int delta, boolean upper -) { - boundedPhiInp(phi, op, b, delta, upper, _, _, _) -} - -private predicate selfBoundedPhiInp(PhiInstruction phi, PhiInputOperand op, boolean upper) { - exists(int d, ValueNumberBound phibound | - phibound.getInstruction() = phi and - boundedPhiInp(phi, op, phibound, d, upper, _, _, _) and - ( - upper = true and d <= 0 - or - upper = false and d >= 0 - ) - ) -} - -pragma[noinline] -private predicate boundedPhiCand( - PhiInstruction phi, boolean upper, Bound b, int delta, boolean fromBackEdge, int origdelta, - Reason reason -) { - boundedPhiInp(phi, _, b, delta, upper, fromBackEdge, origdelta, reason) -} - -/** - * Holds if the value being cast has an upper (for `upper = true`) or lower - * (for `upper = false`) bound within the bounds of the resulting type. - * For `upper = true` this means that the cast will not overflow and for - * `upper = false` this means that the cast will not underflow. - */ -private predicate safeNarrowingCast(NarrowingCastInstruction cast, boolean upper) { - exists(int bound | - boundedNonPhiOperand(cast.getAnOperand(), any(ZeroBound zb), bound, upper, _, _, _) - | - upper = true and bound <= cast.getUpperBound() - or - upper = false and bound >= cast.getLowerBound() - ) -} - -pragma[noinline] -private predicate boundedCastExpr( - NarrowingCastInstruction cast, Bound b, int delta, boolean upper, boolean fromBackEdge, - int origdelta, Reason reason -) { - boundedNonPhiOperand(cast.getAnOperand(), b, delta, upper, fromBackEdge, origdelta, reason) -} - -/** - * Holds if `b + delta` is a valid bound for `i`. - * - `upper = true` : `i <= b + delta` - * - `upper = false` : `i >= b + delta` - */ -private predicate boundedInstruction( - Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, - Reason reason -) { - i instanceof PhiInstruction and - forex(PhiInputOperand op | op = i.getAnOperand() | - boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op) - ) - or - i = b.getInstruction(delta) and - (upper = true or upper = false) and - fromBackEdge = false and - origdelta = delta and - reason = TNoReason() - or - exists(Operand mid, int d1, int d2 | - boundFlowStep(i, mid, d1, upper) and - boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and - delta = d1 + d2 and - not exists(getValue(getConstantValue(i))) - ) - or - exists(Operand mid, int factor, int d | - boundFlowStepMul(i, mid, factor) and - boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and - b instanceof ZeroBound and - delta = d * factor and - not exists(getValue(getConstantValue(i))) - ) - or - exists(Operand mid, int factor, int d | - boundFlowStepDiv(i, mid, factor) and - boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and - d >= 0 and - b instanceof ZeroBound and - delta = d / factor and - not exists(getValue(getConstantValue(i))) - ) - or - exists(NarrowingCastInstruction cast | - cast = i and - safeNarrowingCast(cast, upper.booleanNot()) and - boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason) - ) - or - exists(PropertyAccess pa | - i.(CallInstruction).getAst() = pa and - pa.getProperty().getName() = "Length" and - b instanceof ZeroBound and - delta = origdelta and - (upper = true or upper = false) and - fromBackEdge = false and - delta = getArrayDim(pa.getQualifier().(VariableAccess).getTarget()) and - reason = TNoReason() - ) -} diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll deleted file mode 100644 index b7fdfc3546f..00000000000 --- a/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll +++ /dev/null @@ -1,96 +0,0 @@ -import csharp -private import experimental.ir.IR -// TODO: move this dependency -import experimental.ir.internal.IntegerConstant - -// TODO: move this out of test code -language[monotonicAggregates] -IntValue getConstantValue(Instruction instr) { - result = instr.(IntegerConstantInstruction).getValue().toInt() - or - exists(BinaryInstruction binInstr, IntValue left, IntValue right | - binInstr = instr and - left = getConstantValue(binInstr.getLeft()) and - right = getConstantValue(binInstr.getRight()) and - ( - binInstr instanceof AddInstruction and result = add(left, right) - or - binInstr instanceof SubInstruction and result = sub(left, right) - or - binInstr instanceof MulInstruction and result = mul(left, right) - or - binInstr instanceof DivInstruction and result = div(left, right) - ) - ) - or - result = getConstantValue(instr.(CopyInstruction).getSourceValue()) - or - exists(PhiInstruction phi | - phi = instr and - result = - max(PhiInputOperand operand | - operand = phi.getAnOperand() - | - getConstantValue(operand.getDef()) - ) and - result = - min(PhiInputOperand operand | - operand = phi.getAnOperand() - | - getConstantValue(operand.getDef()) - ) - ) -} - -/** - * Gets the dimension of the array (either the declared size, or the - * size of the initializer); if no size is declared and no initializer used, - * the predicate does not hold. - */ -IntValue getArrayDim(Variable arr) { - exists(ArrayCreation ac | - arr.getInitializer() = ac and - if exists(ac.getLengthArgument(0)) - then result = ac.getLengthArgument(0).getValue().toInt() - else result = ac.getInitializer().getNumberOfElements() - ) -} - -predicate valueFlowStep(Instruction i, Operand op, int delta) { - i.(CopyInstruction).getSourceValueOperand() = op and delta = 0 - or - exists(Operand x | - i.(AddInstruction).getAnOperand() = op and - i.(AddInstruction).getAnOperand() = x and - op != x - | - delta = getValue(getConstantValue(x.getDef())) - ) - or - exists(Operand x | - i.(SubInstruction).getLeftOperand() = op and - i.(SubInstruction).getRightOperand() = x - | - delta = -getValue(getConstantValue(x.getDef())) - ) - or - exists(Operand x | - i.(PointerAddInstruction).getAnOperand() = op and - i.(PointerAddInstruction).getAnOperand() = x and - op != x - | - delta = i.(PointerAddInstruction).getElementSize() * getValue(getConstantValue(x.getDef())) - ) - or - exists(Operand x | - i.(PointerSubInstruction).getLeftOperand() = op and - i.(PointerSubInstruction).getRightOperand() = x - | - delta = i.(PointerSubInstruction).getElementSize() * -getValue(getConstantValue(x.getDef())) - ) -} - -predicate backEdge(PhiInstruction phi, PhiInputOperand op) { - phi.getAnOperand() = op and - phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_) -} diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll deleted file mode 100644 index b74f7c90db5..00000000000 --- a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll +++ /dev/null @@ -1,585 +0,0 @@ -/** - * Provides sign analysis to determine whether expression are always positive - * or negative. - * - * The analysis is implemented as an abstract interpretation over the - * three-valued domain `{negative, zero, positive}`. - */ - -import csharp -private import experimental.ir.IR -private import experimental.ir.internal.IRGuards -private import experimental.ir.ValueNumbering -private import SignAnalysisCached - -private newtype TSign = - TNeg() or - TZero() or - TPos() - -private class Sign extends TSign { - string toString() { - result = "-" and this = TNeg() - or - result = "0" and this = TZero() - or - result = "+" and this = TPos() - } - - Sign inc() { - this = TNeg() and result = TNeg() - or - this = TNeg() and result = TZero() - or - this = TZero() and result = TPos() - or - this = TPos() and result = TPos() - } - - Sign dec() { result.inc() = this } - - Sign neg() { - this = TNeg() and result = TPos() - or - this = TZero() and result = TZero() - or - this = TPos() and result = TNeg() - } - - Sign bitnot() { - this = TNeg() and result = TPos() - or - this = TNeg() and result = TZero() - or - this = TZero() and result = TNeg() - or - this = TPos() and result = TNeg() - } - - Sign add(Sign s) { - this = TZero() and result = s - or - s = TZero() and result = this - or - this = s and this = result - or - this = TPos() and s = TNeg() - or - this = TNeg() and s = TPos() - } - - Sign mul(Sign s) { - result = TZero() and this = TZero() - or - result = TZero() and s = TZero() - or - result = TNeg() and this = TPos() and s = TNeg() - or - result = TNeg() and this = TNeg() and s = TPos() - or - result = TPos() and this = TPos() and s = TPos() - or - result = TPos() and this = TNeg() and s = TNeg() - } - - Sign div(Sign s) { - result = TZero() and s = TNeg() - or - result = TZero() and s = TPos() - or - result = TNeg() and this = TPos() and s = TNeg() - or - result = TNeg() and this = TNeg() and s = TPos() - or - result = TPos() and this = TPos() and s = TPos() - or - result = TPos() and this = TNeg() and s = TNeg() - } - - Sign rem(Sign s) { - result = TZero() and s = TNeg() - or - result = TZero() and s = TPos() - or - result = this and s = TNeg() - or - result = this and s = TPos() - } - - Sign bitand(Sign s) { - result = TZero() and this = TZero() - or - result = TZero() and s = TZero() - or - result = TZero() and this = TPos() - or - result = TZero() and s = TPos() - or - result = TNeg() and this = TNeg() and s = TNeg() - or - result = TPos() and this = TNeg() and s = TPos() - or - result = TPos() and this = TPos() and s = TNeg() - or - result = TPos() and this = TPos() and s = TPos() - } - - Sign bitor(Sign s) { - result = TZero() and this = TZero() and s = TZero() - or - result = TNeg() and this = TNeg() - or - result = TNeg() and s = TNeg() - or - result = TPos() and this = TPos() and s = TZero() - or - result = TPos() and this = TZero() and s = TPos() - or - result = TPos() and this = TPos() and s = TPos() - } - - Sign bitxor(Sign s) { - result = TZero() and this = s - or - result = this and s = TZero() - or - result = s and this = TZero() - or - result = TPos() and this = TPos() and s = TPos() - or - result = TNeg() and this = TNeg() and s = TPos() - or - result = TNeg() and this = TPos() and s = TNeg() - or - result = TPos() and this = TNeg() and s = TNeg() - } - - Sign lshift(Sign s) { - result = TZero() and this = TZero() - or - result = this and s = TZero() - or - this != TZero() and s != TZero() - } - - Sign rshift(Sign s) { - result = TZero() and this = TZero() - or - result = this and s = TZero() - or - result = TNeg() and this = TNeg() - or - result != TNeg() and this = TPos() and s != TZero() - } - - Sign urshift(Sign s) { - result = TZero() and this = TZero() - or - result = this and s = TZero() - or - result != TZero() and this = TNeg() and s != TZero() - or - result != TNeg() and this = TPos() and s != TZero() - } -} - -private Sign certainInstructionSign(Instruction inst) { - exists(int i | inst.(IntegerConstantInstruction).getValue().toInt() = i | - i < 0 and result = TNeg() - or - i = 0 and result = TZero() - or - i > 0 and result = TPos() - ) - or - exists(float f | f = inst.(FloatConstantInstruction).getValue().toFloat() | - f < 0 and result = TNeg() - or - f = 0 and result = TZero() - or - f > 0 and result = TPos() - ) -} - -private newtype CastKind = - TWiden() or - TSame() or - TNarrow() - -private CastKind getCastKind(ConvertInstruction ci) { - exists(int fromSize, int toSize | - toSize = ci.getResultSize() and - fromSize = ci.getUnary().getResultSize() - | - fromSize < toSize and - result = TWiden() - or - fromSize = toSize and - result = TSame() - or - fromSize > toSize and - result = TNarrow() - ) -} - -private predicate bindBool(boolean bool) { - bool = true or - bool = false -} - -private Sign castSign(Sign s, boolean fromSigned, boolean toSigned, CastKind ck) { - result = TZero() and - ( - bindBool(fromSigned) and - bindBool(toSigned) and - s = TZero() - or - bindBool(fromSigned) and - bindBool(toSigned) and - ck = TNarrow() - ) - or - result = TPos() and - ( - bindBool(fromSigned) and - bindBool(toSigned) and - s = TPos() - or - bindBool(fromSigned) and - bindBool(toSigned) and - s = TNeg() and - ck = TNarrow() - or - fromSigned = true and - toSigned = false and - s = TNeg() - ) - or - result = TNeg() and - ( - fromSigned = true and - toSigned = true and - s = TNeg() - or - fromSigned = false and - toSigned = true and - s = TPos() and - ck != TWiden() - ) -} - -/** Holds if the sign of `e` is too complicated to determine. */ -private predicate unknownSign(Instruction i) { - // REVIEW: This should probably be a list of the instructions that we _do_ understand, rather than - // the ones we don't understand. Currently, if we try to compute the sign of an instruction that - // we don't understand, and it isn't on this list, we incorrectly compute the sign as "none" - // instead of "+,0,-". - // Even better, we could track the state of each instruction as a power set of {non-negative, - // non-positive, non-zero}, which would mean that the representation of the sign of an unknown - // value would be the empty set. - ( - i instanceof UninitializedInstruction - or - i instanceof InitializeParameterInstruction - or - i instanceof BuiltInOperationInstruction - or - i instanceof CallInstruction - or - i instanceof ChiInstruction - ) -} - -/** - * Holds if `lowerbound` is a lower bound for `bounded`. This is restricted - * to only include bounds for which we might determine a sign. - */ -private predicate lowerBound( - IRGuardCondition comp, Operand lowerbound, Operand bounded, boolean isStrict -) { - exists(int adjustment, Operand compared | - valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and - ( - isStrict = true and - adjustment = 0 - or - isStrict = false and - adjustment = 1 - ) and - comp.ensuresLt(lowerbound, compared, adjustment, bounded.getUse().getBlock(), true) - ) -} - -/** - * Holds if `upperbound` is an upper bound for `bounded` at `pos`. This is restricted - * to only include bounds for which we might determine a sign. - */ -private predicate upperBound( - IRGuardCondition comp, Operand upperbound, Operand bounded, boolean isStrict -) { - exists(int adjustment, Operand compared | - valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and - ( - isStrict = true and - adjustment = 0 - or - isStrict = false and - adjustment = 1 - ) and - comp.ensuresLt(compared, upperbound, adjustment, bounded.getUse().getBlock(), true) - ) -} - -/** - * Holds if `eqbound` is an equality/inequality for `bounded` at `pos`. This is - * restricted to only include bounds for which we might determine a sign. The - * boolean `isEq` gives the polarity: - * - `isEq = true` : `bounded = eqbound` - * - `isEq = false` : `bounded != eqbound` - */ -private predicate eqBound(IRGuardCondition guard, Operand eqbound, Operand bounded, boolean isEq) { - exists(Operand compared | - valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and - guard.ensuresEq(compared, eqbound, 0, bounded.getUse().getBlock(), isEq) - ) -} - -/** - * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in - * order for `v` to be positive. - */ -private predicate posBound(IRGuardCondition comp, Operand bound, Operand op) { - upperBound(comp, bound, op, _) or - eqBound(comp, bound, op, true) -} - -/** - * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in - * order for `v` to be negative. - */ -private predicate negBound(IRGuardCondition comp, Operand bound, Operand op) { - lowerBound(comp, bound, op, _) or - eqBound(comp, bound, op, true) -} - -/** - * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v` - * can be zero. - */ -private predicate zeroBound(IRGuardCondition comp, Operand bound, Operand op) { - lowerBound(comp, bound, op, _) or - upperBound(comp, bound, op, _) or - eqBound(comp, bound, op, _) -} - -/** Holds if `bound` allows `v` to be positive at `pos`. */ -private predicate posBoundOk(IRGuardCondition comp, Operand bound, Operand op) { - posBound(comp, bound, op) and TPos() = operandSign(bound) -} - -/** Holds if `bound` allows `v` to be negative at `pos`. */ -private predicate negBoundOk(IRGuardCondition comp, Operand bound, Operand op) { - negBound(comp, bound, op) and TNeg() = operandSign(bound) -} - -/** Holds if `bound` allows `v` to be zero at `pos`. */ -private predicate zeroBoundOk(IRGuardCondition comp, Operand bound, Operand op) { - lowerBound(comp, bound, op, _) and TNeg() = operandSign(bound) - or - lowerBound(comp, bound, op, false) and TZero() = operandSign(bound) - or - upperBound(comp, bound, op, _) and TPos() = operandSign(bound) - or - upperBound(comp, bound, op, false) and TZero() = operandSign(bound) - or - eqBound(comp, bound, op, true) and TZero() = operandSign(bound) - or - eqBound(comp, bound, op, false) and TZero() != operandSign(bound) -} - -private Sign binaryOpLhsSign(BinaryInstruction i) { result = operandSign(i.getLeftOperand()) } - -private Sign binaryOpRhsSign(BinaryInstruction i) { result = operandSign(i.getRightOperand()) } - -pragma[noinline] -private predicate binaryOpSigns(BinaryInstruction i, Sign lhs, Sign rhs) { - lhs = binaryOpLhsSign(i) and - rhs = binaryOpRhsSign(i) -} - -private Sign unguardedOperandSign(Operand operand) { - result = instructionSign(operand.getDef()) and - not hasGuard(operand, result) -} - -private Sign guardedOperandSign(Operand operand) { - result = instructionSign(operand.getDef()) and - hasGuard(operand, result) -} - -private Sign guardedOperandSignOk(Operand operand) { - result = TPos() and - forex(IRGuardCondition guard, Operand bound | posBound(guard, bound, operand) | - posBoundOk(guard, bound, operand) - ) - or - result = TNeg() and - forex(IRGuardCondition guard, Operand bound | negBound(guard, bound, operand) | - negBoundOk(guard, bound, operand) - ) - or - result = TZero() and - forex(IRGuardCondition guard, Operand bound | zeroBound(guard, bound, operand) | - zeroBoundOk(guard, bound, operand) - ) -} - -/** - * Holds if there is a bound that might restrict whether `v` has the sign `s` - * at `pos`. - */ -private predicate hasGuard(Operand op, Sign s) { - s = TPos() and posBound(_, _, op) - or - s = TNeg() and negBound(_, _, op) - or - s = TZero() and zeroBound(_, _, op) -} - -cached -module SignAnalysisCached { - /** - * Gets a sign that `operand` may have at `pos`, taking guards into account. - */ - cached - Sign operandSign(Operand operand) { - result = unguardedOperandSign(operand) - or - result = guardedOperandSign(operand) and - result = guardedOperandSignOk(operand) - or - // `result` is unconstrained if the definition is inexact. Then any sign is possible. - operand.isDefinitionInexact() - } - - cached - Sign instructionSign(Instruction i) { - result = certainInstructionSign(i) - or - not exists(certainInstructionSign(i)) and - not ( - result = TNeg() and - i.getResultType() instanceof UnsignedIntegralType - ) and - ( - unknownSign(i) - or - exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | - i = ci and - prior = ci.getUnary() and - ( - if ci.getResultType() instanceof SignedIntegralType - then toSigned = true - else toSigned = false - ) and - ( - if prior.getResultType() instanceof SignedIntegralType - then fromSigned = true - else fromSigned = false - ) and - result = castSign(operandSign(ci.getAnOperand()), fromSigned, toSigned, getCastKind(ci)) - ) - or - result = operandSign(i.(CopyInstruction).getSourceValueOperand()) - or - result = operandSign(i.(BitComplementInstruction).getAnOperand()).bitnot() - or - result = operandSign(i.(NegateInstruction).getAnOperand()).neg() - or - exists(Sign s1, Sign s2 | binaryOpSigns(i, s1, s2) | - i instanceof AddInstruction and result = s1.add(s2) - or - i instanceof SubInstruction and result = s1.add(s2.neg()) - or - i instanceof MulInstruction and result = s1.mul(s2) - or - i instanceof DivInstruction and result = s1.div(s2) - or - i instanceof RemInstruction and result = s1.rem(s2) - or - i instanceof BitAndInstruction and result = s1.bitand(s2) - or - i instanceof BitOrInstruction and result = s1.bitor(s2) - or - i instanceof BitXorInstruction and result = s1.bitxor(s2) - or - i instanceof ShiftLeftInstruction and result = s1.lshift(s2) - or - i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType) instanceof SignedIntegralType and - result = s1.rshift(s2) - or - i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType) instanceof SignedIntegralType and - result = s1.urshift(s2) - or - i instanceof UnsignedShiftRightInstruction and result = s1.urshift(s2) - ) - or - // use hasGuard here? - result = operandSign(i.(PhiInstruction).getAnOperand()) - ) - } -} - -/** Holds if `i` can be positive and cannot be negative. */ -predicate positiveInstruction(Instruction i) { - instructionSign(i) = TPos() and - not instructionSign(i) = TNeg() -} - -/** Holds if `i` at `pos` can be positive at and cannot be negative. */ -predicate positive(Operand op) { - operandSign(op) = TPos() and - not operandSign(op) = TNeg() -} - -/** Holds if `i` can be negative and cannot be positive. */ -predicate negativeInstruction(Instruction i) { - instructionSign(i) = TNeg() and - not instructionSign(i) = TPos() -} - -/** Holds if `i` at `pos` can be negative and cannot be positive. */ -predicate negative(Operand op) { - operandSign(op) = TNeg() and - not operandSign(op) = TPos() -} - -/** Holds if `i` is strictly positive. */ -predicate strictlyPositiveInstruction(Instruction i) { - instructionSign(i) = TPos() and - not instructionSign(i) = TNeg() and - not instructionSign(i) = TZero() -} - -/** Holds if `i` is strictly positive at `pos`. */ -predicate strictlyPositive(Operand op) { - operandSign(op) = TPos() and - not operandSign(op) = TNeg() and - not operandSign(op) = TZero() -} - -/** Holds if `i` is strictly negative. */ -predicate strictlyNegativeInstruction(Instruction i) { - instructionSign(i) = TNeg() and - not instructionSign(i) = TPos() and - not instructionSign(i) = TZero() -} - -/** Holds if `i` is strictly negative at `pos`. */ -predicate strictlyNegative(Operand op) { - operandSign(op) = TNeg() and - not operandSign(op) = TPos() and - not operandSign(op) = TZero() -} diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected deleted file mode 100644 index 242dd277135..00000000000 --- a/csharp/ql/test/experimental/ir/ir/PrintAst.expected +++ /dev/null @@ -1,1379 +0,0 @@ -array.cs: -# 1| [Class] ArrayTest -# 2| 5: [Method] one_dim_init_acc -# 2| -1: [TypeMention] Void -# 3| 4: [BlockStmt] {...} -# 4| 0: [LocalVariableDeclStmt] ... ...; -# 4| 0: [LocalVariableDeclAndInitExpr] Int32[] one_dim = ... -# 4| -1: [TypeMention] Int32[] -# 4| 1: [TypeMention] int -# 4| 0: [LocalVariableAccess] access to local variable one_dim -# 4| 1: [ArrayCreation] array creation of type Int32[] -# 4| -1: [ArrayInitializer] { ..., ... } -# 4| 0: [IntLiteral] 100 -# 4| 1: [IntLiteral] 101 -# 4| 2: [IntLiteral] 102 -# 5| 1: [ExprStmt] ...; -# 5| 0: [AssignExpr] ... = ... -# 5| 0: [ArrayAccess] access to array element -# 5| -1: [LocalVariableAccess] access to local variable one_dim -# 5| 0: [IntLiteral] 0 -# 5| 1: [IntLiteral] 1000 -# 6| 2: [ExprStmt] ...; -# 6| 0: [AssignExpr] ... = ... -# 6| 0: [ArrayAccess] access to array element -# 6| -1: [LocalVariableAccess] access to local variable one_dim -# 6| 0: [IntLiteral] 1 -# 6| 1: [ArrayAccess] access to array element -# 6| -1: [LocalVariableAccess] access to local variable one_dim -# 6| 0: [IntLiteral] 0 -# 7| 3: [ExprStmt] ...; -# 7| 0: [AssignExpr] ... = ... -# 7| 0: [ArrayAccess] access to array element -# 7| -1: [LocalVariableAccess] access to local variable one_dim -# 7| 0: [IntLiteral] 1 -# 7| 1: [IntLiteral] 1003 -# 9| 4: [LocalVariableDeclStmt] ... ...; -# 9| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 9| -1: [TypeMention] int -# 9| 0: [LocalVariableAccess] access to local variable i -# 9| 1: [IntLiteral] 0 -# 10| 5: [ExprStmt] ...; -# 10| 0: [AssignExpr] ... = ... -# 10| 0: [ArrayAccess] access to array element -# 10| -1: [LocalVariableAccess] access to local variable one_dim -# 10| 0: [LocalVariableAccess] access to local variable i -# 10| 1: [IntLiteral] 0 -# 13| 6: [Method] twod_and_init_acc -# 13| -1: [TypeMention] Void -# 14| 4: [BlockStmt] {...} -# 15| 0: [LocalVariableDeclStmt] ... ...; -# 15| 0: [LocalVariableDeclAndInitExpr] Int32[,] a = ... -# 15| -1: [TypeMention] Int32[,] -# 15| 1: [TypeMention] int -# 15| 0: [LocalVariableAccess] access to local variable a -# 15| 1: [ArrayCreation] array creation of type Int32[,] -# 15| -1: [ArrayInitializer] { ..., ... } -# 15| 0: [ArrayInitializer] { ..., ... } -# 15| 0: [IntLiteral] 100 -# 15| 1: [IntLiteral] 101 -# 15| 1: [ArrayInitializer] { ..., ... } -# 15| 0: [IntLiteral] 102 -# 15| 1: [IntLiteral] 103 -# 16| 1: [LocalVariableDeclStmt] ... ...; -# 16| 0: [LocalVariableDeclAndInitExpr] Int32[,] b = ... -# 16| -1: [TypeMention] Int32[,] -# 16| 1: [TypeMention] int -# 16| 0: [LocalVariableAccess] access to local variable b -# 16| 1: [ArrayCreation] array creation of type Int32[,] -# 16| -1: [TypeMention] Int32[,] -# 16| 1: [TypeMention] int -# 16| 0: [IntLiteral] 5 -# 16| 1: [IntLiteral] 5 -# 17| 2: [LocalVariableDeclStmt] ... ...; -# 17| 0: [LocalVariableDeclAndInitExpr] Int32[,] c = ... -# 17| -1: [TypeMention] Int32[,] -# 17| 1: [TypeMention] int -# 17| 0: [LocalVariableAccess] access to local variable c -# 17| 1: [ArrayCreation] array creation of type Int32[,] -# 17| -2: [TypeMention] Int32[,] -# 17| 1: [TypeMention] int -# 17| -1: [ArrayInitializer] { ..., ... } -# 17| 0: [ArrayInitializer] { ..., ... } -# 17| 0: [IntLiteral] 100 -# 17| 1: [IntLiteral] 101 -# 17| 1: [ArrayInitializer] { ..., ... } -# 17| 0: [IntLiteral] 102 -# 17| 1: [IntLiteral] 103 -# 17| 0: [IntLiteral] 2 -# 17| 1: [IntLiteral] 2 -# 18| 3: [LocalVariableDeclStmt] ... ...; -# 18| 0: [LocalVariableDeclAndInitExpr] Int32[,] d = ... -# 18| -1: [TypeMention] Int32[,] -# 18| 1: [TypeMention] int -# 18| 0: [LocalVariableAccess] access to local variable d -# 18| 1: [ArrayCreation] array creation of type Int32[,] -# 18| -2: [TypeMention] Int32[,] -# 18| 1: [TypeMention] int -# 18| -1: [ArrayInitializer] { ..., ... } -# 18| 0: [ArrayInitializer] { ..., ... } -# 18| 0: [IntLiteral] 100 -# 18| 1: [IntLiteral] 101 -# 18| 1: [ArrayInitializer] { ..., ... } -# 18| 0: [IntLiteral] 102 -# 18| 1: [IntLiteral] 103 -# 19| 4: [LocalVariableDeclStmt] ... ...; -# 19| 0: [LocalVariableDeclAndInitExpr] Int32[,] e = ... -# 19| -1: [TypeMention] Int32[,] -# 19| 1: [TypeMention] int -# 19| 0: [LocalVariableAccess] access to local variable e -# 19| 1: [LocalVariableAccess] access to local variable a -# 20| 5: [ExprStmt] ...; -# 20| 0: [AssignExpr] ... = ... -# 20| 0: [ArrayAccess] access to array element -# 20| -1: [LocalVariableAccess] access to local variable e -# 20| 0: [IntLiteral] 1 -# 20| 1: [IntLiteral] 1 -# 20| 1: [UnaryMinusExpr] -... -# 20| 0: [IntLiteral] 1 -assignop.cs: -# 3| [Class] AssignOp -# 5| 5: [Method] Main -# 5| -1: [TypeMention] Void -# 6| 4: [BlockStmt] {...} -# 7| 0: [LocalVariableDeclStmt] ... ...; -# 7| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... -# 7| -1: [TypeMention] int -# 7| 0: [LocalVariableAccess] access to local variable a -# 7| 1: [IntLiteral] 1 -# 8| 1: [LocalVariableDeclStmt] ... ...; -# 8| 0: [LocalVariableDeclAndInitExpr] Int32 c = ... -# 8| -1: [TypeMention] int -# 8| 0: [LocalVariableAccess] access to local variable c -# 8| 1: [IntLiteral] 1 -# 10| 2: [ExprStmt] ...; -# 10| 0: [AssignAddExpr] ... += ... -# 10| 0: [LocalVariableAccess] access to local variable c -# 10| 1: [LocalVariableAccess] access to local variable a -# 11| 3: [ExprStmt] ...; -# 11| 0: [AssignSubExpr] ... -= ... -# 11| 0: [LocalVariableAccess] access to local variable c -# 11| 1: [LocalVariableAccess] access to local variable a -# 12| 4: [ExprStmt] ...; -# 12| 0: [AssignMulExpr] ... *= ... -# 12| 0: [LocalVariableAccess] access to local variable c -# 12| 1: [LocalVariableAccess] access to local variable a -# 13| 5: [ExprStmt] ...; -# 13| 0: [AssignDivExpr] ... /= ... -# 13| 0: [LocalVariableAccess] access to local variable c -# 13| 1: [LocalVariableAccess] access to local variable a -# 14| 6: [ExprStmt] ...; -# 14| 0: [AssignRemExpr] ... %= ... -# 14| 0: [LocalVariableAccess] access to local variable c -# 14| 1: [LocalVariableAccess] access to local variable a -# 15| 7: [ExprStmt] ...; -# 15| 0: [AssignLeftShiftExpr] ... <<= ... -# 15| 0: [LocalVariableAccess] access to local variable c -# 15| 1: [IntLiteral] 2 -# 16| 8: [ExprStmt] ...; -# 16| 0: [AssignRightShiftExpr] ... >>= ... -# 16| 0: [LocalVariableAccess] access to local variable c -# 16| 1: [IntLiteral] 2 -# 17| 9: [ExprStmt] ...; -# 17| 0: [AssignAndExpr] ... &= ... -# 17| 0: [LocalVariableAccess] access to local variable c -# 17| 1: [IntLiteral] 2 -# 18| 10: [ExprStmt] ...; -# 18| 0: [AssignXorExpr] ... ^= ... -# 18| 0: [LocalVariableAccess] access to local variable c -# 18| 1: [IntLiteral] 2 -# 19| 11: [ExprStmt] ...; -# 19| 0: [AssignOrExpr] ... |= ... -# 19| 0: [LocalVariableAccess] access to local variable c -# 19| 1: [IntLiteral] 2 -# 20| 12: [ExprStmt] ...; -# 20| 0: [AssignUnsighedRightShiftExpr] ... >>>= ... -# 20| 0: [LocalVariableAccess] access to local variable c -# 20| 1: [IntLiteral] 2 -casts.cs: -# 1| [Class] Casts_A -# 5| [Class] Casts_B -#-----| 3: (Base types) -# 5| 0: [TypeMention] Casts_A -# 9| [Class] Casts -# 11| 5: [Method] Main -# 11| -1: [TypeMention] Void -# 12| 4: [BlockStmt] {...} -# 13| 0: [LocalVariableDeclStmt] ... ...; -# 13| 0: [LocalVariableDeclAndInitExpr] Casts_A Aobj = ... -# 13| -1: [TypeMention] Casts_A -# 13| 0: [LocalVariableAccess] access to local variable Aobj -# 13| 1: [ObjectCreation] object creation of type Casts_A -# 13| 0: [TypeMention] Casts_A -# 14| 1: [LocalVariableDeclStmt] ... ...; -# 14| 0: [LocalVariableDeclAndInitExpr] Casts_B bobjCE = ... -# 14| -1: [TypeMention] Casts_B -# 14| 0: [LocalVariableAccess] access to local variable bobjCE -# 14| 1: [CastExpr] (...) ... -# 14| 0: [TypeAccess] access to type Casts_B -# 14| 0: [TypeMention] Casts_B -# 14| 1: [LocalVariableAccess] access to local variable Aobj -# 15| 2: [LocalVariableDeclStmt] ... ...; -# 15| 0: [LocalVariableDeclAndInitExpr] Casts_B bobjAS = ... -# 15| -1: [TypeMention] Casts_B -# 15| 0: [LocalVariableAccess] access to local variable bobjAS -# 15| 1: [AsExpr] ... as ... -# 15| 0: [LocalVariableAccess] access to local variable Aobj -# 15| 1: [TypeAccess] access to type Casts_B -# 15| 0: [TypeMention] Casts_B -collections.cs: -# 3| [Class] Collections -# 5| 5: [Class] MyClass -# 7| 5: [Field] a -# 7| -1: [TypeMention] string -# 8| 6: [Field] b -# 8| -1: [TypeMention] string -# 11| 6: [Method] Main -# 11| -1: [TypeMention] Void -# 12| 4: [BlockStmt] {...} -# 13| 0: [LocalVariableDeclStmt] ... ...; -# 13| 0: [LocalVariableDeclAndInitExpr] Dictionary dict = ... -# 13| -1: [TypeMention] Dictionary -# 13| 0: [LocalVariableAccess] access to local variable dict -# 13| 1: [ObjectCreation] object creation of type Dictionary -# 13| -2: [TypeMention] Dictionary -# 13| 1: [TypeMention] int -# 13| 2: [TypeMention] MyClass -# 14| -1: [CollectionInitializer] { ..., ... } -# 15| 0: [ElementInitializer] call to method Add -# 15| 0: [IntLiteral] 0 -# 15| 1: [ObjectCreation] object creation of type MyClass -# 15| -2: [TypeMention] MyClass -# 15| -1: [ObjectInitializer] { ..., ... } -# 15| 0: [MemberInitializer] ... = ... -# 15| 0: [FieldAccess] access to field a -# 15| 1: [StringLiteralUtf16] "Hello" -# 15| 1: [MemberInitializer] ... = ... -# 15| 0: [FieldAccess] access to field b -# 15| 1: [StringLiteralUtf16] "World" -# 16| 1: [ElementInitializer] call to method Add -# 16| 0: [IntLiteral] 1 -# 16| 1: [ObjectCreation] object creation of type MyClass -# 16| -2: [TypeMention] MyClass -# 16| -1: [ObjectInitializer] { ..., ... } -# 16| 0: [MemberInitializer] ... = ... -# 16| 0: [FieldAccess] access to field a -# 16| 1: [StringLiteralUtf16] "Foo" -# 16| 1: [MemberInitializer] ... = ... -# 16| 0: [FieldAccess] access to field b -# 16| 1: [StringLiteralUtf16] "Bar" -constructor_init.cs: -# 1| [Class] BaseClass -# 3| 4: [Field] num -# 3| -1: [TypeMention] int -# 5| 5: [InstanceConstructor] BaseClass -# 6| 4: [BlockStmt] {...} -# 9| 6: [InstanceConstructor] BaseClass -#-----| 2: (Parameters) -# 9| 0: [Parameter] i -# 9| -1: [TypeMention] int -# 10| 4: [BlockStmt] {...} -# 11| 0: [ExprStmt] ...; -# 11| 0: [AssignExpr] ... = ... -# 11| 0: [FieldAccess] access to field num -# 11| 1: [ParameterAccess] access to parameter i -# 15| [Class] DerivedClass -#-----| 3: (Base types) -# 15| 0: [TypeMention] BaseClass -# 17| 4: [InstanceConstructor] DerivedClass -# 17| 3: [ConstructorInitializer] call to constructor BaseClass -# 18| 4: [BlockStmt] {...} -# 21| 5: [InstanceConstructor] DerivedClass -#-----| 2: (Parameters) -# 21| 0: [Parameter] i -# 21| -1: [TypeMention] int -# 21| 3: [ConstructorInitializer] call to constructor BaseClass -# 21| 0: [ParameterAccess] access to parameter i -# 22| 4: [BlockStmt] {...} -# 25| 6: [InstanceConstructor] DerivedClass -#-----| 2: (Parameters) -# 25| 0: [Parameter] i -# 25| -1: [TypeMention] int -# 25| 1: [Parameter] j -# 25| -1: [TypeMention] int -# 25| 3: [ConstructorInitializer] call to constructor DerivedClass -# 25| 0: [ParameterAccess] access to parameter i -# 26| 4: [BlockStmt] {...} -# 29| 7: [Method] Main -# 29| -1: [TypeMention] Void -# 30| 4: [BlockStmt] {...} -# 31| 0: [LocalVariableDeclStmt] ... ...; -# 31| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj1 = ... -# 31| -1: [TypeMention] DerivedClass -# 31| 0: [LocalVariableAccess] access to local variable obj1 -# 31| 1: [ObjectCreation] object creation of type DerivedClass -# 31| 0: [TypeMention] DerivedClass -# 32| 1: [LocalVariableDeclStmt] ... ...; -# 32| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj2 = ... -# 32| -1: [TypeMention] DerivedClass -# 32| 0: [LocalVariableAccess] access to local variable obj2 -# 32| 1: [ObjectCreation] object creation of type DerivedClass -# 32| -1: [TypeMention] DerivedClass -# 32| 0: [IntLiteral] 1 -# 33| 2: [LocalVariableDeclStmt] ... ...; -# 33| 0: [LocalVariableDeclAndInitExpr] DerivedClass obj3 = ... -# 33| -1: [TypeMention] DerivedClass -# 33| 0: [LocalVariableAccess] access to local variable obj3 -# 33| 1: [ObjectCreation] object creation of type DerivedClass -# 33| -1: [TypeMention] DerivedClass -# 33| 0: [IntLiteral] 1 -# 33| 1: [IntLiteral] 2 -crement.cs: -# 1| [Class] CrementOpsTest -# 3| 5: [Method] Main -# 3| -1: [TypeMention] Void -# 4| 4: [BlockStmt] {...} -# 5| 0: [LocalVariableDeclStmt] ... ...; -# 5| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 5| -1: [TypeMention] int -# 5| 0: [LocalVariableAccess] access to local variable x -# 5| 1: [IntLiteral] 10 -# 6| 1: [LocalVariableDeclStmt] ... ...; -# 6| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... -# 6| -1: [TypeMention] int -# 6| 0: [LocalVariableAccess] access to local variable a -# 6| 1: [PostIncrExpr] ...++ -# 6| 0: [LocalVariableAccess] access to local variable x -# 7| 2: [LocalVariableDeclStmt] ... ...; -# 7| 0: [LocalVariableDeclAndInitExpr] Int32 b = ... -# 7| -1: [TypeMention] int -# 7| 0: [LocalVariableAccess] access to local variable b -# 7| 1: [PreDecrExpr] --... -# 7| 0: [LocalVariableAccess] access to local variable x -# 8| 3: [LocalVariableDeclStmt] ... ...; -# 8| 0: [LocalVariableDeclAndInitExpr] Int32 c = ... -# 8| -1: [TypeMention] int -# 8| 0: [LocalVariableAccess] access to local variable c -# 8| 1: [PreIncrExpr] ++... -# 8| 0: [LocalVariableAccess] access to local variable x -# 9| 4: [ExprStmt] ...; -# 9| 0: [AssignExpr] ... = ... -# 9| 0: [LocalVariableAccess] access to local variable x -# 9| 1: [PostDecrExpr] ...-- -# 9| 0: [LocalVariableAccess] access to local variable x -delegates.cs: -# 3| [Class] Delegates -# 4| 5: [DelegateType] Del -#-----| 2: (Parameters) -# 4| 0: [Parameter] num -# 4| -1: [TypeMention] int -# 6| 6: [Method] returns -# 6| -1: [TypeMention] int -#-----| 2: (Parameters) -# 6| 0: [Parameter] ret -# 6| -1: [TypeMention] int -# 7| 4: [BlockStmt] {...} -# 8| 0: [ReturnStmt] return ...; -# 8| 0: [ParameterAccess] access to parameter ret -# 11| 7: [Method] Main -# 11| -1: [TypeMention] Void -# 11| 4: [BlockStmt] {...} -# 12| 0: [LocalVariableDeclStmt] ... ...; -# 12| 0: [LocalVariableDeclAndInitExpr] Del del1 = ... -# 12| -1: [TypeMention] Del -# 12| 0: [LocalVariableAccess] access to local variable del1 -# 12| 1: [ExplicitDelegateCreation] delegate creation of type Del -# 12| -1: [TypeMention] Del -# 12| 0: [MethodAccess] access to method returns -# 13| 1: [ExprStmt] ...; -# 13| 0: [DelegateCall] delegate call -# 13| -1: [LocalVariableAccess] access to local variable del1 -# 13| 0: [IntLiteral] 5 -events.cs: -# 1| [Class] Events -# 3| 4: [DelegateType] MyDel -#-----| 2: (Parameters) -# 3| 0: [Parameter] str -# 3| -1: [TypeMention] string -# 4| 5: [Field] Inst -# 4| -1: [TypeMention] MyDel -# 6| 6: [Event] MyEvent -# 6| -1: [TypeMention] MyDel -# 6| 3: [AddEventAccessor] add_MyEvent -#-----| 2: (Parameters) -# 6| 0: [Parameter] value -# 6| 4: [RemoveEventAccessor] remove_MyEvent -#-----| 2: (Parameters) -# 6| 0: [Parameter] value -# 8| 7: [InstanceConstructor] Events -# 9| 4: [BlockStmt] {...} -# 10| 0: [ExprStmt] ...; -# 10| 0: [AssignExpr] ... = ... -# 10| 0: [FieldAccess] access to field Inst -# 10| -1: [ThisAccess] this access -# 10| 1: [ExplicitDelegateCreation] delegate creation of type MyDel -# 10| -1: [TypeMention] MyDel -# 10| 0: [MethodAccess] access to method Fun -# 10| -1: [ThisAccess] this access -# 13| 8: [Method] AddEvent -# 13| -1: [TypeMention] Void -# 14| 4: [BlockStmt] {...} -# 15| 0: [ExprStmt] ...; -# 15| 0: [AddEventExpr] ... += ... -# 15| 0: [EventAccess,EventCall] access to event MyEvent -# 15| -1: [ThisAccess] this access -# 15| 1: [FieldAccess] access to field Inst -# 15| -1: [ThisAccess] this access -# 18| 9: [Method] RemoveEvent -# 18| -1: [TypeMention] Void -# 19| 4: [BlockStmt] {...} -# 20| 0: [ExprStmt] ...; -# 20| 0: [RemoveEventExpr] ... -= ... -# 20| 0: [EventAccess,EventCall] access to event MyEvent -# 20| -1: [ThisAccess] this access -# 20| 1: [FieldAccess] access to field Inst -# 20| -1: [ThisAccess] this access -# 23| 10: [Method] Fun -# 23| -1: [TypeMention] string -#-----| 2: (Parameters) -# 23| 0: [Parameter] str -# 23| -1: [TypeMention] string -# 24| 4: [BlockStmt] {...} -# 25| 0: [ReturnStmt] return ...; -# 25| 0: [ParameterAccess] access to parameter str -# 28| 11: [Method] Main -# 28| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 28| 0: [Parameter] args -# 28| -1: [TypeMention] String[] -# 28| 1: [TypeMention] string -# 29| 4: [BlockStmt] {...} -# 30| 0: [LocalVariableDeclStmt] ... ...; -# 30| 0: [LocalVariableDeclAndInitExpr] Events obj = ... -# 30| -1: [TypeMention] Events -# 30| 0: [LocalVariableAccess] access to local variable obj -# 30| 1: [ObjectCreation] object creation of type Events -# 30| 0: [TypeMention] Events -# 31| 1: [ExprStmt] ...; -# 31| 0: [MethodCall] call to method AddEvent -# 31| -1: [LocalVariableAccess] access to local variable obj -# 32| 2: [LocalVariableDeclStmt] ... ...; -# 32| 0: [LocalVariableDeclAndInitExpr] String result = ... -# 32| -1: [TypeMention] string -# 32| 0: [LocalVariableAccess] access to local variable result -# 32| 1: [DelegateCall] delegate call -# 32| -1: [LocalVariableAccess] access to local variable obj -# 32| 0: [StringLiteralUtf16] "string" -# 33| 3: [ExprStmt] ...; -# 33| 0: [MethodCall] call to method RemoveEvent -# 33| -1: [LocalVariableAccess] access to local variable obj -foreach.cs: -# 3| [Class] ForEach -# 4| 5: [Method] Main -# 4| -1: [TypeMention] Void -# 4| 4: [BlockStmt] {...} -# 5| 0: [LocalVariableDeclStmt] ... ...; -# 5| 0: [LocalVariableDeclAndInitExpr] Int32[] a_array = ... -# 5| -1: [TypeMention] Int32[] -# 5| 1: [TypeMention] int -# 5| 0: [LocalVariableAccess] access to local variable a_array -# 5| 1: [ArrayCreation] array creation of type Int32[] -# 5| -2: [TypeMention] Int32[] -# 5| 1: [TypeMention] int -# 5| -1: [ArrayInitializer] { ..., ... } -# 5| 0: [IntLiteral] 1 -# 5| 1: [IntLiteral] 2 -# 5| 2: [IntLiteral] 3 -# 5| 3: [IntLiteral] 4 -# 5| 4: [IntLiteral] 5 -# 5| 5: [IntLiteral] 6 -# 5| 6: [IntLiteral] 7 -# 7| 1: [ForeachStmt] foreach (... ... in ...) ... -# 7| 0: [LocalVariableDeclExpr] Int32 items -# 7| 0: [TypeMention] int -# 7| 1: [LocalVariableAccess] access to local variable a_array -# 8| 2: [BlockStmt] {...} -# 9| 0: [LocalVariableDeclStmt] ... ...; -# 9| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 9| -1: [TypeMention] int -# 9| 0: [LocalVariableAccess] access to local variable x -# 9| 1: [LocalVariableAccess] access to local variable items -func_with_param_call.cs: -# 3| [Class] test_call_with_param -# 5| 5: [Method] f -# 5| -1: [TypeMention] int -#-----| 2: (Parameters) -# 5| 0: [Parameter] x -# 5| -1: [TypeMention] int -# 5| 1: [Parameter] y -# 5| -1: [TypeMention] int -# 6| 4: [BlockStmt] {...} -# 7| 0: [ReturnStmt] return ...; -# 7| 0: [AddExpr] ... + ... -# 7| 0: [ParameterAccess] access to parameter x -# 7| 1: [ParameterAccess] access to parameter y -# 10| 6: [Method] g -# 10| -1: [TypeMention] int -# 11| 4: [BlockStmt] {...} -# 12| 0: [ReturnStmt] return ...; -# 12| 0: [MethodCall] call to method f -# 12| 0: [IntLiteral] 2 -# 12| 1: [IntLiteral] 3 -indexers.cs: -# 1| [Class] Indexers -# 3| 5: [Class] MyClass -# 5| 5: [Field] address -# 5| -1: [TypeMention] String[] -# 5| 1: [TypeMention] string -# 5| 1: [AssignExpr] ... = ... -# 5| 0: [FieldAccess] access to field address -# 5| 1: [ArrayCreation] array creation of type String[] -# 5| -1: [TypeMention] String[] -# 5| 1: [TypeMention] string -# 5| 0: [IntLiteral] 2 -# 6| 6: [Indexer] Item -# 6| -1: [TypeMention] string -#-----| 1: (Parameters) -# 6| 0: [Parameter] index -# 6| -1: [TypeMention] int -# 8| 3: [Getter] get_Item -#-----| 2: (Parameters) -# 6| 0: [Parameter] index -# 9| 4: [BlockStmt] {...} -# 10| 0: [ReturnStmt] return ...; -# 10| 0: [ArrayAccess] access to array element -# 10| -1: [FieldAccess] access to field address -# 10| 0: [ParameterAccess] access to parameter index -# 12| 4: [Setter] set_Item -#-----| 2: (Parameters) -# 6| 0: [Parameter] index -# 12| 1: [Parameter] value -# 13| 4: [BlockStmt] {...} -# 14| 0: [ExprStmt] ...; -# 14| 0: [AssignExpr] ... = ... -# 14| 0: [ArrayAccess] access to array element -# 14| -1: [FieldAccess] access to field address -# 14| 0: [ParameterAccess] access to parameter index -# 14| 1: [ParameterAccess] access to parameter value -# 19| 6: [Method] Main -# 19| -1: [TypeMention] Void -# 20| 4: [BlockStmt] {...} -# 21| 0: [LocalVariableDeclStmt] ... ...; -# 21| 0: [LocalVariableDeclAndInitExpr] MyClass inst = ... -# 21| -1: [TypeMention] MyClass -# 21| 0: [LocalVariableAccess] access to local variable inst -# 21| 1: [ObjectCreation] object creation of type MyClass -# 21| 0: [TypeMention] MyClass -# 22| 1: [ExprStmt] ...; -# 22| 0: [AssignExpr] ... = ... -# 22| 0: [IndexerCall] access to indexer -# 22| -1: [LocalVariableAccess] access to local variable inst -# 22| 0: [IntLiteral] 0 -# 22| 1: [StringLiteralUtf16] "str1" -# 23| 2: [ExprStmt] ...; -# 23| 0: [AssignExpr] ... = ... -# 23| 0: [IndexerCall] access to indexer -# 23| -1: [LocalVariableAccess] access to local variable inst -# 23| 0: [IntLiteral] 1 -# 23| 1: [StringLiteralUtf16] "str1" -# 24| 3: [ExprStmt] ...; -# 24| 0: [AssignExpr] ... = ... -# 24| 0: [IndexerCall] access to indexer -# 24| -1: [LocalVariableAccess] access to local variable inst -# 24| 0: [IntLiteral] 1 -# 24| 1: [IndexerCall] access to indexer -# 24| -1: [LocalVariableAccess] access to local variable inst -# 24| 0: [IntLiteral] 0 -inheritance_polymorphism.cs: -# 1| [Class] A -# 3| 5: [Method] function -# 3| -1: [TypeMention] int -# 4| 4: [BlockStmt] {...} -# 5| 0: [ReturnStmt] return ...; -# 5| 0: [IntLiteral] 0 -# 9| [Class] B -#-----| 3: (Base types) -# 9| 0: [TypeMention] A -# 13| [Class] C -#-----| 3: (Base types) -# 13| 0: [TypeMention] B -# 15| 5: [Method] function -# 15| -1: [TypeMention] int -# 16| 4: [BlockStmt] {...} -# 17| 0: [ReturnStmt] return ...; -# 17| 0: [IntLiteral] 1 -# 21| [Class] Program -# 23| 5: [Method] Main -# 23| -1: [TypeMention] Void -# 24| 4: [BlockStmt] {...} -# 25| 0: [LocalVariableDeclStmt] ... ...; -# 25| 0: [LocalVariableDeclAndInitExpr] B objB = ... -# 25| -1: [TypeMention] B -# 25| 0: [LocalVariableAccess] access to local variable objB -# 25| 1: [ObjectCreation] object creation of type B -# 25| 0: [TypeMention] B -# 26| 1: [ExprStmt] ...; -# 26| 0: [MethodCall] call to method function -# 26| -1: [LocalVariableAccess] access to local variable objB -# 29| 2: [LocalVariableDeclStmt] ... ...; -# 29| 0: [LocalVariableDeclExpr] A objA -# 29| 0: [TypeMention] A -# 30| 3: [ExprStmt] ...; -# 30| 0: [AssignExpr] ... = ... -# 30| 0: [LocalVariableAccess] access to local variable objA -# 30| 1: [LocalVariableAccess] access to local variable objB -# 31| 4: [ExprStmt] ...; -# 31| 0: [MethodCall] call to method function -# 31| -1: [LocalVariableAccess] access to local variable objA -# 33| 5: [LocalVariableDeclStmt] ... ...; -# 33| 0: [LocalVariableDeclAndInitExpr] A objC = ... -# 33| -1: [TypeMention] A -# 33| 0: [LocalVariableAccess] access to local variable objC -# 33| 1: [ObjectCreation] object creation of type C -# 33| 0: [TypeMention] C -# 34| 6: [ExprStmt] ...; -# 34| 0: [MethodCall] call to method function -# 34| -1: [LocalVariableAccess] access to local variable objC -inoutref.cs: -# 1| [Class] MyClass -# 2| 5: [Field] fld -# 2| -1: [TypeMention] int -# 5| [Struct] MyStruct -# 6| 5: [Field] fld -# 6| -1: [TypeMention] int -# 9| [Class] InOutRef -# 11| 5: [Method] set -# 11| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 11| 0: [Parameter] o1 -# 11| -1: [TypeMention] MyClass -# 11| 1: [Parameter] o2 -# 11| -1: [TypeMention] MyClass -# 12| 4: [BlockStmt] {...} -# 13| 0: [ExprStmt] ...; -# 13| 0: [AssignExpr] ... = ... -# 13| 0: [ParameterAccess] access to parameter o1 -# 13| 1: [ParameterAccess] access to parameter o2 -# 16| 6: [Method] F -# 16| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 16| 0: [Parameter] a -# 16| -1: [TypeMention] int -# 16| 1: [Parameter] b -# 16| -1: [TypeMention] MyStruct -# 16| 2: [Parameter] b1 -# 16| -1: [TypeMention] MyStruct -# 16| 3: [Parameter] c -# 16| -1: [TypeMention] MyClass -# 16| 4: [Parameter] c1 -# 16| -1: [TypeMention] MyClass -# 17| 4: [BlockStmt] {...} -# 18| 0: [ExprStmt] ...; -# 18| 0: [AssignExpr] ... = ... -# 18| 0: [FieldAccess] access to field fld -# 18| -1: [ParameterAccess] access to parameter b -# 18| 1: [IntLiteral] 0 -# 19| 1: [ExprStmt] ...; -# 19| 0: [AssignExpr] ... = ... -# 19| 0: [ParameterAccess] access to parameter a -# 19| 1: [FieldAccess] access to field fld -# 19| -1: [ParameterAccess] access to parameter b -# 21| 2: [ExprStmt] ...; -# 21| 0: [AssignExpr] ... = ... -# 21| 0: [FieldAccess] access to field fld -# 21| -1: [ParameterAccess] access to parameter c -# 21| 1: [IntLiteral] 10 -# 22| 3: [ExprStmt] ...; -# 22| 0: [AssignExpr] ... = ... -# 22| 0: [ParameterAccess] access to parameter a -# 22| 1: [FieldAccess] access to field fld -# 22| -1: [ParameterAccess] access to parameter c -# 24| 4: [ExprStmt] ...; -# 24| 0: [AssignExpr] ... = ... -# 24| 0: [ParameterAccess] access to parameter b -# 24| 1: [ParameterAccess] access to parameter b1 -# 26| 5: [ExprStmt] ...; -# 26| 0: [MethodCall] call to method set -# 26| 0: [ParameterAccess] access to parameter c -# 26| 1: [ParameterAccess] access to parameter c1 -# 29| 7: [Method] Main -# 29| -1: [TypeMention] Void -# 30| 4: [BlockStmt] {...} -# 31| 0: [LocalVariableDeclStmt] ... ...; -# 31| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... -# 31| -1: [TypeMention] int -# 31| 0: [LocalVariableAccess] access to local variable a -# 31| 1: [IntLiteral] 0 -# 32| 1: [LocalVariableDeclStmt] ... ...; -# 32| 0: [LocalVariableDeclAndInitExpr] MyStruct b = ... -# 32| -1: [TypeMention] MyStruct -# 32| 0: [LocalVariableAccess] access to local variable b -# 32| 1: [ObjectCreation] object creation of type MyStruct -# 32| 0: [TypeMention] MyStruct -# 33| 2: [LocalVariableDeclStmt] ... ...; -# 33| 0: [LocalVariableDeclAndInitExpr] MyClass c = ... -# 33| -1: [TypeMention] MyClass -# 33| 0: [LocalVariableAccess] access to local variable c -# 33| 1: [ObjectCreation] object creation of type MyClass -# 33| 0: [TypeMention] MyClass -# 34| 3: [ExprStmt] ...; -# 34| 0: [MethodCall] call to method F -# 34| 0: [LocalVariableAccess] access to local variable a -# 34| 1: [LocalVariableAccess] access to local variable b -# 34| 2: [LocalVariableAccess] access to local variable b -# 34| 3: [LocalVariableAccess] access to local variable c -# 34| 4: [LocalVariableAccess] access to local variable c -# 36| 4: [LocalVariableDeclStmt] ... ...; -# 36| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 36| -1: [TypeMention] int -# 36| 0: [LocalVariableAccess] access to local variable x -# 36| 1: [FieldAccess] access to field fld -# 36| -1: [LocalVariableAccess] access to local variable b -isexpr.cs: -# 1| [Class] Is_A -# 3| 5: [Field] x -# 3| -1: [TypeMention] int -# 6| [Class] IsExpr -# 8| 5: [Method] Main -# 8| -1: [TypeMention] Void -# 9| 4: [BlockStmt] {...} -# 10| 0: [LocalVariableDeclStmt] ... ...; -# 10| 0: [LocalVariableDeclAndInitExpr] Is_A obj = ... -# 10| -1: [TypeMention] Is_A -# 10| 0: [LocalVariableAccess] access to local variable obj -# 10| 1: [NullLiteral] null -# 12| 1: [LocalVariableDeclStmt] ... ...; -# 12| 0: [LocalVariableDeclAndInitExpr] Object o = ... -# 12| -1: [TypeMention] object -# 12| 0: [LocalVariableAccess] access to local variable o -# 12| 1: [LocalVariableAccess] access to local variable obj -# 13| 2: [IfStmt] if (...) ... -# 13| 0: [IsExpr] ... is ... -# 13| 0: [LocalVariableAccess] access to local variable o -# 13| 1: [VariablePatternExpr] Is_A tmp -# 13| 0: [TypeMention] Is_A -# 14| 1: [BlockStmt] {...} -# 15| 0: [LocalVariableDeclStmt] ... ...; -# 15| 0: [LocalVariableDeclAndInitExpr] Int32 res = ... -# 15| -1: [TypeMention] int -# 15| 0: [LocalVariableAccess] access to local variable res -# 15| 1: [FieldAccess] access to field x -# 15| -1: [LocalVariableAccess] access to local variable tmp -# 17| 3: [IfStmt] if (...) ... -# 17| 0: [IsExpr] ... is ... -# 17| 0: [LocalVariableAccess] access to local variable o -# 17| 1: [TypeAccessPatternExpr] access to type Is_A -# 17| 0: [TypeMention] Is_A -# 18| 1: [BlockStmt] {...} -jumps.cs: -# 3| [Class] Jumps -# 5| 5: [Method] Main -# 5| -1: [TypeMention] Void -# 6| 4: [BlockStmt] {...} -# 7| 0: [ForStmt] for (...;...;...) ... -# 7| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 7| -1: [TypeMention] int -# 7| 0: [LocalVariableAccess] access to local variable i -# 7| 1: [IntLiteral] 1 -# 7| 0: [LEExpr] ... <= ... -# 7| 0: [LocalVariableAccess] access to local variable i -# 7| 1: [IntLiteral] 10 -# 7| 1: [PostIncrExpr] ...++ -# 7| 0: [LocalVariableAccess] access to local variable i -# 8| 2: [BlockStmt] {...} -# 9| 0: [IfStmt] if (...) ... -# 9| 0: [EQExpr] ... == ... -# 9| 0: [LocalVariableAccess] access to local variable i -# 9| 1: [IntLiteral] 3 -# 10| 1: [ContinueStmt] continue; -# 11| 2: [IfStmt] if (...) ... -# 11| 0: [EQExpr] ... == ... -# 11| 0: [LocalVariableAccess] access to local variable i -# 11| 1: [IntLiteral] 5 -# 12| 1: [BreakStmt] break; -# 13| 1: [ExprStmt] ...; -# 13| 0: [MethodCall] call to method WriteLine -# 13| -1: [TypeAccess] access to type Console -# 13| 0: [TypeMention] Console -# 13| 0: [StringLiteralUtf16] "BreakAndContinue" -# 16| 1: [ForStmt] for (...;...;...) ... -# 16| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 16| -1: [TypeMention] int -# 16| 0: [LocalVariableAccess] access to local variable i -# 16| 1: [IntLiteral] 0 -# 16| 0: [LTExpr] ... < ... -# 16| 0: [LocalVariableAccess] access to local variable i -# 16| 1: [IntLiteral] 10 -# 17| 1: [BlockStmt] {...} -# 18| 0: [ExprStmt] ...; -# 18| 0: [PostIncrExpr] ...++ -# 18| 0: [LocalVariableAccess] access to local variable i -# 19| 1: [ContinueStmt] continue; -# 22| 2: [LocalVariableDeclStmt] ... ...; -# 22| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... -# 22| -1: [TypeMention] int -# 22| 0: [LocalVariableAccess] access to local variable a -# 22| 1: [IntLiteral] 0 -# 23| 3: [WhileStmt] while (...) ... -# 23| 0: [BoolLiteral] true -# 24| 1: [BlockStmt] {...} -# 25| 0: [ExprStmt] ...; -# 25| 0: [PostIncrExpr] ...++ -# 25| 0: [LocalVariableAccess] access to local variable a -# 26| 1: [IfStmt] if (...) ... -# 26| 0: [EQExpr] ... == ... -# 26| 0: [LocalVariableAccess] access to local variable a -# 26| 1: [IntLiteral] 5 -# 27| 1: [ContinueStmt] continue; -# 28| 2: [IfStmt] if (...) ... -# 28| 0: [EQExpr] ... == ... -# 28| 0: [LocalVariableAccess] access to local variable a -# 28| 1: [IntLiteral] 10 -# 29| 1: [BreakStmt] break; -# 32| 4: [ForStmt] for (...;...;...) ... -# 32| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 32| -1: [TypeMention] int -# 32| 0: [LocalVariableAccess] access to local variable i -# 32| 1: [IntLiteral] 1 -# 32| 0: [LEExpr] ... <= ... -# 32| 0: [LocalVariableAccess] access to local variable i -# 32| 1: [IntLiteral] 10 -# 32| 1: [PostIncrExpr] ...++ -# 32| 0: [LocalVariableAccess] access to local variable i -# 33| 2: [BlockStmt] {...} -# 34| 0: [IfStmt] if (...) ... -# 34| 0: [EQExpr] ... == ... -# 34| 0: [LocalVariableAccess] access to local variable i -# 34| 1: [IntLiteral] 5 -# 35| 1: [GotoLabelStmt] goto ...; -# 37| 5: [LabelStmt] done: -# 38| 6: [ExprStmt] ...; -# 38| 0: [MethodCall] call to method WriteLine -# 38| -1: [TypeAccess] access to type Console -# 38| 0: [TypeMention] Console -# 38| 0: [StringLiteralUtf16] "Done" -lock.cs: -# 3| [Class] LockTest -# 5| 5: [Method] A -# 5| -1: [TypeMention] Void -# 6| 4: [BlockStmt] {...} -# 7| 0: [LocalVariableDeclStmt] ... ...; -# 7| 0: [LocalVariableDeclAndInitExpr] Object object = ... -# 7| -1: [TypeMention] object -# 7| 0: [LocalVariableAccess] access to local variable object -# 7| 1: [ObjectCreation] object creation of type Object -# 7| 0: [TypeMention] object -# 8| 1: [LockStmt] lock (...) {...} -# 8| 0: [LocalVariableAccess] access to local variable object -# 9| 1: [BlockStmt] {...} -# 10| 0: [ExprStmt] ...; -# 10| 0: [MethodCall] call to method WriteLine -# 10| -1: [TypeAccess] access to type Console -# 10| 0: [TypeMention] Console -# 10| 0: [MethodCall] call to method ToString -# 10| -1: [LocalVariableAccess] access to local variable object -obj_creation.cs: -# 1| [Class] ObjCreation -# 3| 5: [Class] MyClass -# 5| 4: [Field] x -# 5| -1: [TypeMention] int -# 7| 5: [InstanceConstructor] MyClass -# 8| 4: [BlockStmt] {...} -# 11| 6: [InstanceConstructor] MyClass -#-----| 2: (Parameters) -# 11| 0: [Parameter] _x -# 11| -1: [TypeMention] int -# 12| 4: [BlockStmt] {...} -# 13| 0: [ExprStmt] ...; -# 13| 0: [AssignExpr] ... = ... -# 13| 0: [FieldAccess] access to field x -# 13| 1: [ParameterAccess] access to parameter _x -# 17| 6: [Method] SomeFun -# 17| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 17| 0: [Parameter] x -# 17| -1: [TypeMention] MyClass -# 18| 4: [BlockStmt] {...} -# 21| 7: [Method] Main -# 21| -1: [TypeMention] Void -# 22| 4: [BlockStmt] {...} -# 23| 0: [LocalVariableDeclStmt] ... ...; -# 23| 0: [LocalVariableDeclAndInitExpr] MyClass obj = ... -# 23| -1: [TypeMention] MyClass -# 23| 0: [LocalVariableAccess] access to local variable obj -# 23| 1: [ObjectCreation] object creation of type MyClass -# 23| -1: [TypeMention] MyClass -# 23| 0: [IntLiteral] 100 -# 24| 1: [LocalVariableDeclStmt] ... ...; -# 24| 0: [LocalVariableDeclAndInitExpr] MyClass obj_initlist = ... -# 24| -1: [TypeMention] MyClass -# 24| 0: [LocalVariableAccess] access to local variable obj_initlist -# 24| 1: [ObjectCreation] object creation of type MyClass -# 24| -2: [TypeMention] MyClass -# 24| -1: [ObjectInitializer] { ..., ... } -# 24| 0: [MemberInitializer] ... = ... -# 24| 0: [FieldAccess] access to field x -# 24| 1: [IntLiteral] 101 -# 25| 2: [LocalVariableDeclStmt] ... ...; -# 25| 0: [LocalVariableDeclAndInitExpr] Int32 a = ... -# 25| -1: [TypeMention] int -# 25| 0: [LocalVariableAccess] access to local variable a -# 25| 1: [FieldAccess] access to field x -# 25| -1: [LocalVariableAccess] access to local variable obj -# 27| 3: [ExprStmt] ...; -# 27| 0: [MethodCall] call to method SomeFun -# 27| 0: [ObjectCreation] object creation of type MyClass -# 27| -1: [TypeMention] MyClass -# 27| 0: [IntLiteral] 100 -pointers.cs: -# 1| [Class] Pointers -# 3| 5: [Method] addone -# 3| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 3| 0: [Parameter] arr -# 3| -1: [TypeMention] Int32[] -# 3| 1: [TypeMention] int -# 4| 4: [BlockStmt] {...} -# 5| 0: [LocalVariableDeclStmt] ... ...; -# 5| 0: [LocalVariableDeclAndInitExpr] Int32 length = ... -# 5| -1: [TypeMention] int -# 5| 0: [LocalVariableAccess] access to local variable length -# 5| 1: [PropertyCall] access to property Length -# 5| -1: [ParameterAccess] access to parameter arr -# 6| 1: [FixedStmt] fixed(...) { ... } -# 6| -1: [LocalVariableDeclAndInitExpr] Int32* b = ... -# 6| -1: [TypeMention] int* -# 6| 1: [TypeMention] int -# 6| 0: [LocalVariableAccess] access to local variable b -# 6| 1: [CastExpr] (...) ... -# 6| 1: [ParameterAccess] access to parameter arr -# 7| 0: [BlockStmt] {...} -# 8| 0: [LocalVariableDeclStmt] ... ...; -# 8| 0: [LocalVariableDeclAndInitExpr] Int32* p = ... -# 8| -1: [TypeMention] int* -# 8| 1: [TypeMention] int -# 8| 0: [LocalVariableAccess] access to local variable p -# 8| 1: [LocalVariableAccess] access to local variable b -# 9| 1: [ForStmt] for (...;...;...) ... -# 9| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 9| -1: [TypeMention] int -# 9| 0: [LocalVariableAccess] access to local variable i -# 9| 1: [IntLiteral] 0 -# 9| 0: [LTExpr] ... < ... -# 9| 0: [LocalVariableAccess] access to local variable i -# 9| 1: [LocalVariableAccess] access to local variable length -# 9| 1: [PostIncrExpr] ...++ -# 9| 0: [LocalVariableAccess] access to local variable i -# 10| 2: [ExprStmt] ...; -# 10| 0: [AssignAddExpr] ... += ... -# 10| 0: [PointerIndirectionExpr] *... -# 10| 0: [PostIncrExpr] ...++ -# 10| 0: [LocalVariableAccess] access to local variable p -# 10| 1: [IntLiteral] 1 -# 14| 6: [Class] MyClass -# 16| 5: [Field] fld1 -# 16| -1: [TypeMention] int -# 17| 6: [Field] fld2 -# 17| -1: [TypeMention] int -# 20| 7: [Struct] MyStruct -# 22| 5: [Field] fld -# 22| -1: [TypeMention] int -# 25| 8: [Method] Main -# 25| -1: [TypeMention] Void -# 25| 4: [BlockStmt] {...} -# 26| 0: [LocalVariableDeclStmt] ... ...; -# 26| 0: [LocalVariableDeclAndInitExpr] MyClass o = ... -# 26| -1: [TypeMention] MyClass -# 26| 0: [LocalVariableAccess] access to local variable o -# 26| 1: [ObjectCreation] object creation of type MyClass -# 26| 0: [TypeMention] MyClass -# 27| 1: [LocalVariableDeclStmt] ... ...; -# 27| 0: [LocalVariableDeclAndInitExpr] MyStruct s = ... -# 27| -1: [TypeMention] MyStruct -# 27| 0: [LocalVariableAccess] access to local variable s -# 27| 1: [ObjectCreation] object creation of type MyStruct -# 27| 0: [TypeMention] MyStruct -# 28| 2: [UnsafeStmt] unsafe {...} -# 29| 0: [BlockStmt] {...} -# 30| 0: [FixedStmt] fixed(...) { ... } -# 30| -2: [LocalVariableDeclAndInitExpr] Int32* q = ... -# 30| -1: [TypeMention] int* -# 30| 1: [TypeMention] int -# 30| 0: [LocalVariableAccess] access to local variable q -# 30| 1: [AddressOfExpr] &... -# 30| 0: [FieldAccess] access to field fld2 -# 30| -1: [LocalVariableAccess] access to local variable o -# 30| -1: [LocalVariableDeclAndInitExpr] Int32* p = ... -# 30| -1: [TypeMention] int* -# 30| 1: [TypeMention] int -# 30| 0: [LocalVariableAccess] access to local variable p -# 30| 1: [AddressOfExpr] &... -# 30| 0: [FieldAccess] access to field fld1 -# 30| -1: [LocalVariableAccess] access to local variable o -# 31| 0: [BlockStmt] {...} -# 32| 0: [ExprStmt] ...; -# 32| 0: [AssignExpr] ... = ... -# 32| 0: [PointerIndirectionExpr] *... -# 32| 0: [LocalVariableAccess] access to local variable p -# 32| 1: [IntLiteral] 0 -# 33| 1: [ExprStmt] ...; -# 33| 0: [AssignExpr] ... = ... -# 33| 0: [PointerIndirectionExpr] *... -# 33| 0: [LocalVariableAccess] access to local variable q -# 33| 1: [IntLiteral] 0 -# 34| 2: [LocalVariableDeclStmt] ... ...; -# 34| 0: [LocalVariableDeclAndInitExpr] MyStruct* r = ... -# 34| -1: [TypeMention] MyStruct* -# 34| 1: [TypeMention] MyStruct -# 34| 0: [LocalVariableAccess] access to local variable r -# 34| 1: [AddressOfExpr] &... -# 34| 0: [LocalVariableAccess] access to local variable s -# 35| 3: [ExprStmt] ...; -# 35| 0: [AssignExpr] ... = ... -# 35| 0: [FieldAccess] access to field fld -# 35| -1: [PointerIndirectionExpr] *... -# 35| 0: [LocalVariableAccess] access to local variable r -# 35| 1: [IntLiteral] 0 -# 39| 3: [LocalVariableDeclStmt] ... ...; -# 39| 0: [LocalVariableDeclAndInitExpr] Int32[] arr = ... -# 39| -1: [TypeMention] Int32[] -# 39| 1: [TypeMention] int -# 39| 0: [LocalVariableAccess] access to local variable arr -# 39| 1: [ArrayCreation] array creation of type Int32[] -# 39| -1: [ArrayInitializer] { ..., ... } -# 39| 0: [IntLiteral] 1 -# 39| 1: [IntLiteral] 2 -# 39| 2: [IntLiteral] 3 -# 40| 4: [ExprStmt] ...; -# 40| 0: [MethodCall] call to method addone -# 40| 0: [LocalVariableAccess] access to local variable arr -prop.cs: -# 1| [Class] PropClass -# 3| 5: [Field] prop -# 3| -1: [TypeMention] int -# 5| 6: [Property] Prop -# 5| -1: [TypeMention] int -# 7| 3: [Getter] get_Prop -# 8| 4: [BlockStmt] {...} -# 9| 0: [ReturnStmt] return ...; -# 9| 0: [MethodCall] call to method func -# 12| 4: [Setter] set_Prop -#-----| 2: (Parameters) -# 12| 0: [Parameter] value -# 13| 4: [BlockStmt] {...} -# 14| 0: [ExprStmt] ...; -# 14| 0: [AssignExpr] ... = ... -# 14| 0: [FieldAccess] access to field prop -# 14| 1: [ParameterAccess] access to parameter value -# 18| 7: [Method] func -# 18| -1: [TypeMention] int -# 19| 4: [BlockStmt] {...} -# 20| 0: [ReturnStmt] return ...; -# 20| 0: [IntLiteral] 0 -# 24| [Class] Prog -# 26| 5: [Method] Main -# 26| -1: [TypeMention] Void -# 27| 4: [BlockStmt] {...} -# 28| 0: [LocalVariableDeclStmt] ... ...; -# 28| 0: [LocalVariableDeclAndInitExpr] PropClass obj = ... -# 28| -1: [TypeMention] PropClass -# 28| 0: [LocalVariableAccess] access to local variable obj -# 28| 1: [ObjectCreation] object creation of type PropClass -# 28| 0: [TypeMention] PropClass -# 29| 1: [ExprStmt] ...; -# 29| 0: [AssignExpr] ... = ... -# 29| 0: [PropertyCall] access to property Prop -# 29| -1: [LocalVariableAccess] access to local variable obj -# 29| 1: [IntLiteral] 5 -# 30| 2: [LocalVariableDeclStmt] ... ...; -# 30| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 30| -1: [TypeMention] int -# 30| 0: [LocalVariableAccess] access to local variable x -# 30| 1: [PropertyCall] access to property Prop -# 30| -1: [LocalVariableAccess] access to local variable obj -simple_call.cs: -# 3| [Class] test_simple_call -# 5| 5: [Method] f -# 5| -1: [TypeMention] int -# 6| 4: [BlockStmt] {...} -# 7| 0: [ReturnStmt] return ...; -# 7| 0: [IntLiteral] 0 -# 10| 6: [Method] g -# 10| -1: [TypeMention] int -# 11| 4: [BlockStmt] {...} -# 12| 0: [ReturnStmt] return ...; -# 12| 0: [MethodCall] call to method f -simple_function.cs: -# 3| [Class] test_simple_function -# 5| 5: [Method] f -# 5| -1: [TypeMention] int -# 6| 4: [BlockStmt] {...} -# 7| 0: [ReturnStmt] return ...; -# 7| 0: [IntLiteral] 0 -stmts.cs: -# 3| [Class] test_stmts -# 5| 5: [Method] ifStmt -# 5| -1: [TypeMention] int -#-----| 2: (Parameters) -# 5| 0: [Parameter] x -# 5| -1: [TypeMention] int -# 6| 4: [BlockStmt] {...} -# 7| 0: [IfStmt] if (...) ... -# 7| 0: [EQExpr] ... == ... -# 7| 0: [ParameterAccess] access to parameter x -# 7| 1: [IntLiteral] 5 -# 8| 1: [ReturnStmt] return ...; -# 8| 0: [IntLiteral] 0 -# 10| 2: [ReturnStmt] return ...; -# 10| 0: [IntLiteral] 1 -# 13| 6: [Method] whileStmt -# 13| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 13| 0: [Parameter] x -# 13| -1: [TypeMention] int -# 14| 4: [BlockStmt] {...} -# 15| 0: [LocalVariableDeclStmt] ... ...; -# 15| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 15| -1: [TypeMention] int -# 15| 0: [LocalVariableAccess] access to local variable i -# 15| 1: [IntLiteral] 0 -# 16| 1: [WhileStmt] while (...) ... -# 16| 0: [LTExpr] ... < ... -# 16| 0: [LocalVariableAccess] access to local variable i -# 16| 1: [IntLiteral] 10 -# 17| 1: [BlockStmt] {...} -# 18| 0: [ExprStmt] ...; -# 18| 0: [AssignExpr] ... = ... -# 18| 0: [ParameterAccess] access to parameter x -# 18| 1: [AddExpr] ... + ... -# 18| 0: [ParameterAccess] access to parameter x -# 18| 1: [IntLiteral] 1 -# 22| 7: [Method] switchStmt -# 22| -1: [TypeMention] int -# 23| 4: [BlockStmt] {...} -# 24| 0: [LocalVariableDeclStmt] ... ...; -# 24| 0: [LocalVariableDeclAndInitExpr] Object caseSwitch = ... -# 24| -1: [TypeMention] object -# 24| 0: [LocalVariableAccess] access to local variable caseSwitch -# 24| 1: [ObjectCreation] object creation of type Object -# 24| 0: [TypeMention] object -# 25| 1: [LocalVariableDeclStmt] ... ...; -# 25| 0: [LocalVariableDeclAndInitExpr] Int32 select = ... -# 25| -1: [TypeMention] int -# 25| 0: [LocalVariableAccess] access to local variable select -# 25| 1: [IntLiteral] 0 -# 27| 2: [SwitchStmt] switch (...) {...} -# 27| 0: [LocalVariableAccess] access to local variable caseSwitch -# 29| 0: [ConstCase] case ...: -# 29| 0: [ConstantPatternExpr,UnaryMinusExpr] -... -# 29| 0: [IntLiteral] 1 -# 30| 1: [GotoCaseStmt] goto case ...; -# 30| 0: [BoolLiteral] true -# 31| 2: [ConstCase] case ...: -# 31| 0: [ConstantPatternExpr,IntLiteral] 0 -# 32| 3: [GotoCaseStmt] goto case ...; -# 32| 0: [StringLiteralUtf16] "123" -# 33| 4: [ConstCase] case ...: -# 33| 0: [ConstantPatternExpr,StringLiteralUtf16] "123" -# 34| 5: [ExprStmt] ...; -# 34| 0: [AssignExpr] ... = ... -# 34| 0: [LocalVariableAccess] access to local variable select -# 34| 1: [IntLiteral] 100 -# 35| 6: [BreakStmt] break; -# 36| 7: [ConstCase] case ...: -# 36| 0: [BoolLiteral,ConstantPatternExpr] true -# 37| 8: [ExprStmt] ...; -# 37| 0: [AssignExpr] ... = ... -# 37| 0: [LocalVariableAccess] access to local variable select -# 37| 1: [IntLiteral] 101 -# 38| 9: [GotoDefaultStmt] goto default; -# 39| 10: [DefaultCase] default: -# 40| 11: [ReturnStmt] return ...; -# 40| 0: [LocalVariableAccess] access to local variable select -# 42| 3: [ReturnStmt] return ...; -# 42| 0: [IntLiteral] 0 -# 45| 8: [Method] tryCatchFinally -# 45| -1: [TypeMention] Void -# 46| 4: [BlockStmt] {...} -# 47| 0: [LocalVariableDeclStmt] ... ...; -# 47| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 47| -1: [TypeMention] int -# 47| 0: [LocalVariableAccess] access to local variable x -# 47| 1: [IntLiteral] 5 -# 48| 1: [TryStmt] try {...} ... -# 63| -1: [BlockStmt] {...} -# 64| 0: [ExprStmt] ...; -# 64| 0: [AssignExpr] ... = ... -# 64| 0: [LocalVariableAccess] access to local variable x -# 64| 1: [IntLiteral] 2 -# 49| 0: [BlockStmt] {...} -# 50| 0: [IfStmt] if (...) ... -# 50| 0: [NEExpr] ... != ... -# 50| 0: [LocalVariableAccess] access to local variable x -# 50| 1: [IntLiteral] 0 -# 51| 1: [ThrowStmt] throw ...; -# 51| 0: [ObjectCreation] object creation of type Exception -# 51| 0: [TypeMention] Exception -# 52| 1: [ExprStmt] ...; -# 52| 0: [AssignExpr] ... = ... -# 52| 0: [LocalVariableAccess] access to local variable x -# 52| 1: [IntLiteral] 0 -# 54| 1: [SpecificCatchClause] catch (...) {...} -# 54| 0: [LocalVariableDeclExpr] Exception ex -# 54| 0: [TypeMention] Exception -# 55| 1: [BlockStmt] {...} -# 56| 0: [ExprStmt] ...; -# 56| 0: [AssignExpr] ... = ... -# 56| 0: [LocalVariableAccess] access to local variable x -# 56| 1: [IntLiteral] 1 -# 58| 2: [GeneralCatchClause] catch {...} -# 59| 1: [BlockStmt] {...} -# 60| 0: [ThrowStmt] throw ...; -# 68| 9: [Method] forStmt -# 68| -1: [TypeMention] Void -# 69| 4: [BlockStmt] {...} -# 70| 0: [LocalVariableDeclStmt] ... ...; -# 70| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 70| -1: [TypeMention] int -# 70| 0: [LocalVariableAccess] access to local variable x -# 70| 1: [IntLiteral] 0 -# 71| 1: [ForStmt] for (...;...;...) ... -# 71| -2: [LocalVariableDeclAndInitExpr] Int32 j = ... -# 71| -1: [TypeMention] int -# 71| 0: [LocalVariableAccess] access to local variable j -# 71| 1: [IntLiteral] 10 -# 71| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... -# 71| -1: [TypeMention] int -# 71| 0: [LocalVariableAccess] access to local variable i -# 71| 1: [IntLiteral] 0 -# 71| 0: [LTExpr] ... < ... -# 71| 0: [LocalVariableAccess] access to local variable i -# 71| 1: [LocalVariableAccess] access to local variable j -# 71| 1: [PostIncrExpr] ...++ -# 71| 0: [LocalVariableAccess] access to local variable i -# 71| 2: [PostDecrExpr] ...-- -# 71| 0: [LocalVariableAccess] access to local variable j -# 72| 3: [BlockStmt] {...} -# 73| 0: [ExprStmt] ...; -# 73| 0: [AssignExpr] ... = ... -# 73| 0: [LocalVariableAccess] access to local variable x -# 73| 1: [SubExpr] ... - ... -# 73| 0: [LocalVariableAccess] access to local variable x -# 73| 1: [IntLiteral] 1 -# 76| 2: [LocalVariableDeclStmt] ... ...; -# 76| 0: [LocalVariableDeclExpr] Int32 a -# 76| 0: [TypeMention] int -# 76| 1: [LocalVariableDeclAndInitExpr] Int32 b = ... -# 76| -1: [TypeMention] int -# 76| 0: [LocalVariableAccess] access to local variable b -# 76| 1: [IntLiteral] 10 -# 77| 3: [ForStmt] for (...;...;...) ... -# 77| -1: [AssignExpr] ... = ... -# 77| 0: [LocalVariableAccess] access to local variable a -# 77| 1: [IntLiteral] 0 -# 77| 0: [LTExpr] ... < ... -# 77| 0: [LocalVariableAccess] access to local variable a -# 77| 1: [LocalVariableAccess] access to local variable b -# 78| 1: [BlockStmt] {...} -# 79| 0: [ExprStmt] ...; -# 79| 0: [PostIncrExpr] ...++ -# 79| 0: [LocalVariableAccess] access to local variable a -# 82| 4: [ForStmt] for (...;...;...) ... -# 83| 1: [BlockStmt] {...} -# 88| 10: [Method] doWhile -# 88| -1: [TypeMention] Void -# 89| 4: [BlockStmt] {...} -# 90| 0: [LocalVariableDeclStmt] ... ...; -# 90| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... -# 90| -1: [TypeMention] int -# 90| 0: [LocalVariableAccess] access to local variable x -# 90| 1: [IntLiteral] 0 -# 91| 1: [DoStmt] do ... while (...); -# 95| 0: [LTExpr] ... < ... -# 95| 0: [LocalVariableAccess] access to local variable x -# 95| 1: [IntLiteral] 10 -# 92| 1: [BlockStmt] {...} -# 93| 0: [ExprStmt] ...; -# 93| 0: [AssignExpr] ... = ... -# 93| 0: [LocalVariableAccess] access to local variable x -# 93| 1: [AddExpr] ... + ... -# 93| 0: [LocalVariableAccess] access to local variable x -# 93| 1: [IntLiteral] 1 -# 98| 11: [Method] checkedUnchecked -# 98| -1: [TypeMention] Void -# 99| 4: [BlockStmt] {...} -# 100| 0: [LocalVariableDeclStmt] ... ...; -# 100| 0: [LocalVariableDeclAndInitExpr] Int32 num = ... -# 100| -1: [TypeMention] int -# 100| 0: [LocalVariableAccess] access to local variable num -# 100| 1: [MemberConstantAccess] access to constant MaxValue -# 100| -1: [TypeAccess] access to type Int32 -# 100| 0: [TypeMention] int -# 101| 1: [UncheckedStmt] unchecked {...} -# 102| 0: [BlockStmt] {...} -# 103| 0: [ExprStmt] ...; -# 103| 0: [AssignExpr] ... = ... -# 103| 0: [LocalVariableAccess] access to local variable num -# 103| 1: [AddExpr] ... + ... -# 103| 0: [LocalVariableAccess] access to local variable num -# 103| 1: [IntLiteral] 1 -# 105| 2: [CheckedStmt] checked {...} -# 106| 0: [BlockStmt] {...} -# 107| 0: [ExprStmt] ...; -# 107| 0: [AssignExpr] ... = ... -# 107| 0: [LocalVariableAccess] access to local variable num -# 107| 1: [AddExpr] ... + ... -# 107| 0: [LocalVariableAccess] access to local variable num -# 107| 1: [IntLiteral] 1 -using.cs: -# 3| [Class] UsingStmt -# 5| 5: [Class] MyDisposable -#-----| 3: (Base types) -# 5| 1: [TypeMention] IDisposable -# 7| 4: [InstanceConstructor] MyDisposable -# 7| 4: [BlockStmt] {...} -# 8| 5: [Method] DoSomething -# 8| -1: [TypeMention] Void -# 8| 4: [BlockStmt] {...} -# 9| 6: [Method] Dispose -# 9| -1: [TypeMention] Void -# 9| 4: [BlockStmt] {...} -# 12| 6: [Method] Main -# 12| -1: [TypeMention] Void -# 13| 4: [BlockStmt] {...} -# 14| 0: [UsingBlockStmt] using (...) {...} -# 14| -1: [LocalVariableDeclAndInitExpr] MyDisposable o1 = ... -# 14| -1: [TypeMention] MyDisposable -# 14| 0: [LocalVariableAccess] access to local variable o1 -# 14| 1: [ObjectCreation] object creation of type MyDisposable -# 14| 0: [TypeMention] MyDisposable -# 15| 1: [BlockStmt] {...} -# 16| 0: [ExprStmt] ...; -# 16| 0: [MethodCall] call to method DoSomething -# 16| -1: [LocalVariableAccess] access to local variable o1 -# 19| 1: [LocalVariableDeclStmt] ... ...; -# 19| 0: [LocalVariableDeclAndInitExpr] MyDisposable o2 = ... -# 19| -1: [TypeMention] MyDisposable -# 19| 0: [LocalVariableAccess] access to local variable o2 -# 19| 1: [ObjectCreation] object creation of type MyDisposable -# 19| 0: [TypeMention] MyDisposable -# 20| 2: [UsingBlockStmt] using (...) {...} -# 20| 0: [LocalVariableAccess] access to local variable o2 -# 21| 1: [BlockStmt] {...} -# 22| 0: [ExprStmt] ...; -# 22| 0: [MethodCall] call to method DoSomething -# 22| -1: [LocalVariableAccess] access to local variable o2 -# 25| 3: [UsingDeclStmt] using ... ...; -# 25| 0: [LocalVariableDeclAndInitExpr] MyDisposable o3 = ... -# 25| -1: [TypeMention] MyDisposable -# 25| 0: [LocalVariableAccess] access to local variable o3 -# 25| 1: [ObjectCreation] object creation of type MyDisposable -# 25| 0: [TypeMention] MyDisposable -# 26| 4: [ExprStmt] ...; -# 26| 0: [MethodCall] call to method DoSomething -# 26| -1: [LocalVariableAccess] access to local variable o3 -variables.cs: -# 3| [Class] test_variables -# 5| 5: [Method] f -# 5| -1: [TypeMention] Void -# 6| 4: [BlockStmt] {...} -# 7| 0: [LocalVariableDeclStmt] ... ...; -# 7| 0: [LocalVariableDeclExpr] Int32 x -# 7| 0: [TypeMention] int -# 7| 1: [LocalVariableDeclAndInitExpr] Int32 y = ... -# 7| -1: [TypeMention] int -# 7| 0: [LocalVariableAccess] access to local variable y -# 7| 1: [IntLiteral] 5 -# 8| 1: [ExprStmt] ...; -# 8| 0: [AssignExpr] ... = ... -# 8| 0: [LocalVariableAccess] access to local variable x -# 8| 1: [IntLiteral] 4 -# 9| 2: [ExprStmt] ...; -# 9| 0: [AssignExpr] ... = ... -# 9| 0: [LocalVariableAccess] access to local variable x -# 9| 1: [LocalVariableAccess] access to local variable y -# 10| 3: [LocalVariableDeclStmt] ... ...; -# 10| 0: [LocalVariableDeclAndInitExpr] Int32 z = ... -# 10| -1: [TypeMention] int -# 10| 0: [LocalVariableAccess] access to local variable z -# 10| 1: [LocalVariableAccess] access to local variable y diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.qlref b/csharp/ql/test/experimental/ir/ir/PrintAst.qlref deleted file mode 100644 index f867dd01f9f..00000000000 --- a/csharp/ql/test/experimental/ir/ir/PrintAst.qlref +++ /dev/null @@ -1 +0,0 @@ -shared/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/array.cs b/csharp/ql/test/experimental/ir/ir/array.cs deleted file mode 100644 index d53a828ff54..00000000000 --- a/csharp/ql/test/experimental/ir/ir/array.cs +++ /dev/null @@ -1,22 +0,0 @@ -public class ArrayTest { - public void one_dim_init_acc() - { - int[] one_dim = {100, 101, 102}; - one_dim[0] = 1000; - one_dim[1] = one_dim[0]; - one_dim[1] = 1003; - - int i = 0; - one_dim[i] = 0; - } - - public void twod_and_init_acc() - { - int[,] a = { {100, 101}, {102, 103} }; - int[,] b = new int[5, 5]; - int[,] c = new int[2, 2] { {100, 101}, {102, 103} }; - int[,] d = new int[,] { {100, 101}, {102, 103} }; - int[,] e = a; - e[1, 1] = -1; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs deleted file mode 100644 index 21fdfccbcf9..00000000000 --- a/csharp/ql/test/experimental/ir/ir/assignop.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -class AssignOp -{ - static void Main() - { - int a = 1; - int c = 1; - - c += a; - c -= a; - c *= a; - c /= a; - c %= a; - c <<= 2; - c >>= 2; - c &= 2; - c ^= 2; - c |= 2; - c >>>= 2; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/casts.cs b/csharp/ql/test/experimental/ir/ir/casts.cs deleted file mode 100644 index cd885ce30f2..00000000000 --- a/csharp/ql/test/experimental/ir/ir/casts.cs +++ /dev/null @@ -1,17 +0,0 @@ -public class Casts_A -{ -} - -public class Casts_B : Casts_A -{ -} - -public class Casts -{ - public static void Main() - { - Casts_A Aobj = new Casts_A(); - Casts_B bobjCE = (Casts_B) Aobj; - Casts_B bobjAS = Aobj as Casts_B; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/collections.cs b/csharp/ql/test/experimental/ir/ir/collections.cs deleted file mode 100644 index b8f6c56dd50..00000000000 --- a/csharp/ql/test/experimental/ir/ir/collections.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -public class Collections -{ - class MyClass - { - public string a; - public string b; - } - - public static void Main() - { - var dict = new Dictionary() - { - { 0, new MyClass { a="Hello", b="World" } }, - { 1, new MyClass { a="Foo", b="Bar" } } - }; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/constructor_init.cs b/csharp/ql/test/experimental/ir/ir/constructor_init.cs deleted file mode 100644 index 25d1c20660e..00000000000 --- a/csharp/ql/test/experimental/ir/ir/constructor_init.cs +++ /dev/null @@ -1,35 +0,0 @@ -public class BaseClass -{ - int num; - - public BaseClass() - { - } - - public BaseClass(int i) - { - num = i; - } -} - -public class DerivedClass : BaseClass -{ - public DerivedClass() : base() - { - } - - public DerivedClass(int i) : base(i) - { - } - - public DerivedClass(int i, int j): this(i) - { - } - - static void Main() - { - DerivedClass obj1 = new DerivedClass(); - DerivedClass obj2 = new DerivedClass(1); - DerivedClass obj3 = new DerivedClass(1, 2); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/crement.cs b/csharp/ql/test/experimental/ir/ir/crement.cs deleted file mode 100644 index 857b2fd804d..00000000000 --- a/csharp/ql/test/experimental/ir/ir/crement.cs +++ /dev/null @@ -1,11 +0,0 @@ -class CrementOpsTest -{ - public static void Main() - { - int x = 10; - int a = x++; - int b = --x; - int c = ++x; - x = x--; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/delegates.cs b/csharp/ql/test/experimental/ir/ir/delegates.cs deleted file mode 100644 index 5f9def1260a..00000000000 --- a/csharp/ql/test/experimental/ir/ir/delegates.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; - -public class Delegates { - delegate int Del(int num); - - static int returns(int ret) - { - return ret; - } - - public static void Main() { - Del del1 = new Del(returns); - del1(5); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/events.cs b/csharp/ql/test/experimental/ir/ir/events.cs deleted file mode 100644 index 7364b0069f9..00000000000 --- a/csharp/ql/test/experimental/ir/ir/events.cs +++ /dev/null @@ -1,35 +0,0 @@ -class Events -{ - public delegate string MyDel(string str); - public MyDel Inst; - - event MyDel MyEvent; - - public Events() - { - this.Inst = new MyDel(this.Fun); - } - - public void AddEvent() - { - this.MyEvent += this.Inst; - } - - public void RemoveEvent() - { - this.MyEvent -= this.Inst; - } - - public string Fun(string str) - { - return str; - } - - static void Main(string[] args) - { - Events obj = new Events(); - obj.AddEvent(); - string result = obj.MyEvent("string"); - obj.RemoveEvent(); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/foreach.cs b/csharp/ql/test/experimental/ir/ir/foreach.cs deleted file mode 100644 index 2ddf2fa1b1d..00000000000 --- a/csharp/ql/test/experimental/ir/ir/foreach.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -class ForEach { - public static void Main() { - int[] a_array = new int[] { 1, 2, 3, 4, 5, 6, 7 }; - - foreach(int items in a_array) - { - int x = items; - } - } -} diff --git a/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs b/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs deleted file mode 100644 index 7bf64c02482..00000000000 --- a/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -public class test_call_with_param -{ - public static int f(int x, int y) - { - return x + y; - } - - public static int g() - { - return f(2, 3); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/indexers.cs b/csharp/ql/test/experimental/ir/ir/indexers.cs deleted file mode 100644 index dfe9c5fa21e..00000000000 --- a/csharp/ql/test/experimental/ir/ir/indexers.cs +++ /dev/null @@ -1,26 +0,0 @@ -class Indexers -{ - public class MyClass - { - private string[] address = new string[2]; - public string this[int index] - { - get - { - return address[index]; - } - set - { - address[index] = value; - } - } - } - - public static void Main() - { - MyClass inst = new MyClass(); - inst[0] = "str1"; - inst[1] = "str1"; - inst[1] = inst[0]; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs b/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs deleted file mode 100644 index 37fad70eaec..00000000000 --- a/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs +++ /dev/null @@ -1,37 +0,0 @@ -public class A -{ - public virtual int function() - { - return 0; - } -} - -class B : A -{ -} - -class C : B -{ - public override int function() - { - return 1; - } -} - -class Program -{ - static void Main() - { - B objB = new B(); - objB.function(); - - // Check conversion works - A objA; - objA = objB; - objA.function(); - - A objC = new C(); - objC.function(); - } - -} diff --git a/csharp/ql/test/experimental/ir/ir/inoutref.cs b/csharp/ql/test/experimental/ir/ir/inoutref.cs deleted file mode 100644 index 604337da1de..00000000000 --- a/csharp/ql/test/experimental/ir/ir/inoutref.cs +++ /dev/null @@ -1,38 +0,0 @@ -class MyClass { - public int fld; -} - -struct MyStruct { - public int fld; -} - -class InOutRef -{ - static void set(ref MyClass o1, MyClass o2) - { - o1 = o2; - } - - static void F(ref int a, ref MyStruct b, in MyStruct b1, ref MyClass c, in MyClass c1) - { - b.fld = 0; - a = b.fld; - - c.fld = 10; - a = c.fld; - - b = b1; - - set(ref c, c1); - } - - static void Main() - { - int a = 0; - MyStruct b = new MyStruct(); - MyClass c = new MyClass(); - F(ref a, ref b, in b, ref c, in c); - - int x = b.fld; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/isexpr.cs b/csharp/ql/test/experimental/ir/ir/isexpr.cs deleted file mode 100644 index d00a4f9d07f..00000000000 --- a/csharp/ql/test/experimental/ir/ir/isexpr.cs +++ /dev/null @@ -1,22 +0,0 @@ -public class Is_A -{ - public int x; -} - -public class IsExpr -{ - public static void Main() - { - Is_A obj = null; - - object o = obj; - if (o is Is_A tmp) - { - int res = tmp.x; - } - if (o is Is_A) - { - - } - } -} diff --git a/csharp/ql/test/experimental/ir/ir/jumps.cs b/csharp/ql/test/experimental/ir/ir/jumps.cs deleted file mode 100644 index 52b0ba9439e..00000000000 --- a/csharp/ql/test/experimental/ir/ir/jumps.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -class Jumps -{ - public static void Main() - { - for (int i = 1; i <= 10; i++) - { - if (i == 3) - continue; - else if (i == 5) - break; - Console.WriteLine("BreakAndContinue"); - } - - for (int i = 0 ; i < 10 ; ) - { - i++; - continue; - } - - int a = 0; - while (true) - { - a++; - if (a == 5) - continue; - if (a == 10) - break; - } - - for (int i = 1; i <= 10; i++) - { - if (i == 5) - goto done; - } - done: - Console.WriteLine("Done"); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/lock.cs b/csharp/ql/test/experimental/ir/ir/lock.cs deleted file mode 100644 index affc9f3f981..00000000000 --- a/csharp/ql/test/experimental/ir/ir/lock.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -class LockTest -{ - static void A() - { - object @object = new object(); - lock (@object) - { - Console.WriteLine(@object.ToString()); - } - } -} diff --git a/csharp/ql/test/experimental/ir/ir/obj_creation.cs b/csharp/ql/test/experimental/ir/ir/obj_creation.cs deleted file mode 100644 index d045f44ed88..00000000000 --- a/csharp/ql/test/experimental/ir/ir/obj_creation.cs +++ /dev/null @@ -1,29 +0,0 @@ -public class ObjCreation -{ - public class MyClass - { - public int x; - - public MyClass() - { - } - - public MyClass(int _x) - { - x = _x; - } - } - - public static void SomeFun(MyClass x) - { - } - - public static void Main() - { - MyClass obj = new MyClass(100); - MyClass obj_initlist = new MyClass { x = 101 }; - int a = obj.x; - - SomeFun(new MyClass(100)); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/options b/csharp/ql/test/experimental/ir/ir/options deleted file mode 100644 index c943386b4b8..00000000000 --- a/csharp/ql/test/experimental/ir/ir/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: /langversion:preview diff --git a/csharp/ql/test/experimental/ir/ir/pointers.cs b/csharp/ql/test/experimental/ir/ir/pointers.cs deleted file mode 100644 index c15cbc45176..00000000000 --- a/csharp/ql/test/experimental/ir/ir/pointers.cs +++ /dev/null @@ -1,42 +0,0 @@ -class Pointers -{ - unsafe static void addone(int[] arr) - { - int length = arr.Length; - fixed (int* b = arr) - { - int* p = b; - for(int i = 0; i < length; i++) - *p++ += 1; - } - } - - class MyClass - { - public int fld1; - public int fld2; - } - - struct MyStruct - { - public int fld; - } - - static void Main() { - MyClass o = new MyClass(); - MyStruct s = new MyStruct(); - unsafe - { - fixed(int* p = &o.fld1, q = &o.fld2) - { - *p = 0; - *q = 0; - MyStruct* r = &s; - (*r).fld = 0; - } - } - - int[] arr = {1, 2, 3}; - addone(arr); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/prop.cs b/csharp/ql/test/experimental/ir/ir/prop.cs deleted file mode 100644 index a075703d875..00000000000 --- a/csharp/ql/test/experimental/ir/ir/prop.cs +++ /dev/null @@ -1,32 +0,0 @@ -class PropClass -{ - private static int prop; - - public int Prop - { - get - { - return func(); - } - - set - { - prop = value; - } - } - - private int func() - { - return 0; - } -} - -class Prog -{ - public static void Main() - { - PropClass obj = new PropClass(); - obj.Prop = 5; - int x = obj.Prop; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected deleted file mode 100644 index 7ba67d33cae..00000000000 --- a/csharp/ql/test/experimental/ir/ir/raw_ir.expected +++ /dev/null @@ -1,2008 +0,0 @@ -array.cs: -# 2| ArrayTest.one_dim_init_acc() -# 2| Block 0 -# 2| v2_1(Void) = EnterFunction : -# 2| mu2_2() = AliasedDefinition : -# 2| r2_3(glval) = InitializeThis : -# 4| r4_1(glval) = VariableAddress[one_dim] : -# 4| mu4_2(Int32[]) = Uninitialized[one_dim] : &:r4_1 -# 4| r4_3(Int32) = Constant[0] : -# 4| r4_4(glval) = PointerAdd[4] : r4_1, r4_3 -# 4| r4_5(Int32) = Constant[100] : -# 4| mu4_6(Int32) = Store[?] : &:r4_4, r4_5 -# 4| r4_7(Int32) = Constant[1] : -# 4| r4_8(glval) = PointerAdd[4] : r4_1, r4_7 -# 4| r4_9(Int32) = Constant[101] : -# 4| mu4_10(Int32) = Store[?] : &:r4_8, r4_9 -# 4| r4_11(Int32) = Constant[2] : -# 4| r4_12(glval) = PointerAdd[4] : r4_1, r4_11 -# 4| r4_13(Int32) = Constant[102] : -# 4| mu4_14(Int32) = Store[?] : &:r4_12, r4_13 -# 5| r5_1(Int32) = Constant[1000] : -# 5| r5_2(glval) = VariableAddress[one_dim] : -# 5| r5_3(Int32[]) = ElementsAddress : r5_2 -# 5| r5_4(Int32) = Constant[0] : -# 5| r5_5(Int32[]) = PointerAdd[4] : r5_3, r5_4 -# 5| mu5_6(Int32) = Store[?] : &:r5_5, r5_1 -# 6| r6_1(glval) = VariableAddress[one_dim] : -# 6| r6_2(Int32[]) = ElementsAddress : r6_1 -# 6| r6_3(Int32) = Constant[0] : -# 6| r6_4(Int32[]) = PointerAdd[4] : r6_2, r6_3 -# 6| r6_5(Int32) = Load[?] : &:r6_4, ~m? -# 6| r6_6(glval) = VariableAddress[one_dim] : -# 6| r6_7(Int32[]) = ElementsAddress : r6_6 -# 6| r6_8(Int32) = Constant[1] : -# 6| r6_9(Int32[]) = PointerAdd[4] : r6_7, r6_8 -# 6| mu6_10(Int32) = Store[?] : &:r6_9, r6_5 -# 7| r7_1(Int32) = Constant[1003] : -# 7| r7_2(glval) = VariableAddress[one_dim] : -# 7| r7_3(Int32[]) = ElementsAddress : r7_2 -# 7| r7_4(Int32) = Constant[1] : -# 7| r7_5(Int32[]) = PointerAdd[4] : r7_3, r7_4 -# 7| mu7_6(Int32) = Store[?] : &:r7_5, r7_1 -# 9| r9_1(glval) = VariableAddress[i] : -# 9| r9_2(Int32) = Constant[0] : -# 9| mu9_3(Int32) = Store[i] : &:r9_1, r9_2 -# 10| r10_1(Int32) = Constant[0] : -# 10| r10_2(glval) = VariableAddress[one_dim] : -# 10| r10_3(Int32[]) = ElementsAddress : r10_2 -# 10| r10_4(glval) = VariableAddress[i] : -# 10| r10_5(Int32) = Load[i] : &:r10_4, ~m? -# 10| r10_6(Int32[]) = PointerAdd[4] : r10_3, r10_5 -# 10| mu10_7(Int32) = Store[?] : &:r10_6, r10_1 -# 2| v2_4(Void) = ReturnVoid : -# 2| v2_5(Void) = AliasedUse : ~m? -# 2| v2_6(Void) = ExitFunction : - -# 13| ArrayTest.twod_and_init_acc() -# 13| Block 0 -# 13| v13_1(Void) = EnterFunction : -# 13| mu13_2() = AliasedDefinition : -# 13| r13_3(glval) = InitializeThis : -# 15| r15_1(glval) = VariableAddress[a] : -# 15| mu15_2(Int32[,]) = Uninitialized[a] : &:r15_1 -# 15| r15_3(Int32) = Constant[0] : -# 15| r15_4(glval) = PointerAdd[8] : r15_1, r15_3 -# 15| r15_5(Int32) = Constant[0] : -# 15| r15_6(glval) = PointerAdd[4] : r15_4, r15_5 -# 15| r15_7(Int32) = Constant[100] : -# 15| mu15_8(Int32) = Store[?] : &:r15_6, r15_7 -# 15| r15_9(Int32) = Constant[1] : -# 15| r15_10(glval) = PointerAdd[4] : r15_4, r15_9 -# 15| r15_11(Int32) = Constant[101] : -# 15| mu15_12(Int32) = Store[?] : &:r15_10, r15_11 -# 15| r15_13(Int32) = Constant[1] : -# 15| r15_14(glval) = PointerAdd[8] : r15_1, r15_13 -# 15| r15_15(Int32) = Constant[0] : -# 15| r15_16(glval) = PointerAdd[4] : r15_14, r15_15 -# 15| r15_17(Int32) = Constant[102] : -# 15| mu15_18(Int32) = Store[?] : &:r15_16, r15_17 -# 15| r15_19(Int32) = Constant[1] : -# 15| r15_20(glval) = PointerAdd[4] : r15_14, r15_19 -# 15| r15_21(Int32) = Constant[103] : -# 15| mu15_22(Int32) = Store[?] : &:r15_20, r15_21 -# 16| r16_1(glval) = VariableAddress[b] : -# 16| mu16_2(Int32[,]) = Uninitialized[b] : &:r16_1 -# 17| r17_1(glval) = VariableAddress[c] : -# 17| mu17_2(Int32[,]) = Uninitialized[c] : &:r17_1 -# 17| r17_3(Int32) = Constant[0] : -# 17| r17_4(glval) = PointerAdd[8] : r17_1, r17_3 -# 17| r17_5(Int32) = Constant[0] : -# 17| r17_6(glval) = PointerAdd[4] : r17_4, r17_5 -# 17| r17_7(Int32) = Constant[100] : -# 17| mu17_8(Int32) = Store[?] : &:r17_6, r17_7 -# 17| r17_9(Int32) = Constant[1] : -# 17| r17_10(glval) = PointerAdd[4] : r17_4, r17_9 -# 17| r17_11(Int32) = Constant[101] : -# 17| mu17_12(Int32) = Store[?] : &:r17_10, r17_11 -# 17| r17_13(Int32) = Constant[1] : -# 17| r17_14(glval) = PointerAdd[8] : r17_1, r17_13 -# 17| r17_15(Int32) = Constant[0] : -# 17| r17_16(glval) = PointerAdd[4] : r17_14, r17_15 -# 17| r17_17(Int32) = Constant[102] : -# 17| mu17_18(Int32) = Store[?] : &:r17_16, r17_17 -# 17| r17_19(Int32) = Constant[1] : -# 17| r17_20(glval) = PointerAdd[4] : r17_14, r17_19 -# 17| r17_21(Int32) = Constant[103] : -# 17| mu17_22(Int32) = Store[?] : &:r17_20, r17_21 -# 18| r18_1(glval) = VariableAddress[d] : -# 18| mu18_2(Int32[,]) = Uninitialized[d] : &:r18_1 -# 18| r18_3(Int32) = Constant[0] : -# 18| r18_4(glval) = PointerAdd[8] : r18_1, r18_3 -# 18| r18_5(Int32) = Constant[0] : -# 18| r18_6(glval) = PointerAdd[4] : r18_4, r18_5 -# 18| r18_7(Int32) = Constant[100] : -# 18| mu18_8(Int32) = Store[?] : &:r18_6, r18_7 -# 18| r18_9(Int32) = Constant[1] : -# 18| r18_10(glval) = PointerAdd[4] : r18_4, r18_9 -# 18| r18_11(Int32) = Constant[101] : -# 18| mu18_12(Int32) = Store[?] : &:r18_10, r18_11 -# 18| r18_13(Int32) = Constant[1] : -# 18| r18_14(glval) = PointerAdd[8] : r18_1, r18_13 -# 18| r18_15(Int32) = Constant[0] : -# 18| r18_16(glval) = PointerAdd[4] : r18_14, r18_15 -# 18| r18_17(Int32) = Constant[102] : -# 18| mu18_18(Int32) = Store[?] : &:r18_16, r18_17 -# 18| r18_19(Int32) = Constant[1] : -# 18| r18_20(glval) = PointerAdd[4] : r18_14, r18_19 -# 18| r18_21(Int32) = Constant[103] : -# 18| mu18_22(Int32) = Store[?] : &:r18_20, r18_21 -# 19| r19_1(glval) = VariableAddress[e] : -# 19| r19_2(glval) = VariableAddress[a] : -# 19| r19_3(Int32[,]) = Load[a] : &:r19_2, ~m? -# 19| mu19_4(Int32[,]) = Store[e] : &:r19_1, r19_3 -# 20| r20_1(Int32) = Constant[-1] : -# 20| r20_2(glval) = VariableAddress[e] : -# 20| r20_3(Int32[,]) = ElementsAddress : r20_2 -# 20| r20_4(Int32) = Constant[1] : -# 20| r20_5(Int32[,]) = PointerAdd[4] : r20_3, r20_4 -# 20| r20_6(Int32[]) = ElementsAddress : r20_5 -# 20| r20_7(Int32) = Constant[1] : -# 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 -# 20| mu20_9(Int32) = Store[?] : &:r20_8, r20_1 -# 13| v13_4(Void) = ReturnVoid : -# 13| v13_5(Void) = AliasedUse : ~m? -# 13| v13_6(Void) = ExitFunction : - -assignop.cs: -# 5| AssignOp.Main() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[a] : -# 7| r7_2(Int32) = Constant[1] : -# 7| mu7_3(Int32) = Store[a] : &:r7_1, r7_2 -# 8| r8_1(glval) = VariableAddress[c] : -# 8| r8_2(Int32) = Constant[1] : -# 8| mu8_3(Int32) = Store[c] : &:r8_1, r8_2 -# 10| r10_1(glval) = VariableAddress[a] : -# 10| r10_2(Int32) = Load[a] : &:r10_1, ~m? -# 10| r10_3(glval) = VariableAddress[c] : -# 10| r10_4(Int32) = Load[c] : &:r10_3, ~m? -# 10| r10_5(Int32) = Add : r10_4, r10_2 -# 10| mu10_6(Int32) = Store[c] : &:r10_3, r10_5 -# 11| r11_1(glval) = VariableAddress[a] : -# 11| r11_2(Int32) = Load[a] : &:r11_1, ~m? -# 11| r11_3(glval) = VariableAddress[c] : -# 11| r11_4(Int32) = Load[c] : &:r11_3, ~m? -# 11| r11_5(Int32) = Sub : r11_4, r11_2 -# 11| mu11_6(Int32) = Store[c] : &:r11_3, r11_5 -# 12| r12_1(glval) = VariableAddress[a] : -# 12| r12_2(Int32) = Load[a] : &:r12_1, ~m? -# 12| r12_3(glval) = VariableAddress[c] : -# 12| r12_4(Int32) = Load[c] : &:r12_3, ~m? -# 12| r12_5(Int32) = Mul : r12_4, r12_2 -# 12| mu12_6(Int32) = Store[c] : &:r12_3, r12_5 -# 13| r13_1(glval) = VariableAddress[a] : -# 13| r13_2(Int32) = Load[a] : &:r13_1, ~m? -# 13| r13_3(glval) = VariableAddress[c] : -# 13| r13_4(Int32) = Load[c] : &:r13_3, ~m? -# 13| r13_5(Int32) = Div : r13_4, r13_2 -# 13| mu13_6(Int32) = Store[c] : &:r13_3, r13_5 -# 14| r14_1(glval) = VariableAddress[a] : -# 14| r14_2(Int32) = Load[a] : &:r14_1, ~m? -# 14| r14_3(glval) = VariableAddress[c] : -# 14| r14_4(Int32) = Load[c] : &:r14_3, ~m? -# 14| r14_5(Int32) = Rem : r14_4, r14_2 -# 14| mu14_6(Int32) = Store[c] : &:r14_3, r14_5 -# 15| r15_1(Int32) = Constant[2] : -# 15| r15_2(glval) = VariableAddress[c] : -# 15| r15_3(Int32) = Load[c] : &:r15_2, ~m? -# 15| r15_4(Int32) = ShiftLeft : r15_3, r15_1 -# 15| mu15_5(Int32) = Store[c] : &:r15_2, r15_4 -# 16| r16_1(Int32) = Constant[2] : -# 16| r16_2(glval) = VariableAddress[c] : -# 16| r16_3(Int32) = Load[c] : &:r16_2, ~m? -# 16| r16_4(Int32) = ShiftRight : r16_3, r16_1 -# 16| mu16_5(Int32) = Store[c] : &:r16_2, r16_4 -# 17| r17_1(Int32) = Constant[2] : -# 17| r17_2(glval) = VariableAddress[c] : -# 17| r17_3(Int32) = Load[c] : &:r17_2, ~m? -# 17| r17_4(Int32) = BitAnd : r17_3, r17_1 -# 17| mu17_5(Int32) = Store[c] : &:r17_2, r17_4 -# 18| r18_1(Int32) = Constant[2] : -# 18| r18_2(glval) = VariableAddress[c] : -# 18| r18_3(Int32) = Load[c] : &:r18_2, ~m? -# 18| r18_4(Int32) = BitXor : r18_3, r18_1 -# 18| mu18_5(Int32) = Store[c] : &:r18_2, r18_4 -# 19| r19_1(Int32) = Constant[2] : -# 19| r19_2(glval) = VariableAddress[c] : -# 19| r19_3(Int32) = Load[c] : &:r19_2, ~m? -# 19| r19_4(Int32) = BitOr : r19_3, r19_1 -# 19| mu19_5(Int32) = Store[c] : &:r19_2, r19_4 -# 20| r20_1(Int32) = Constant[2] : -# 20| r20_2(glval) = VariableAddress[c] : -# 20| r20_3(Int32) = Load[c] : &:r20_2, ~m? -# 20| r20_4(Int32) = UnsignedShiftRight : r20_3, r20_1 -# 20| mu20_5(Int32) = Store[c] : &:r20_2, r20_4 -# 5| v5_3(Void) = ReturnVoid : -# 5| v5_4(Void) = AliasedUse : ~m? -# 5| v5_5(Void) = ExitFunction : - -casts.cs: -# 11| Casts.Main() -# 11| Block 0 -# 11| v11_1(Void) = EnterFunction : -# 11| mu11_2() = AliasedDefinition : -# 13| r13_1(glval) = VariableAddress[Aobj] : -# 13| r13_2(Casts_A) = NewObj : -# 13| r13_3() = FunctionAddress[Casts_A] : -# 13| v13_4(Void) = Call[Casts_A] : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~m? -# 13| mu13_6(Casts_A) = Store[Aobj] : &:r13_1, r13_2 -# 14| r14_1(glval) = VariableAddress[bobjCE] : -# 14| r14_2(glval) = VariableAddress[Aobj] : -# 14| r14_3(Casts_A) = Load[Aobj] : &:r14_2, ~m? -# 14| r14_4(Casts_B) = CheckedConvertOrThrow : r14_3 -# 14| mu14_5(Casts_B) = Store[bobjCE] : &:r14_1, r14_4 -# 15| r15_1(glval) = VariableAddress[bobjAS] : -# 15| r15_2(glval) = VariableAddress[Aobj] : -# 15| r15_3(Casts_A) = Load[Aobj] : &:r15_2, ~m? -# 15| r15_4(Casts_B) = CheckedConvertOrNull : r15_3 -# 15| mu15_5(Casts_B) = Store[bobjAS] : &:r15_1, r15_4 -# 11| v11_3(Void) = ReturnVoid : -# 11| v11_4(Void) = AliasedUse : ~m? -# 11| v11_5(Void) = ExitFunction : - -collections.cs: -# 11| Collections.Main() -# 11| Block 0 -# 11| v11_1(Void) = EnterFunction : -# 11| mu11_2() = AliasedDefinition : -# 13| r13_1(glval>) = VariableAddress[dict] : -# 13| r13_2(Dictionary) = NewObj : -# 13| r13_3() = FunctionAddress[Dictionary] : -# 13| v13_4(Void) = Call[Dictionary] : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~m? -# 15| r15_1() = FunctionAddress[Add] : -# 15| r15_2(Int32) = Constant[0] : -# 15| r15_3(MyClass) = NewObj : -# 15| r15_4() = FunctionAddress[MyClass] : -# 15| v15_5(Void) = Call[MyClass] : func:r15_4, this:r15_3 -# 15| mu15_6() = ^CallSideEffect : ~m? -# 15| r15_7(String) = StringConstant["Hello"] : -# 15| r15_8(glval) = FieldAddress[a] : r15_3 -# 15| mu15_9(String) = Store[?] : &:r15_8, r15_7 -# 15| r15_10(String) = StringConstant["World"] : -# 15| r15_11(glval) = FieldAddress[b] : r15_3 -# 15| mu15_12(String) = Store[?] : &:r15_11, r15_10 -# 15| v15_13(Void) = Call[Add] : func:r15_1, this:r13_2, 0:r15_2, 1:r15_3 -# 15| mu15_14() = ^CallSideEffect : ~m? -# 16| r16_1() = FunctionAddress[Add] : -# 16| r16_2(Int32) = Constant[1] : -# 16| r16_3(MyClass) = NewObj : -# 16| r16_4() = FunctionAddress[MyClass] : -# 16| v16_5(Void) = Call[MyClass] : func:r16_4, this:r16_3 -# 16| mu16_6() = ^CallSideEffect : ~m? -# 16| r16_7(String) = StringConstant["Foo"] : -# 16| r16_8(glval) = FieldAddress[a] : r16_3 -# 16| mu16_9(String) = Store[?] : &:r16_8, r16_7 -# 16| r16_10(String) = StringConstant["Bar"] : -# 16| r16_11(glval) = FieldAddress[b] : r16_3 -# 16| mu16_12(String) = Store[?] : &:r16_11, r16_10 -# 16| v16_13(Void) = Call[Add] : func:r16_1, this:r13_2, 0:r16_2, 1:r16_3 -# 16| mu16_14() = ^CallSideEffect : ~m? -# 13| mu13_6(Dictionary) = Store[dict] : &:r13_1, r13_2 -# 11| v11_3(Void) = ReturnVoid : -# 11| v11_4(Void) = AliasedUse : ~m? -# 11| v11_5(Void) = ExitFunction : - -constructor_init.cs: -# 5| BaseClass.BaseClass() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| r5_3(glval) = InitializeThis : -# 5| r5_4(glval) = Convert[BaseClass : Object] : r5_3 -# 5| r5_5() = FunctionAddress[Object] : -# 5| v5_6(Void) = Call[Object] : func:r5_5, this:r5_4 -# 5| mu5_7() = ^CallSideEffect : ~m? -# 6| v6_1(Void) = NoOp : -# 5| v5_8(Void) = ReturnVoid : -# 5| v5_9(Void) = AliasedUse : ~m? -# 5| v5_10(Void) = ExitFunction : - -# 9| BaseClass.BaseClass(int) -# 9| Block 0 -# 9| v9_1(Void) = EnterFunction : -# 9| mu9_2() = AliasedDefinition : -# 9| r9_3(glval) = InitializeThis : -# 9| r9_4(glval) = VariableAddress[i] : -# 9| mu9_5(Int32) = InitializeParameter[i] : &:r9_4 -# 9| r9_6(glval) = Convert[BaseClass : Object] : r9_3 -# 9| r9_7() = FunctionAddress[Object] : -# 9| v9_8(Void) = Call[Object] : func:r9_7, this:r9_6 -# 9| mu9_9() = ^CallSideEffect : ~m? -# 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load[i] : &:r11_1, ~m? -# 11| r11_3(BaseClass) = CopyValue : r9_3 -# 11| r11_4(glval) = FieldAddress[num] : r11_3 -# 11| mu11_5(Int32) = Store[?] : &:r11_4, r11_2 -# 9| v9_10(Void) = ReturnVoid : -# 9| v9_11(Void) = AliasedUse : ~m? -# 9| v9_12(Void) = ExitFunction : - -# 17| DerivedClass.DerivedClass() -# 17| Block 0 -# 17| v17_1(Void) = EnterFunction : -# 17| mu17_2() = AliasedDefinition : -# 17| r17_3(glval) = InitializeThis : -# 17| r17_4(glval) = Convert[DerivedClass : BaseClass] : r17_3 -# 17| r17_5() = FunctionAddress[BaseClass] : -# 17| v17_6(Void) = Call[BaseClass] : func:r17_5, this:r17_4 -# 17| mu17_7() = ^CallSideEffect : ~m? -# 18| v18_1(Void) = NoOp : -# 17| v17_8(Void) = ReturnVoid : -# 17| v17_9(Void) = AliasedUse : ~m? -# 17| v17_10(Void) = ExitFunction : - -# 21| DerivedClass.DerivedClass(int) -# 21| Block 0 -# 21| v21_1(Void) = EnterFunction : -# 21| mu21_2() = AliasedDefinition : -# 21| r21_3(glval) = InitializeThis : -# 21| r21_4(glval) = VariableAddress[i] : -# 21| mu21_5(Int32) = InitializeParameter[i] : &:r21_4 -# 21| r21_6(glval) = Convert[DerivedClass : BaseClass] : r21_3 -# 21| r21_7() = FunctionAddress[BaseClass] : -# 21| r21_8(glval) = VariableAddress[i] : -# 21| r21_9(Int32) = Load[i] : &:r21_8, ~m? -# 21| v21_10(Void) = Call[BaseClass] : func:r21_7, this:r21_6, 0:r21_9 -# 21| mu21_11() = ^CallSideEffect : ~m? -# 22| v22_1(Void) = NoOp : -# 21| v21_12(Void) = ReturnVoid : -# 21| v21_13(Void) = AliasedUse : ~m? -# 21| v21_14(Void) = ExitFunction : - -# 25| DerivedClass.DerivedClass(int, int) -# 25| Block 0 -# 25| v25_1(Void) = EnterFunction : -# 25| mu25_2() = AliasedDefinition : -# 25| r25_3(glval) = InitializeThis : -# 25| r25_4(glval) = VariableAddress[i] : -# 25| mu25_5(Int32) = InitializeParameter[i] : &:r25_4 -# 25| r25_6(glval) = VariableAddress[j] : -# 25| mu25_7(Int32) = InitializeParameter[j] : &:r25_6 -# 25| r25_8() = FunctionAddress[DerivedClass] : -# 25| r25_9(glval) = VariableAddress[i] : -# 25| r25_10(Int32) = Load[i] : &:r25_9, ~m? -# 25| v25_11(Void) = Call[DerivedClass] : func:r25_8, this:r25_3, 0:r25_10 -# 25| mu25_12() = ^CallSideEffect : ~m? -# 26| v26_1(Void) = NoOp : -# 25| v25_13(Void) = ReturnVoid : -# 25| v25_14(Void) = AliasedUse : ~m? -# 25| v25_15(Void) = ExitFunction : - -# 29| DerivedClass.Main() -# 29| Block 0 -# 29| v29_1(Void) = EnterFunction : -# 29| mu29_2() = AliasedDefinition : -# 31| r31_1(glval) = VariableAddress[obj1] : -# 31| r31_2(DerivedClass) = NewObj : -# 31| r31_3() = FunctionAddress[DerivedClass] : -# 31| v31_4(Void) = Call[DerivedClass] : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~m? -# 31| mu31_6(DerivedClass) = Store[obj1] : &:r31_1, r31_2 -# 32| r32_1(glval) = VariableAddress[obj2] : -# 32| r32_2(DerivedClass) = NewObj : -# 32| r32_3() = FunctionAddress[DerivedClass] : -# 32| r32_4(Int32) = Constant[1] : -# 32| v32_5(Void) = Call[DerivedClass] : func:r32_3, this:r32_2, 0:r32_4 -# 32| mu32_6() = ^CallSideEffect : ~m? -# 32| mu32_7(DerivedClass) = Store[obj2] : &:r32_1, r32_2 -# 33| r33_1(glval) = VariableAddress[obj3] : -# 33| r33_2(DerivedClass) = NewObj : -# 33| r33_3() = FunctionAddress[DerivedClass] : -# 33| r33_4(Int32) = Constant[1] : -# 33| r33_5(Int32) = Constant[2] : -# 33| v33_6(Void) = Call[DerivedClass] : func:r33_3, this:r33_2, 0:r33_4, 1:r33_5 -# 33| mu33_7() = ^CallSideEffect : ~m? -# 33| mu33_8(DerivedClass) = Store[obj3] : &:r33_1, r33_2 -# 29| v29_3(Void) = ReturnVoid : -# 29| v29_4(Void) = AliasedUse : ~m? -# 29| v29_5(Void) = ExitFunction : - -crement.cs: -# 3| CrementOpsTest.Main() -# 3| Block 0 -# 3| v3_1(Void) = EnterFunction : -# 3| mu3_2() = AliasedDefinition : -# 5| r5_1(glval) = VariableAddress[x] : -# 5| r5_2(Int32) = Constant[10] : -# 5| mu5_3(Int32) = Store[x] : &:r5_1, r5_2 -# 6| r6_1(glval) = VariableAddress[a] : -# 6| r6_2(glval) = VariableAddress[x] : -# 6| r6_3(Int32) = Load[x] : &:r6_2, ~m? -# 6| r6_4(Int32) = Constant[1] : -# 6| r6_5(Int32) = Add : r6_3, r6_4 -# 6| mu6_6(Int32) = Store[x] : &:r6_2, r6_5 -# 6| mu6_7(Int32) = Store[a] : &:r6_1, r6_3 -# 7| r7_1(glval) = VariableAddress[b] : -# 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load[x] : &:r7_2, ~m? -# 7| r7_4(Int32) = Constant[1] : -# 7| r7_5(Int32) = Sub : r7_3, r7_4 -# 7| mu7_6(Int32) = Store[x] : &:r7_2, r7_5 -# 7| mu7_7(Int32) = Store[b] : &:r7_1, r7_5 -# 8| r8_1(glval) = VariableAddress[c] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| r8_3(Int32) = Load[x] : &:r8_2, ~m? -# 8| r8_4(Int32) = Constant[1] : -# 8| r8_5(Int32) = Add : r8_3, r8_4 -# 8| mu8_6(Int32) = Store[x] : &:r8_2, r8_5 -# 8| mu8_7(Int32) = Store[c] : &:r8_1, r8_5 -# 9| r9_1(glval) = VariableAddress[x] : -# 9| r9_2(Int32) = Load[x] : &:r9_1, ~m? -# 9| r9_3(Int32) = Constant[1] : -# 9| r9_4(Int32) = Sub : r9_2, r9_3 -# 9| mu9_5(Int32) = Store[x] : &:r9_1, r9_4 -# 9| r9_6(glval) = VariableAddress[x] : -# 9| mu9_7(Int32) = Store[x] : &:r9_6, r9_2 -# 3| v3_3(Void) = ReturnVoid : -# 3| v3_4(Void) = AliasedUse : ~m? -# 3| v3_5(Void) = ExitFunction : - -delegates.cs: -# 6| Delegates.returns(int) -# 6| Block 0 -# 6| v6_1(Void) = EnterFunction : -# 6| mu6_2() = AliasedDefinition : -# 6| r6_3(glval) = VariableAddress[ret] : -# 6| mu6_4(Int32) = InitializeParameter[ret] : &:r6_3 -# 8| r8_1(glval) = VariableAddress[#return] : -# 8| r8_2(glval) = VariableAddress[ret] : -# 8| r8_3(Int32) = Load[ret] : &:r8_2, ~m? -# 8| mu8_4(Int32) = Store[#return] : &:r8_1, r8_3 -# 6| r6_5(glval) = VariableAddress[#return] : -# 6| v6_6(Void) = ReturnValue : &:r6_5, ~m? -# 6| v6_7(Void) = AliasedUse : ~m? -# 6| v6_8(Void) = ExitFunction : - -# 11| Delegates.Main() -# 11| Block 0 -# 11| v11_1(Void) = EnterFunction : -# 11| mu11_2() = AliasedDefinition : -# 12| r12_1(glval) = VariableAddress[del1] : -# 12| r12_2(Del) = NewObj : -# 12| r12_3() = FunctionAddress[Del] : -# 12| r12_4(glval) = FunctionAddress[returns] : -# 12| v12_5(Void) = Call[Del] : func:r12_3, this:r12_2, 0:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~m? -# 12| mu12_7(Del) = Store[del1] : &:r12_1, r12_2 -# 13| r13_1(glval) = VariableAddress[del1] : -# 13| r13_2(Del) = Load[del1] : &:r13_1, ~m? -# 13| r13_3() = FunctionAddress[Invoke] : -# 13| r13_4(Int32) = Constant[5] : -# 13| v13_5(Void) = Call[Invoke] : func:r13_3, this:r13_2, 0:r13_4 -# 13| mu13_6() = ^CallSideEffect : ~m? -# 11| v11_3(Void) = ReturnVoid : -# 11| v11_4(Void) = AliasedUse : ~m? -# 11| v11_5(Void) = ExitFunction : - -events.cs: -# 8| Events.Events() -# 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 8| r8_3(glval) = InitializeThis : -# 8| r8_4(glval) = Convert[Events : Object] : r8_3 -# 8| r8_5() = FunctionAddress[Object] : -# 8| v8_6(Void) = Call[Object] : func:r8_5, this:r8_4 -# 8| mu8_7() = ^CallSideEffect : ~m? -# 10| r10_1(MyDel) = NewObj : -# 10| r10_2() = FunctionAddress[MyDel] : -# 10| r10_3(glval) = FunctionAddress[Fun] : -# 10| v10_4(Void) = Call[MyDel] : func:r10_2, this:r10_1, 0:r10_3 -# 10| mu10_5() = ^CallSideEffect : ~m? -# 10| r10_6(Events) = CopyValue : r8_3 -# 10| r10_7(glval) = FieldAddress[Inst] : r10_6 -# 10| mu10_8(MyDel) = Store[?] : &:r10_7, r10_1 -# 8| v8_8(Void) = ReturnVoid : -# 8| v8_9(Void) = AliasedUse : ~m? -# 8| v8_10(Void) = ExitFunction : - -# 13| Events.AddEvent() -# 13| Block 0 -# 13| v13_1(Void) = EnterFunction : -# 13| mu13_2() = AliasedDefinition : -# 13| r13_3(glval) = InitializeThis : -# 15| r15_1(Events) = CopyValue : r13_3 -# 15| r15_2() = FunctionAddress[add_MyEvent] : -# 15| r15_3(Events) = CopyValue : r13_3 -# 15| r15_4(glval) = FieldAddress[Inst] : r15_3 -# 15| r15_5(MyDel) = Load[?] : &:r15_4, ~m? -# 15| v15_6(Void) = Call[add_MyEvent] : func:r15_2, this:r15_1, 0:r15_5 -# 15| mu15_7() = ^CallSideEffect : ~m? -# 13| v13_4(Void) = ReturnVoid : -# 13| v13_5(Void) = AliasedUse : ~m? -# 13| v13_6(Void) = ExitFunction : - -# 18| Events.RemoveEvent() -# 18| Block 0 -# 18| v18_1(Void) = EnterFunction : -# 18| mu18_2() = AliasedDefinition : -# 18| r18_3(glval) = InitializeThis : -# 20| r20_1(Events) = CopyValue : r18_3 -# 20| r20_2() = FunctionAddress[remove_MyEvent] : -# 20| r20_3(Events) = CopyValue : r18_3 -# 20| r20_4(glval) = FieldAddress[Inst] : r20_3 -# 20| r20_5(MyDel) = Load[?] : &:r20_4, ~m? -# 20| v20_6(Void) = Call[remove_MyEvent] : func:r20_2, this:r20_1, 0:r20_5 -# 20| mu20_7() = ^CallSideEffect : ~m? -# 18| v18_4(Void) = ReturnVoid : -# 18| v18_5(Void) = AliasedUse : ~m? -# 18| v18_6(Void) = ExitFunction : - -# 23| Events.Fun(string) -# 23| Block 0 -# 23| v23_1(Void) = EnterFunction : -# 23| mu23_2() = AliasedDefinition : -# 23| r23_3(glval) = InitializeThis : -# 23| r23_4(glval) = VariableAddress[str] : -# 23| mu23_5(String) = InitializeParameter[str] : &:r23_4 -# 25| r25_1(glval) = VariableAddress[#return] : -# 25| r25_2(glval) = VariableAddress[str] : -# 25| r25_3(String) = Load[str] : &:r25_2, ~m? -# 25| mu25_4(String) = Store[#return] : &:r25_1, r25_3 -# 23| r23_6(glval) = VariableAddress[#return] : -# 23| v23_7(Void) = ReturnValue : &:r23_6, ~m? -# 23| v23_8(Void) = AliasedUse : ~m? -# 23| v23_9(Void) = ExitFunction : - -# 28| Events.Main(String[]) -# 28| Block 0 -# 28| v28_1(Void) = EnterFunction : -# 28| mu28_2() = AliasedDefinition : -# 28| r28_3(glval) = VariableAddress[args] : -# 28| mu28_4(String[]) = InitializeParameter[args] : &:r28_3 -# 30| r30_1(glval) = VariableAddress[obj] : -# 30| r30_2(Events) = NewObj : -# 30| r30_3() = FunctionAddress[Events] : -# 30| v30_4(Void) = Call[Events] : func:r30_3, this:r30_2 -# 30| mu30_5() = ^CallSideEffect : ~m? -# 30| mu30_6(Events) = Store[obj] : &:r30_1, r30_2 -# 31| r31_1(glval) = VariableAddress[obj] : -# 31| r31_2(Events) = Load[obj] : &:r31_1, ~m? -# 31| r31_3() = FunctionAddress[AddEvent] : -# 31| v31_4(Void) = Call[AddEvent] : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~m? -# 32| r32_1(glval) = VariableAddress[result] : -# 32| r32_2(glval) = VariableAddress[obj] : -# 32| r32_3(Events) = Load[obj] : &:r32_2, ~m? -# 32| r32_4() = FunctionAddress[Invoke] : -# 32| r32_5(String) = StringConstant["string"] : -# 32| v32_6(Void) = Call[Invoke] : func:r32_4, this:r32_3, 0:r32_5 -# 32| mu32_7() = ^CallSideEffect : ~m? -# 32| mu32_8(String) = Store[result] : &:r32_1, v32_6 -# 33| r33_1(glval) = VariableAddress[obj] : -# 33| r33_2(Events) = Load[obj] : &:r33_1, ~m? -# 33| r33_3() = FunctionAddress[RemoveEvent] : -# 33| v33_4(Void) = Call[RemoveEvent] : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~m? -# 28| v28_5(Void) = ReturnVoid : -# 28| v28_6(Void) = AliasedUse : ~m? -# 28| v28_7(Void) = ExitFunction : - -foreach.cs: -# 4| ForEach.Main() -# 4| Block 0 -# 4| v4_1(Void) = EnterFunction : -# 4| mu4_2() = AliasedDefinition : -# 5| r5_1(glval) = VariableAddress[a_array] : -# 5| mu5_2(Int32[]) = Uninitialized[a_array] : &:r5_1 -# 5| r5_3(Int32) = Constant[0] : -# 5| r5_4(glval) = PointerAdd[4] : r5_1, r5_3 -# 5| r5_5(Int32) = Constant[1] : -# 5| mu5_6(Int32) = Store[?] : &:r5_4, r5_5 -# 5| r5_7(Int32) = Constant[1] : -# 5| r5_8(glval) = PointerAdd[4] : r5_1, r5_7 -# 5| r5_9(Int32) = Constant[2] : -# 5| mu5_10(Int32) = Store[?] : &:r5_8, r5_9 -# 5| r5_11(Int32) = Constant[2] : -# 5| r5_12(glval) = PointerAdd[4] : r5_1, r5_11 -# 5| r5_13(Int32) = Constant[3] : -# 5| mu5_14(Int32) = Store[?] : &:r5_12, r5_13 -# 5| r5_15(Int32) = Constant[3] : -# 5| r5_16(glval) = PointerAdd[4] : r5_1, r5_15 -# 5| r5_17(Int32) = Constant[4] : -# 5| mu5_18(Int32) = Store[?] : &:r5_16, r5_17 -# 5| r5_19(Int32) = Constant[4] : -# 5| r5_20(glval) = PointerAdd[4] : r5_1, r5_19 -# 5| r5_21(Int32) = Constant[5] : -# 5| mu5_22(Int32) = Store[?] : &:r5_20, r5_21 -# 5| r5_23(Int32) = Constant[5] : -# 5| r5_24(glval) = PointerAdd[4] : r5_1, r5_23 -# 5| r5_25(Int32) = Constant[6] : -# 5| mu5_26(Int32) = Store[?] : &:r5_24, r5_25 -# 5| r5_27(Int32) = Constant[6] : -# 5| r5_28(glval) = PointerAdd[4] : r5_1, r5_27 -# 5| r5_29(Int32) = Constant[7] : -# 5| mu5_30(Int32) = Store[?] : &:r5_28, r5_29 -# 7| r7_1(glval) = VariableAddress[#temp7:9] : -# 7| r7_2(glval) = VariableAddress[a_array] : -# 7| r7_3(Int32[]) = Load[a_array] : &:r7_2, ~m? -# 7| r7_4() = FunctionAddress[GetEnumerator] : -# 7| r7_5(IEnumerator) = Call[GetEnumerator] : func:r7_4, this:r7_3 -# 7| mu7_6() = ^CallSideEffect : ~m? -# 7| mu7_7(IEnumerator) = Store[#temp7:9] : &:r7_1, r7_5 -#-----| Goto -> Block 1 - -# 7| Block 1 -# 7| r7_8(glval) = VariableAddress[#temp7:9] : -# 7| r7_9(IEnumerator) = Load[#temp7:9] : &:r7_8, ~m? -# 7| r7_10() = FunctionAddress[MoveNext] : -# 7| r7_11(Boolean) = Call[MoveNext] : func:r7_10, this:r7_9 -# 7| mu7_12() = ^CallSideEffect : ~m? -# 7| v7_13(Void) = ConditionalBranch : r7_11 -#-----| False -> Block 3 -#-----| True -> Block 2 - -# 7| Block 2 -# 7| r7_14(glval) = VariableAddress[items] : -# 7| r7_15(glval) = VariableAddress[#temp7:9] : -# 7| r7_16(IEnumerator) = Load[#temp7:9] : &:r7_15, ~m? -# 7| r7_17() = FunctionAddress[get_Current] : -# 7| r7_18(Int32) = Call[get_Current] : func:r7_17, this:r7_16 -# 7| mu7_19() = ^CallSideEffect : ~m? -# 7| mu7_20(Int32) = Store[items] : &:r7_14, r7_18 -# 9| r9_1(glval) = VariableAddress[x] : -# 9| r9_2(glval) = VariableAddress[items] : -# 9| r9_3(Int32) = Load[items] : &:r9_2, ~m? -# 9| mu9_4(Int32) = Store[x] : &:r9_1, r9_3 -#-----| Goto (back edge) -> Block 1 - -# 7| Block 3 -# 7| r7_21(glval) = VariableAddress[#temp7:9] : -# 7| r7_22(IEnumerator) = Load[#temp7:9] : &:r7_21, ~m? -# 7| r7_23() = FunctionAddress[Dispose] : -# 7| v7_24(Void) = Call[Dispose] : func:r7_23, this:r7_22 -# 7| mu7_25() = ^CallSideEffect : ~m? -# 4| v4_3(Void) = ReturnVoid : -# 4| v4_4(Void) = AliasedUse : ~m? -# 4| v4_5(Void) = ExitFunction : - -func_with_param_call.cs: -# 5| test_call_with_param.f(int, int) -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| r5_3(glval) = VariableAddress[x] : -# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 -# 5| r5_5(glval) = VariableAddress[y] : -# 5| mu5_6(Int32) = InitializeParameter[y] : &:r5_5 -# 7| r7_1(glval) = VariableAddress[#return] : -# 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load[x] : &:r7_2, ~m? -# 7| r7_4(glval) = VariableAddress[y] : -# 7| r7_5(Int32) = Load[y] : &:r7_4, ~m? -# 7| r7_6(Int32) = Add : r7_3, r7_5 -# 7| mu7_7(Int32) = Store[#return] : &:r7_1, r7_6 -# 5| r5_7(glval) = VariableAddress[#return] : -# 5| v5_8(Void) = ReturnValue : &:r5_7, ~m? -# 5| v5_9(Void) = AliasedUse : ~m? -# 5| v5_10(Void) = ExitFunction : - -# 10| test_call_with_param.g() -# 10| Block 0 -# 10| v10_1(Void) = EnterFunction : -# 10| mu10_2() = AliasedDefinition : -# 12| r12_1(glval) = VariableAddress[#return] : -# 12| r12_2() = FunctionAddress[f] : -# 12| r12_3(Int32) = Constant[2] : -# 12| r12_4(Int32) = Constant[3] : -# 12| r12_5(Int32) = Call[f] : func:r12_2, 0:r12_3, 1:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~m? -# 12| mu12_7(Int32) = Store[#return] : &:r12_1, r12_5 -# 10| r10_3(glval) = VariableAddress[#return] : -# 10| v10_4(Void) = ReturnValue : &:r10_3, ~m? -# 10| v10_5(Void) = AliasedUse : ~m? -# 10| v10_6(Void) = ExitFunction : - -indexers.cs: -# 8| Indexers+MyClass.get_Item(int) -# 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 8| r8_3(glval) = InitializeThis : -# 6| r6_1(glval) = VariableAddress[index] : -# 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 -# 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(MyClass) = CopyValue : r8_3 -# 10| r10_3(glval) = FieldAddress[address] : r10_2 -# 10| r10_4(String[]) = ElementsAddress : r10_3 -# 10| r10_5(glval) = VariableAddress[index] : -# 10| r10_6(Int32) = Load[index] : &:r10_5, ~m? -# 10| r10_7(String[]) = PointerAdd[8] : r10_4, r10_6 -# 10| r10_8(String) = Load[?] : &:r10_7, ~m? -# 10| mu10_9(String) = Store[#return] : &:r10_1, r10_8 -# 8| r8_4(glval) = VariableAddress[#return] : -# 8| v8_5(Void) = ReturnValue : &:r8_4, ~m? -# 8| v8_6(Void) = AliasedUse : ~m? -# 8| v8_7(Void) = ExitFunction : - -# 12| Indexers+MyClass.set_Item(int, string) -# 12| Block 0 -# 12| v12_1(Void) = EnterFunction : -# 12| mu12_2() = AliasedDefinition : -# 12| r12_3(glval) = InitializeThis : -# 6| r6_1(glval) = VariableAddress[index] : -# 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 -# 12| r12_4(glval) = VariableAddress[value] : -# 12| mu12_5(String) = InitializeParameter[value] : &:r12_4 -# 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(String) = Load[value] : &:r14_1, ~m? -# 14| r14_3(MyClass) = CopyValue : r12_3 -# 14| r14_4(glval) = FieldAddress[address] : r14_3 -# 14| r14_5(String[]) = ElementsAddress : r14_4 -# 14| r14_6(glval) = VariableAddress[index] : -# 14| r14_7(Int32) = Load[index] : &:r14_6, ~m? -# 14| r14_8(String[]) = PointerAdd[8] : r14_5, r14_7 -# 14| mu14_9(String) = Store[?] : &:r14_8, r14_2 -# 12| v12_6(Void) = ReturnVoid : -# 12| v12_7(Void) = AliasedUse : ~m? -# 12| v12_8(Void) = ExitFunction : - -# 19| Indexers.Main() -# 19| Block 0 -# 19| v19_1(Void) = EnterFunction : -# 19| mu19_2() = AliasedDefinition : -# 21| r21_1(glval) = VariableAddress[inst] : -# 21| r21_2(MyClass) = NewObj : -# 21| r21_3() = FunctionAddress[MyClass] : -# 21| v21_4(Void) = Call[MyClass] : func:r21_3, this:r21_2 -# 21| mu21_5() = ^CallSideEffect : ~m? -# 21| mu21_6(MyClass) = Store[inst] : &:r21_1, r21_2 -# 22| r22_1(glval) = VariableAddress[inst] : -# 22| r22_2(MyClass) = Load[inst] : &:r22_1, ~m? -# 22| r22_3() = FunctionAddress[set_Item] : -# 22| r22_4(Int32) = Constant[0] : -# 22| r22_5(String) = StringConstant["str1"] : -# 22| v22_6(Void) = Call[set_Item] : func:r22_3, this:r22_2, 0:r22_4, 1:r22_5 -# 22| mu22_7() = ^CallSideEffect : ~m? -# 23| r23_1(glval) = VariableAddress[inst] : -# 23| r23_2(MyClass) = Load[inst] : &:r23_1, ~m? -# 23| r23_3() = FunctionAddress[set_Item] : -# 23| r23_4(Int32) = Constant[1] : -# 23| r23_5(String) = StringConstant["str1"] : -# 23| v23_6(Void) = Call[set_Item] : func:r23_3, this:r23_2, 0:r23_4, 1:r23_5 -# 23| mu23_7() = ^CallSideEffect : ~m? -# 24| r24_1(glval) = VariableAddress[inst] : -# 24| r24_2(MyClass) = Load[inst] : &:r24_1, ~m? -# 24| r24_3() = FunctionAddress[set_Item] : -# 24| r24_4(Int32) = Constant[1] : -# 24| r24_5(glval) = VariableAddress[inst] : -# 24| r24_6(MyClass) = Load[inst] : &:r24_5, ~m? -# 24| r24_7() = FunctionAddress[get_Item] : -# 24| r24_8(Int32) = Constant[0] : -# 24| r24_9(String) = Call[get_Item] : func:r24_7, this:r24_6, 0:r24_8 -# 24| mu24_10() = ^CallSideEffect : ~m? -# 24| v24_11(Void) = Call[set_Item] : func:r24_3, this:r24_2, 0:r24_4, 1:r24_9 -# 24| mu24_12() = ^CallSideEffect : ~m? -# 19| v19_3(Void) = ReturnVoid : -# 19| v19_4(Void) = AliasedUse : ~m? -# 19| v19_5(Void) = ExitFunction : - -inheritance_polymorphism.cs: -# 3| A.function() -# 3| Block 0 -# 3| v3_1(Void) = EnterFunction : -# 3| mu3_2() = AliasedDefinition : -# 3| r3_3(glval) = InitializeThis : -# 5| r5_1(glval) = VariableAddress[#return] : -# 5| r5_2(Int32) = Constant[0] : -# 5| mu5_3(Int32) = Store[#return] : &:r5_1, r5_2 -# 3| r3_4(glval) = VariableAddress[#return] : -# 3| v3_5(Void) = ReturnValue : &:r3_4, ~m? -# 3| v3_6(Void) = AliasedUse : ~m? -# 3| v3_7(Void) = ExitFunction : - -# 15| C.function() -# 15| Block 0 -# 15| v15_1(Void) = EnterFunction : -# 15| mu15_2() = AliasedDefinition : -# 15| r15_3(glval) = InitializeThis : -# 17| r17_1(glval) = VariableAddress[#return] : -# 17| r17_2(Int32) = Constant[1] : -# 17| mu17_3(Int32) = Store[#return] : &:r17_1, r17_2 -# 15| r15_4(glval) = VariableAddress[#return] : -# 15| v15_5(Void) = ReturnValue : &:r15_4, ~m? -# 15| v15_6(Void) = AliasedUse : ~m? -# 15| v15_7(Void) = ExitFunction : - -# 23| Program.Main() -# 23| Block 0 -# 23| v23_1(Void) = EnterFunction : -# 23| mu23_2() = AliasedDefinition : -# 25| r25_1(glval) = VariableAddress[objB] : -# 25| r25_2(B) = NewObj : -# 25| r25_3() = FunctionAddress[B] : -# 25| v25_4(Void) = Call[B] : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~m? -# 25| mu25_6(B) = Store[objB] : &:r25_1, r25_2 -# 26| r26_1(glval) = VariableAddress[objB] : -# 26| r26_2(B) = Load[objB] : &:r26_1, ~m? -# 26| r26_3() = FunctionAddress[function] : -# 26| r26_4(Int32) = Call[function] : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~m? -# 29| r29_1(glval) = VariableAddress[objA] : -# 29| mu29_2(A) = Uninitialized[objA] : &:r29_1 -# 30| r30_1(glval) = VariableAddress[objB] : -# 30| r30_2(B) = Load[objB] : &:r30_1, ~m? -# 30| r30_3(A) = Convert : r30_2 -# 30| r30_4(glval) = VariableAddress[objA] : -# 30| mu30_5(A) = Store[objA] : &:r30_4, r30_3 -# 31| r31_1(glval) = VariableAddress[objA] : -# 31| r31_2(A) = Load[objA] : &:r31_1, ~m? -# 31| r31_3() = FunctionAddress[function] : -# 31| r31_4(Int32) = Call[function] : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~m? -# 33| r33_1(glval) = VariableAddress[objC] : -# 33| r33_2(C) = NewObj : -# 33| r33_3() = FunctionAddress[C] : -# 33| v33_4(Void) = Call[C] : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~m? -# 33| r33_6(A) = Convert : r33_2 -# 33| mu33_7(A) = Store[objC] : &:r33_1, r33_2 -# 34| r34_1(glval) = VariableAddress[objC] : -# 34| r34_2(A) = Load[objC] : &:r34_1, ~m? -# 34| r34_3() = FunctionAddress[function] : -# 34| r34_4(Int32) = Call[function] : func:r34_3, this:r34_2 -# 34| mu34_5() = ^CallSideEffect : ~m? -# 23| v23_3(Void) = ReturnVoid : -# 23| v23_4(Void) = AliasedUse : ~m? -# 23| v23_5(Void) = ExitFunction : - -inoutref.cs: -# 11| InOutRef.set(ref MyClass, MyClass) -# 11| Block 0 -# 11| v11_1(Void) = EnterFunction : -# 11| mu11_2() = AliasedDefinition : -# 11| r11_3(glval) = VariableAddress[o1] : -# 11| mu11_4(MyClass) = InitializeParameter[o1] : &:r11_3 -# 11| r11_5(glval) = VariableAddress[o2] : -# 11| mu11_6(MyClass) = InitializeParameter[o2] : &:r11_5 -# 13| r13_1(glval) = VariableAddress[o2] : -# 13| r13_2(MyClass) = Load[o2] : &:r13_1, ~m? -# 13| r13_3(glval) = VariableAddress[o1] : -# 13| r13_4(MyClass) = Load[o1] : &:r13_3, ~m? -# 13| mu13_5(MyClass) = Store[?] : &:r13_4, r13_2 -# 11| v11_7(Void) = ReturnVoid : -# 11| v11_8(Void) = AliasedUse : ~m? -# 11| v11_9(Void) = ExitFunction : - -# 16| InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) -# 16| Block 0 -# 16| v16_1(Void) = EnterFunction : -# 16| mu16_2() = AliasedDefinition : -# 16| r16_3(glval) = VariableAddress[a] : -# 16| mu16_4(Int32) = InitializeParameter[a] : &:r16_3 -# 16| r16_5(glval) = VariableAddress[b] : -# 16| mu16_6(MyStruct) = InitializeParameter[b] : &:r16_5 -# 16| r16_7(glval) = VariableAddress[b1] : -# 16| mu16_8(MyStruct) = InitializeParameter[b1] : &:r16_7 -# 16| r16_9(glval) = VariableAddress[c] : -# 16| mu16_10(MyClass) = InitializeParameter[c] : &:r16_9 -# 16| r16_11(glval) = VariableAddress[c1] : -# 16| mu16_12(MyClass) = InitializeParameter[c1] : &:r16_11 -# 18| r18_1(Int32) = Constant[0] : -# 18| r18_2(glval) = VariableAddress[b] : -# 18| r18_3(MyStruct) = Load[b] : &:r18_2, ~m? -# 18| r18_4(glval) = FieldAddress[fld] : r18_3 -# 18| mu18_5(Int32) = Store[?] : &:r18_4, r18_1 -# 19| r19_1(glval) = VariableAddress[b] : -# 19| r19_2(MyStruct) = Load[b] : &:r19_1, ~m? -# 19| r19_3(glval) = FieldAddress[fld] : r19_2 -# 19| r19_4(Int32) = Load[?] : &:r19_3, ~m? -# 19| r19_5(glval) = VariableAddress[a] : -# 19| r19_6(Int32) = Load[a] : &:r19_5, ~m? -# 19| mu19_7(Int32) = Store[?] : &:r19_6, r19_4 -# 21| r21_1(Int32) = Constant[10] : -# 21| r21_2(glval) = VariableAddress[c] : -# 21| r21_3(MyClass) = Load[c] : &:r21_2, ~m? -# 21| r21_4(MyClass) = Load[?] : &:r21_3, ~m? -# 21| r21_5(glval) = FieldAddress[fld] : r21_4 -# 21| mu21_6(Int32) = Store[?] : &:r21_5, r21_1 -# 22| r22_1(glval) = VariableAddress[c] : -# 22| r22_2(MyClass) = Load[c] : &:r22_1, ~m? -# 22| r22_3(MyClass) = Load[?] : &:r22_2, ~m? -# 22| r22_4(glval) = FieldAddress[fld] : r22_3 -# 22| r22_5(Int32) = Load[?] : &:r22_4, ~m? -# 22| r22_6(glval) = VariableAddress[a] : -# 22| r22_7(Int32) = Load[a] : &:r22_6, ~m? -# 22| mu22_8(Int32) = Store[?] : &:r22_7, r22_5 -# 24| r24_1(glval) = VariableAddress[b1] : -# 24| r24_2(MyStruct) = Load[b1] : &:r24_1, ~m? -# 24| r24_3(MyStruct) = Load[?] : &:r24_2, ~m? -# 24| r24_4(glval) = VariableAddress[b] : -# 24| r24_5(MyStruct) = Load[b] : &:r24_4, ~m? -# 24| mu24_6(MyStruct) = Store[?] : &:r24_5, r24_3 -# 26| r26_1() = FunctionAddress[set] : -# 26| r26_2(glval) = VariableAddress[c] : -# 26| r26_3(MyClass) = Load[c] : &:r26_2, ~m? -# 26| r26_4(glval) = VariableAddress[c1] : -# 26| r26_5(MyClass) = Load[c1] : &:r26_4, ~m? -# 26| r26_6(MyClass) = Load[?] : &:r26_5, ~m? -# 26| v26_7(Void) = Call[set] : func:r26_1, 0:r26_3, 1:r26_6 -# 26| mu26_8() = ^CallSideEffect : ~m? -# 16| v16_13(Void) = ReturnVoid : -# 16| v16_14(Void) = AliasedUse : ~m? -# 16| v16_15(Void) = ExitFunction : - -# 29| InOutRef.Main() -# 29| Block 0 -# 29| v29_1(Void) = EnterFunction : -# 29| mu29_2() = AliasedDefinition : -# 31| r31_1(glval) = VariableAddress[a] : -# 31| r31_2(Int32) = Constant[0] : -# 31| mu31_3(Int32) = Store[a] : &:r31_1, r31_2 -# 32| r32_1(glval) = VariableAddress[b] : -# 32| r32_2(MyStruct) = NewObj : -# 32| r32_3() = FunctionAddress[MyStruct] : -# 32| v32_4(Void) = Call[MyStruct] : func:r32_3, this:r32_2 -# 32| mu32_5() = ^CallSideEffect : ~m? -# 32| r32_6(MyStruct) = Load[?] : &:r32_2, ~m? -# 32| mu32_7(MyStruct) = Store[b] : &:r32_1, r32_6 -# 33| r33_1(glval) = VariableAddress[c] : -# 33| r33_2(MyClass) = NewObj : -# 33| r33_3() = FunctionAddress[MyClass] : -# 33| v33_4(Void) = Call[MyClass] : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~m? -# 33| mu33_6(MyClass) = Store[c] : &:r33_1, r33_2 -# 34| r34_1() = FunctionAddress[F] : -# 34| r34_2(glval) = VariableAddress[a] : -# 34| r34_3(glval) = VariableAddress[b] : -# 34| r34_4(glval) = VariableAddress[b] : -# 34| r34_5(glval) = VariableAddress[c] : -# 34| r34_6(glval) = VariableAddress[c] : -# 34| v34_7(Void) = Call[F] : func:r34_1, 0:r34_2, 1:r34_3, 2:r34_4, 3:r34_5, 4:r34_6 -# 34| mu34_8() = ^CallSideEffect : ~m? -# 36| r36_1(glval) = VariableAddress[x] : -# 36| r36_2(glval) = VariableAddress[b] : -# 36| r36_3(glval) = FieldAddress[fld] : r36_2 -# 36| r36_4(Int32) = Load[?] : &:r36_3, ~m? -# 36| mu36_5(Int32) = Store[x] : &:r36_1, r36_4 -# 29| v29_3(Void) = ReturnVoid : -# 29| v29_4(Void) = AliasedUse : ~m? -# 29| v29_5(Void) = ExitFunction : - -isexpr.cs: -# 8| IsExpr.Main() -# 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 10| r10_1(glval) = VariableAddress[obj] : -# 10| r10_2(null) = Constant[null] : -# 10| r10_3(Is_A) = Convert : r10_2 -# 10| mu10_4(Is_A) = Store[obj] : &:r10_1, r10_2 -# 12| r12_1(glval) = VariableAddress[o] : -# 12| r12_2(glval) = VariableAddress[obj] : -# 12| r12_3(Is_A) = Load[obj] : &:r12_2, ~m? -# 12| r12_4(Object) = Convert : r12_3 -# 12| mu12_5(Object) = Store[o] : &:r12_1, r12_3 -# 13| r13_1(glval) = VariableAddress[o] : -# 13| r13_2(Object) = Load[o] : &:r13_1, ~m? -# 13| r13_3(Is_A) = CheckedConvertOrNull : r13_2 -# 13| r13_4(Is_A) = Constant[0] : -# 13| r13_5(glval) = VariableAddress[tmp] : -# 13| mu13_6(Is_A) = Uninitialized[tmp] : &:r13_5 -# 13| r13_7(Boolean) = CompareNE : r13_3, r13_4 -# 13| v13_8(Void) = ConditionalBranch : r13_7 -#-----| False -> Block 2 -#-----| True -> Block 3 - -# 8| Block 1 -# 8| v8_3(Void) = ReturnVoid : -# 8| v8_4(Void) = AliasedUse : ~m? -# 8| v8_5(Void) = ExitFunction : - -# 13| Block 2 -# 13| v13_9(Void) = ConditionalBranch : r13_7 -#-----| False -> Block 5 -#-----| True -> Block 4 - -# 13| Block 3 -# 13| mu13_10(Is_A) = Store[tmp] : &:r13_5, r13_3 -#-----| Goto -> Block 2 - -# 15| Block 4 -# 15| r15_1(glval) = VariableAddress[res] : -# 15| r15_2(glval) = VariableAddress[tmp] : -# 15| r15_3(Is_A) = Load[tmp] : &:r15_2, ~m? -# 15| r15_4(glval) = FieldAddress[x] : r15_3 -# 15| r15_5(Int32) = Load[?] : &:r15_4, ~m? -# 15| mu15_6(Int32) = Store[res] : &:r15_1, r15_5 -#-----| Goto -> Block 5 - -# 17| Block 5 -# 17| r17_1(glval) = VariableAddress[o] : -# 17| r17_2(Object) = Load[o] : &:r17_1, ~m? -# 17| r17_3(Is_A) = CheckedConvertOrNull : r17_2 -# 17| r17_4(Is_A) = Constant[0] : -# 17| r17_5(Boolean) = CompareNE : r17_3, r17_4 -# 17| v17_6(Void) = ConditionalBranch : r17_5 -#-----| False -> Block 1 -#-----| True -> Block 6 - -# 18| Block 6 -# 18| v18_1(Void) = NoOp : -#-----| Goto -> Block 1 - -jumps.cs: -# 5| Jumps.Main() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[i] : -# 7| r7_2(Int32) = Constant[1] : -# 7| mu7_3(Int32) = Store[i] : &:r7_1, r7_2 -#-----| Goto -> Block 2 - -# 7| Block 1 -# 7| r7_4(glval) = VariableAddress[i] : -# 7| r7_5(Int32) = Load[i] : &:r7_4, ~m? -# 7| r7_6(Int32) = Constant[1] : -# 7| r7_7(Int32) = Add : r7_5, r7_6 -# 7| mu7_8(Int32) = Store[i] : &:r7_4, r7_7 -#-----| Goto (back edge) -> Block 2 - -# 7| Block 2 -# 7| r7_9(glval) = VariableAddress[i] : -# 7| r7_10(Int32) = Load[i] : &:r7_9, ~m? -# 7| r7_11(Int32) = Constant[10] : -# 7| r7_12(Boolean) = CompareLE : r7_10, r7_11 -# 7| v7_13(Void) = ConditionalBranch : r7_12 -#-----| False -> Block 8 -#-----| True -> Block 3 - -# 9| Block 3 -# 9| r9_1(glval) = VariableAddress[i] : -# 9| r9_2(Int32) = Load[i] : &:r9_1, ~m? -# 9| r9_3(Int32) = Constant[3] : -# 9| r9_4(Boolean) = CompareEQ : r9_2, r9_3 -# 9| v9_5(Void) = ConditionalBranch : r9_4 -#-----| False -> Block 5 -#-----| True -> Block 4 - -# 10| Block 4 -# 10| v10_1(Void) = NoOp : -#-----| Goto -> Block 1 - -# 11| Block 5 -# 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load[i] : &:r11_1, ~m? -# 11| r11_3(Int32) = Constant[5] : -# 11| r11_4(Boolean) = CompareEQ : r11_2, r11_3 -# 11| v11_5(Void) = ConditionalBranch : r11_4 -#-----| False -> Block 7 -#-----| True -> Block 6 - -# 12| Block 6 -# 12| v12_1(Void) = NoOp : -#-----| Goto -> Block 8 - -# 13| Block 7 -# 13| r13_1() = FunctionAddress[WriteLine] : -# 13| r13_2(String) = StringConstant["BreakAndContinue"] : -# 13| v13_3(Void) = Call[WriteLine] : func:r13_1, 0:r13_2 -# 13| mu13_4() = ^CallSideEffect : ~m? -#-----| Goto -> Block 1 - -# 16| Block 8 -# 16| r16_1(glval) = VariableAddress[i] : -# 16| r16_2(Int32) = Constant[0] : -# 16| mu16_3(Int32) = Store[i] : &:r16_1, r16_2 -#-----| Goto -> Block 9 - -# 16| Block 9 -# 16| r16_4(glval) = VariableAddress[i] : -# 16| r16_5(Int32) = Load[i] : &:r16_4, ~m? -# 16| r16_6(Int32) = Constant[10] : -# 16| r16_7(Boolean) = CompareLT : r16_5, r16_6 -# 16| v16_8(Void) = ConditionalBranch : r16_7 -#-----| False -> Block 11 -#-----| True -> Block 10 - -# 18| Block 10 -# 18| r18_1(glval) = VariableAddress[i] : -# 18| r18_2(Int32) = Load[i] : &:r18_1, ~m? -# 18| r18_3(Int32) = Constant[1] : -# 18| r18_4(Int32) = Add : r18_2, r18_3 -# 18| mu18_5(Int32) = Store[i] : &:r18_1, r18_4 -# 19| v19_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 9 - -# 22| Block 11 -# 22| r22_1(glval) = VariableAddress[a] : -# 22| r22_2(Int32) = Constant[0] : -# 22| mu22_3(Int32) = Store[a] : &:r22_1, r22_2 -#-----| Goto -> Block 12 - -# 23| Block 12 -# 23| r23_1(Boolean) = Constant[true] : -# 23| v23_2(Void) = ConditionalBranch : r23_1 -#-----| False -> Block 17 -#-----| True -> Block 13 - -# 25| Block 13 -# 25| r25_1(glval) = VariableAddress[a] : -# 25| r25_2(Int32) = Load[a] : &:r25_1, ~m? -# 25| r25_3(Int32) = Constant[1] : -# 25| r25_4(Int32) = Add : r25_2, r25_3 -# 25| mu25_5(Int32) = Store[a] : &:r25_1, r25_4 -# 26| r26_1(glval) = VariableAddress[a] : -# 26| r26_2(Int32) = Load[a] : &:r26_1, ~m? -# 26| r26_3(Int32) = Constant[5] : -# 26| r26_4(Boolean) = CompareEQ : r26_2, r26_3 -# 26| v26_5(Void) = ConditionalBranch : r26_4 -#-----| False -> Block 15 -#-----| True -> Block 14 - -# 27| Block 14 -# 27| v27_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 12 - -# 28| Block 15 -# 28| r28_1(glval) = VariableAddress[a] : -# 28| r28_2(Int32) = Load[a] : &:r28_1, ~m? -# 28| r28_3(Int32) = Constant[10] : -# 28| r28_4(Boolean) = CompareEQ : r28_2, r28_3 -# 28| v28_5(Void) = ConditionalBranch : r28_4 -#-----| False (back edge) -> Block 12 -#-----| True -> Block 16 - -# 29| Block 16 -# 29| v29_1(Void) = NoOp : -#-----| Goto -> Block 17 - -# 32| Block 17 -# 32| r32_1(glval) = VariableAddress[i] : -# 32| r32_2(Int32) = Constant[1] : -# 32| mu32_3(Int32) = Store[i] : &:r32_1, r32_2 -#-----| Goto -> Block 19 - -# 32| Block 18 -# 32| r32_4(glval) = VariableAddress[i] : -# 32| r32_5(Int32) = Load[i] : &:r32_4, ~m? -# 32| r32_6(Int32) = Constant[1] : -# 32| r32_7(Int32) = Add : r32_5, r32_6 -# 32| mu32_8(Int32) = Store[i] : &:r32_4, r32_7 -#-----| Goto (back edge) -> Block 19 - -# 32| Block 19 -# 32| r32_9(glval) = VariableAddress[i] : -# 32| r32_10(Int32) = Load[i] : &:r32_9, ~m? -# 32| r32_11(Int32) = Constant[10] : -# 32| r32_12(Boolean) = CompareLE : r32_10, r32_11 -# 32| v32_13(Void) = ConditionalBranch : r32_12 -#-----| False -> Block 22 -#-----| True -> Block 20 - -# 34| Block 20 -# 34| r34_1(glval) = VariableAddress[i] : -# 34| r34_2(Int32) = Load[i] : &:r34_1, ~m? -# 34| r34_3(Int32) = Constant[5] : -# 34| r34_4(Boolean) = CompareEQ : r34_2, r34_3 -# 34| v34_5(Void) = ConditionalBranch : r34_4 -#-----| False -> Block 18 -#-----| True -> Block 21 - -# 35| Block 21 -# 35| v35_1(Void) = NoOp : -#-----| Goto -> Block 22 - -# 37| Block 22 -# 37| v37_1(Void) = NoOp : -# 38| r38_1() = FunctionAddress[WriteLine] : -# 38| r38_2(String) = StringConstant["Done"] : -# 38| v38_3(Void) = Call[WriteLine] : func:r38_1, 0:r38_2 -# 38| mu38_4() = ^CallSideEffect : ~m? -# 5| v5_3(Void) = ReturnVoid : -# 5| v5_4(Void) = AliasedUse : ~m? -# 5| v5_5(Void) = ExitFunction : - -lock.cs: -# 5| LockTest.A() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[object] : -# 7| r7_2(Object) = NewObj : -# 7| r7_3() = FunctionAddress[Object] : -# 7| v7_4(Void) = Call[Object] : func:r7_3, this:r7_2 -# 7| mu7_5() = ^CallSideEffect : ~m? -# 7| mu7_6(Object) = Store[object] : &:r7_1, r7_2 -# 8| r8_1(glval) = VariableAddress[#temp8:9] : -# 8| r8_2(glval) = VariableAddress[object] : -# 8| r8_3(Object) = Load[object] : &:r8_2, ~m? -# 8| mu8_4(Object) = Store[#temp8:9] : &:r8_1, r8_3 -# 8| r8_5(glval) = VariableAddress[#temp8:9] : -# 8| r8_6(Boolean) = Constant[false] : -# 8| mu8_7(Boolean) = Store[#temp8:9] : &:r8_5, r8_6 -# 8| r8_8() = FunctionAddress[Enter] : -# 8| r8_9(glval) = VariableAddress[#temp8:9] : -# 8| r8_10(Object) = Load[#temp8:9] : &:r8_9, ~m? -# 8| r8_11(glval) = VariableAddress[#temp8:9] : -# 8| v8_12(Void) = Call[Enter] : func:r8_8, 0:r8_10, 1:r8_11 -# 8| mu8_13() = ^CallSideEffect : ~m? -# 10| r10_1() = FunctionAddress[WriteLine] : -# 10| r10_2(glval) = VariableAddress[object] : -# 10| r10_3(Object) = Load[object] : &:r10_2, ~m? -# 10| r10_4() = FunctionAddress[ToString] : -# 10| r10_5(String) = Call[ToString] : func:r10_4, this:r10_3 -# 10| mu10_6() = ^CallSideEffect : ~m? -# 10| v10_7(Void) = Call[WriteLine] : func:r10_1, 0:r10_5 -# 10| mu10_8() = ^CallSideEffect : ~m? -# 8| r8_14(glval) = VariableAddress[#temp8:9] : -# 8| r8_15(Boolean) = Load[#temp8:9] : &:r8_14, ~m? -# 8| v8_16(Void) = ConditionalBranch : r8_15 -#-----| False -> Block 1 -#-----| True -> Block 2 - -# 5| Block 1 -# 5| v5_3(Void) = ReturnVoid : -# 5| v5_4(Void) = AliasedUse : ~m? -# 5| v5_5(Void) = ExitFunction : - -# 8| Block 2 -# 8| r8_17() = FunctionAddress[Exit] : -# 8| r8_18(glval) = VariableAddress[#temp8:9] : -# 8| r8_19(Object) = Load[#temp8:9] : &:r8_18, ~m? -# 8| v8_20(Void) = Call[Exit] : func:r8_17, 0:r8_19 -# 8| mu8_21() = ^CallSideEffect : ~m? -#-----| Goto -> Block 1 - -obj_creation.cs: -# 7| ObjCreation+MyClass.MyClass() -# 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| r7_3(glval) = InitializeThis : -# 7| r7_4(glval) = Convert[MyClass : Object] : r7_3 -# 7| r7_5() = FunctionAddress[Object] : -# 7| v7_6(Void) = Call[Object] : func:r7_5, this:r7_4 -# 7| mu7_7() = ^CallSideEffect : ~m? -# 8| v8_1(Void) = NoOp : -# 7| v7_8(Void) = ReturnVoid : -# 7| v7_9(Void) = AliasedUse : ~m? -# 7| v7_10(Void) = ExitFunction : - -# 11| ObjCreation+MyClass.MyClass(int) -# 11| Block 0 -# 11| v11_1(Void) = EnterFunction : -# 11| mu11_2() = AliasedDefinition : -# 11| r11_3(glval) = InitializeThis : -# 11| r11_4(glval) = VariableAddress[_x] : -# 11| mu11_5(Int32) = InitializeParameter[_x] : &:r11_4 -# 11| r11_6(glval) = Convert[MyClass : Object] : r11_3 -# 11| r11_7() = FunctionAddress[Object] : -# 11| v11_8(Void) = Call[Object] : func:r11_7, this:r11_6 -# 11| mu11_9() = ^CallSideEffect : ~m? -# 13| r13_1(glval) = VariableAddress[_x] : -# 13| r13_2(Int32) = Load[_x] : &:r13_1, ~m? -# 13| r13_3(MyClass) = CopyValue : r11_3 -# 13| r13_4(glval) = FieldAddress[x] : r13_3 -# 13| mu13_5(Int32) = Store[?] : &:r13_4, r13_2 -# 11| v11_10(Void) = ReturnVoid : -# 11| v11_11(Void) = AliasedUse : ~m? -# 11| v11_12(Void) = ExitFunction : - -# 17| ObjCreation.SomeFun(MyClass) -# 17| Block 0 -# 17| v17_1(Void) = EnterFunction : -# 17| mu17_2() = AliasedDefinition : -# 17| r17_3(glval) = VariableAddress[x] : -# 17| mu17_4(MyClass) = InitializeParameter[x] : &:r17_3 -# 18| v18_1(Void) = NoOp : -# 17| v17_5(Void) = ReturnVoid : -# 17| v17_6(Void) = AliasedUse : ~m? -# 17| v17_7(Void) = ExitFunction : - -# 21| ObjCreation.Main() -# 21| Block 0 -# 21| v21_1(Void) = EnterFunction : -# 21| mu21_2() = AliasedDefinition : -# 23| r23_1(glval) = VariableAddress[obj] : -# 23| r23_2(MyClass) = NewObj : -# 23| r23_3() = FunctionAddress[MyClass] : -# 23| r23_4(Int32) = Constant[100] : -# 23| v23_5(Void) = Call[MyClass] : func:r23_3, this:r23_2, 0:r23_4 -# 23| mu23_6() = ^CallSideEffect : ~m? -# 23| mu23_7(MyClass) = Store[obj] : &:r23_1, r23_2 -# 24| r24_1(glval) = VariableAddress[obj_initlist] : -# 24| r24_2(MyClass) = NewObj : -# 24| r24_3() = FunctionAddress[MyClass] : -# 24| v24_4(Void) = Call[MyClass] : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~m? -# 24| r24_6(Int32) = Constant[101] : -# 24| r24_7(glval) = FieldAddress[x] : r24_2 -# 24| mu24_8(Int32) = Store[?] : &:r24_7, r24_6 -# 24| mu24_9(MyClass) = Store[obj_initlist] : &:r24_1, r24_2 -# 25| r25_1(glval) = VariableAddress[a] : -# 25| r25_2(glval) = VariableAddress[obj] : -# 25| r25_3(MyClass) = Load[obj] : &:r25_2, ~m? -# 25| r25_4(glval) = FieldAddress[x] : r25_3 -# 25| r25_5(Int32) = Load[?] : &:r25_4, ~m? -# 25| mu25_6(Int32) = Store[a] : &:r25_1, r25_5 -# 27| r27_1() = FunctionAddress[SomeFun] : -# 27| r27_2(MyClass) = NewObj : -# 27| r27_3() = FunctionAddress[MyClass] : -# 27| r27_4(Int32) = Constant[100] : -# 27| v27_5(Void) = Call[MyClass] : func:r27_3, this:r27_2, 0:r27_4 -# 27| mu27_6() = ^CallSideEffect : ~m? -# 27| v27_7(Void) = Call[SomeFun] : func:r27_1, 0:r27_2 -# 27| mu27_8() = ^CallSideEffect : ~m? -# 21| v21_3(Void) = ReturnVoid : -# 21| v21_4(Void) = AliasedUse : ~m? -# 21| v21_5(Void) = ExitFunction : - -pointers.cs: -# 3| Pointers.addone(Int32[]) -# 3| Block 0 -# 3| v3_1(Void) = EnterFunction : -# 3| mu3_2() = AliasedDefinition : -# 3| r3_3(glval) = VariableAddress[arr] : -# 3| mu3_4(Int32[]) = InitializeParameter[arr] : &:r3_3 -# 5| r5_1(glval) = VariableAddress[length] : -# 5| r5_2(glval) = VariableAddress[arr] : -# 5| r5_3(Int32[]) = Load[arr] : &:r5_2, ~m? -# 5| r5_4() = FunctionAddress[get_Length] : -# 5| r5_5(Int32) = Call[get_Length] : func:r5_4, this:r5_3 -# 5| mu5_6() = ^CallSideEffect : ~m? -# 5| mu5_7(Int32) = Store[length] : &:r5_1, r5_5 -# 6| r6_1(glval) = VariableAddress[b] : -# 6| r6_2(glval) = VariableAddress[arr] : -# 6| r6_3(Int32[]) = Load[arr] : &:r6_2, ~m? -# 6| r6_4(Int32*) = CheckedConvertOrThrow : r6_3 -# 6| mu6_5(Int32*) = Store[b] : &:r6_1, r6_4 -# 8| r8_1(glval) = VariableAddress[p] : -# 8| r8_2(glval) = VariableAddress[b] : -# 8| r8_3(Int32*) = Load[b] : &:r8_2, ~m? -# 8| mu8_4(Int32*) = Store[p] : &:r8_1, r8_3 -# 9| r9_1(glval) = VariableAddress[i] : -# 9| r9_2(Int32) = Constant[0] : -# 9| mu9_3(Int32) = Store[i] : &:r9_1, r9_2 -#-----| Goto -> Block 2 - -# 3| Block 1 -# 3| v3_5(Void) = ReturnVoid : -# 3| v3_6(Void) = AliasedUse : ~m? -# 3| v3_7(Void) = ExitFunction : - -# 9| Block 2 -# 9| r9_4(glval) = VariableAddress[i] : -# 9| r9_5(Int32) = Load[i] : &:r9_4, ~m? -# 9| r9_6(glval) = VariableAddress[length] : -# 9| r9_7(Int32) = Load[length] : &:r9_6, ~m? -# 9| r9_8(Boolean) = CompareLT : r9_5, r9_7 -# 9| v9_9(Void) = ConditionalBranch : r9_8 -#-----| False -> Block 1 -#-----| True -> Block 3 - -# 10| Block 3 -# 10| r10_1(Int32) = Constant[1] : -# 10| r10_2(glval) = VariableAddress[p] : -# 10| r10_3(Int32*) = Load[p] : &:r10_2, ~m? -# 10| r10_4(Int32) = Constant[1] : -# 10| r10_5(Int32*) = PointerAdd[4] : r10_3, r10_4 -# 10| mu10_6(Int32*) = Store[p] : &:r10_2, r10_5 -# 10| r10_7(Int32) = Load[?] : &:r10_3, ~m? -# 10| r10_8(Int32) = Add : r10_7, r10_1 -# 10| mu10_9(Int32) = Store[?] : &:r10_3, r10_8 -# 9| r9_10(glval) = VariableAddress[i] : -# 9| r9_11(Int32) = Load[i] : &:r9_10, ~m? -# 9| r9_12(Int32) = Constant[1] : -# 9| r9_13(Int32) = Add : r9_11, r9_12 -# 9| mu9_14(Int32) = Store[i] : &:r9_10, r9_13 -#-----| Goto (back edge) -> Block 2 - -# 25| Pointers.Main() -# 25| Block 0 -# 25| v25_1(Void) = EnterFunction : -# 25| mu25_2() = AliasedDefinition : -# 26| r26_1(glval) = VariableAddress[o] : -# 26| r26_2(MyClass) = NewObj : -# 26| r26_3() = FunctionAddress[MyClass] : -# 26| v26_4(Void) = Call[MyClass] : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~m? -# 26| mu26_6(MyClass) = Store[o] : &:r26_1, r26_2 -# 27| r27_1(glval) = VariableAddress[s] : -# 27| r27_2(MyStruct) = NewObj : -# 27| r27_3() = FunctionAddress[MyStruct] : -# 27| v27_4(Void) = Call[MyStruct] : func:r27_3, this:r27_2 -# 27| mu27_5() = ^CallSideEffect : ~m? -# 27| r27_6(MyStruct) = Load[?] : &:r27_2, ~m? -# 27| mu27_7(MyStruct) = Store[s] : &:r27_1, r27_6 -# 30| r30_1(glval) = VariableAddress[p] : -# 30| r30_2(glval) = VariableAddress[o] : -# 30| r30_3(MyClass) = Load[o] : &:r30_2, ~m? -# 30| r30_4(glval) = FieldAddress[fld1] : r30_3 -# 30| mu30_5(Int32*) = Store[p] : &:r30_1, r30_4 -# 30| r30_6(glval) = VariableAddress[q] : -# 30| r30_7(glval) = VariableAddress[o] : -# 30| r30_8(MyClass) = Load[o] : &:r30_7, ~m? -# 30| r30_9(glval) = FieldAddress[fld2] : r30_8 -# 30| mu30_10(Int32*) = Store[q] : &:r30_6, r30_9 -# 32| r32_1(Int32) = Constant[0] : -# 32| r32_2(glval) = VariableAddress[p] : -# 32| r32_3(Int32*) = Load[p] : &:r32_2, ~m? -# 32| mu32_4(Int32) = Store[?] : &:r32_3, r32_1 -# 33| r33_1(Int32) = Constant[0] : -# 33| r33_2(glval) = VariableAddress[q] : -# 33| r33_3(Int32*) = Load[q] : &:r33_2, ~m? -# 33| mu33_4(Int32) = Store[?] : &:r33_3, r33_1 -# 34| r34_1(glval) = VariableAddress[r] : -# 34| r34_2(glval) = VariableAddress[s] : -# 34| mu34_3(MyStruct*) = Store[r] : &:r34_1, r34_2 -# 35| r35_1(Int32) = Constant[0] : -# 35| r35_2(glval) = VariableAddress[r] : -# 35| r35_3(MyStruct*) = Load[r] : &:r35_2, ~m? -# 35| r35_4(MyStruct) = Load[?] : &:r35_3, ~m? -# 35| r35_5(glval) = FieldAddress[fld] : r35_4 -# 35| mu35_6(Int32) = Store[?] : &:r35_5, r35_1 -# 39| r39_1(glval) = VariableAddress[arr] : -# 39| mu39_2(Int32[]) = Uninitialized[arr] : &:r39_1 -# 39| r39_3(Int32) = Constant[0] : -# 39| r39_4(glval) = PointerAdd[4] : r39_1, r39_3 -# 39| r39_5(Int32) = Constant[1] : -# 39| mu39_6(Int32) = Store[?] : &:r39_4, r39_5 -# 39| r39_7(Int32) = Constant[1] : -# 39| r39_8(glval) = PointerAdd[4] : r39_1, r39_7 -# 39| r39_9(Int32) = Constant[2] : -# 39| mu39_10(Int32) = Store[?] : &:r39_8, r39_9 -# 39| r39_11(Int32) = Constant[2] : -# 39| r39_12(glval) = PointerAdd[4] : r39_1, r39_11 -# 39| r39_13(Int32) = Constant[3] : -# 39| mu39_14(Int32) = Store[?] : &:r39_12, r39_13 -# 40| r40_1() = FunctionAddress[addone] : -# 40| r40_2(glval) = VariableAddress[arr] : -# 40| r40_3(Int32[]) = Load[arr] : &:r40_2, ~m? -# 40| v40_4(Void) = Call[addone] : func:r40_1, 0:r40_3 -# 40| mu40_5() = ^CallSideEffect : ~m? -# 25| v25_3(Void) = ReturnVoid : -# 25| v25_4(Void) = AliasedUse : ~m? -# 25| v25_5(Void) = ExitFunction : - -prop.cs: -# 7| PropClass.get_Prop() -# 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| r7_3(glval) = InitializeThis : -# 9| r9_1(glval) = VariableAddress[#return] : -# 9| r9_2(PropClass) = CopyValue : r7_3 -# 9| r9_3() = FunctionAddress[func] : -# 9| r9_4(Int32) = Call[func] : func:r9_3, this:r9_2 -# 9| mu9_5() = ^CallSideEffect : ~m? -# 9| mu9_6(Int32) = Store[#return] : &:r9_1, r9_4 -# 7| r7_4(glval) = VariableAddress[#return] : -# 7| v7_5(Void) = ReturnValue : &:r7_4, ~m? -# 7| v7_6(Void) = AliasedUse : ~m? -# 7| v7_7(Void) = ExitFunction : - -# 12| PropClass.set_Prop(int) -# 12| Block 0 -# 12| v12_1(Void) = EnterFunction : -# 12| mu12_2() = AliasedDefinition : -# 12| r12_3(glval) = InitializeThis : -# 12| r12_4(glval) = VariableAddress[value] : -# 12| mu12_5(Int32) = InitializeParameter[value] : &:r12_4 -# 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(Int32) = Load[value] : &:r14_1, ~m? -# 14| r14_3(glval) = VariableAddress[prop] : -# 14| mu14_4(Int32) = Store[prop] : &:r14_3, r14_2 -# 12| v12_6(Void) = ReturnVoid : -# 12| v12_7(Void) = AliasedUse : ~m? -# 12| v12_8(Void) = ExitFunction : - -# 18| PropClass.func() -# 18| Block 0 -# 18| v18_1(Void) = EnterFunction : -# 18| mu18_2() = AliasedDefinition : -# 18| r18_3(glval) = InitializeThis : -# 20| r20_1(glval) = VariableAddress[#return] : -# 20| r20_2(Int32) = Constant[0] : -# 20| mu20_3(Int32) = Store[#return] : &:r20_1, r20_2 -# 18| r18_4(glval) = VariableAddress[#return] : -# 18| v18_5(Void) = ReturnValue : &:r18_4, ~m? -# 18| v18_6(Void) = AliasedUse : ~m? -# 18| v18_7(Void) = ExitFunction : - -# 26| Prog.Main() -# 26| Block 0 -# 26| v26_1(Void) = EnterFunction : -# 26| mu26_2() = AliasedDefinition : -# 28| r28_1(glval) = VariableAddress[obj] : -# 28| r28_2(PropClass) = NewObj : -# 28| r28_3() = FunctionAddress[PropClass] : -# 28| v28_4(Void) = Call[PropClass] : func:r28_3, this:r28_2 -# 28| mu28_5() = ^CallSideEffect : ~m? -# 28| mu28_6(PropClass) = Store[obj] : &:r28_1, r28_2 -# 29| r29_1(glval) = VariableAddress[obj] : -# 29| r29_2(PropClass) = Load[obj] : &:r29_1, ~m? -# 29| r29_3() = FunctionAddress[set_Prop] : -# 29| r29_4(Int32) = Constant[5] : -# 29| v29_5(Void) = Call[set_Prop] : func:r29_3, this:r29_2, 0:r29_4 -# 29| mu29_6() = ^CallSideEffect : ~m? -# 30| r30_1(glval) = VariableAddress[x] : -# 30| r30_2(glval) = VariableAddress[obj] : -# 30| r30_3(PropClass) = Load[obj] : &:r30_2, ~m? -# 30| r30_4() = FunctionAddress[get_Prop] : -# 30| r30_5(Int32) = Call[get_Prop] : func:r30_4, this:r30_3 -# 30| mu30_6() = ^CallSideEffect : ~m? -# 30| mu30_7(Int32) = Store[x] : &:r30_1, r30_5 -# 26| v26_3(Void) = ReturnVoid : -# 26| v26_4(Void) = AliasedUse : ~m? -# 26| v26_5(Void) = ExitFunction : - -simple_call.cs: -# 5| test_simple_call.f() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[#return] : -# 7| r7_2(Int32) = Constant[0] : -# 7| mu7_3(Int32) = Store[#return] : &:r7_1, r7_2 -# 5| r5_3(glval) = VariableAddress[#return] : -# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? -# 5| v5_5(Void) = AliasedUse : ~m? -# 5| v5_6(Void) = ExitFunction : - -# 10| test_simple_call.g() -# 10| Block 0 -# 10| v10_1(Void) = EnterFunction : -# 10| mu10_2() = AliasedDefinition : -# 10| r10_3(glval) = InitializeThis : -# 12| r12_1(glval) = VariableAddress[#return] : -# 12| r12_2() = FunctionAddress[f] : -# 12| r12_3(Int32) = Call[f] : func:r12_2 -# 12| mu12_4() = ^CallSideEffect : ~m? -# 12| mu12_5(Int32) = Store[#return] : &:r12_1, r12_3 -# 10| r10_4(glval) = VariableAddress[#return] : -# 10| v10_5(Void) = ReturnValue : &:r10_4, ~m? -# 10| v10_6(Void) = AliasedUse : ~m? -# 10| v10_7(Void) = ExitFunction : - -simple_function.cs: -# 5| test_simple_function.f() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[#return] : -# 7| r7_2(Int32) = Constant[0] : -# 7| mu7_3(Int32) = Store[#return] : &:r7_1, r7_2 -# 5| r5_3(glval) = VariableAddress[#return] : -# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? -# 5| v5_5(Void) = AliasedUse : ~m? -# 5| v5_6(Void) = ExitFunction : - -stmts.cs: -# 5| test_stmts.ifStmt(int) -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| r5_3(glval) = VariableAddress[x] : -# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 -# 7| r7_1(glval) = VariableAddress[x] : -# 7| r7_2(Int32) = Load[x] : &:r7_1, ~m? -# 7| r7_3(Int32) = Constant[5] : -# 7| r7_4(Boolean) = CompareEQ : r7_2, r7_3 -# 7| v7_5(Void) = ConditionalBranch : r7_4 -#-----| False -> Block 3 -#-----| True -> Block 2 - -# 5| Block 1 -# 5| r5_5(glval) = VariableAddress[#return] : -# 5| v5_6(Void) = ReturnValue : &:r5_5, ~m? -# 5| v5_7(Void) = AliasedUse : ~m? -# 5| v5_8(Void) = ExitFunction : - -# 8| Block 2 -# 8| r8_1(glval) = VariableAddress[#return] : -# 8| r8_2(Int32) = Constant[0] : -# 8| mu8_3(Int32) = Store[#return] : &:r8_1, r8_2 -#-----| Goto -> Block 1 - -# 10| Block 3 -# 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(Int32) = Constant[1] : -# 10| mu10_3(Int32) = Store[#return] : &:r10_1, r10_2 -#-----| Goto -> Block 1 - -# 13| test_stmts.whileStmt(int) -# 13| Block 0 -# 13| v13_1(Void) = EnterFunction : -# 13| mu13_2() = AliasedDefinition : -# 13| r13_3(glval) = VariableAddress[x] : -# 13| mu13_4(Int32) = InitializeParameter[x] : &:r13_3 -# 15| r15_1(glval) = VariableAddress[i] : -# 15| r15_2(Int32) = Constant[0] : -# 15| mu15_3(Int32) = Store[i] : &:r15_1, r15_2 -#-----| Goto -> Block 2 - -# 13| Block 1 -# 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = AliasedUse : ~m? -# 13| v13_7(Void) = ExitFunction : - -# 16| Block 2 -# 16| r16_1(glval) = VariableAddress[i] : -# 16| r16_2(Int32) = Load[i] : &:r16_1, ~m? -# 16| r16_3(Int32) = Constant[10] : -# 16| r16_4(Boolean) = CompareLT : r16_2, r16_3 -# 16| v16_5(Void) = ConditionalBranch : r16_4 -#-----| False -> Block 1 -#-----| True -> Block 3 - -# 18| Block 3 -# 18| r18_1(glval) = VariableAddress[x] : -# 18| r18_2(Int32) = Load[x] : &:r18_1, ~m? -# 18| r18_3(Int32) = Constant[1] : -# 18| r18_4(Int32) = Add : r18_2, r18_3 -# 18| r18_5(glval) = VariableAddress[x] : -# 18| mu18_6(Int32) = Store[x] : &:r18_5, r18_4 -#-----| Goto (back edge) -> Block 2 - -# 22| test_stmts.switchStmt() -# 22| Block 0 -# 22| v22_1(Void) = EnterFunction : -# 22| mu22_2() = AliasedDefinition : -# 24| r24_1(glval) = VariableAddress[caseSwitch] : -# 24| r24_2(Object) = NewObj : -# 24| r24_3() = FunctionAddress[Object] : -# 24| v24_4(Void) = Call[Object] : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~m? -# 24| mu24_6(Object) = Store[caseSwitch] : &:r24_1, r24_2 -# 25| r25_1(glval) = VariableAddress[select] : -# 25| r25_2(Int32) = Constant[0] : -# 25| mu25_3(Int32) = Store[select] : &:r25_1, r25_2 -# 27| r27_1(glval) = VariableAddress[caseSwitch] : -# 27| r27_2(Object) = Load[caseSwitch] : &:r27_1, ~m? -# 27| v27_3(Void) = Switch : r27_2 -#-----| Case[-1] -> Block 2 -#-----| Case[0] -> Block 3 -#-----| Case[123] -> Block 4 -#-----| Case[true] -> Block 5 -#-----| Default -> Block 6 - -# 22| Block 1 -# 22| r22_3(glval) = VariableAddress[#return] : -# 22| v22_4(Void) = ReturnValue : &:r22_3, ~m? -# 22| v22_5(Void) = AliasedUse : ~m? -# 22| v22_6(Void) = ExitFunction : - -# 29| Block 2 -# 29| v29_1(Void) = NoOp : -# 30| v30_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 5 - -# 31| Block 3 -# 31| v31_1(Void) = NoOp : -# 32| v32_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 4 - -# 33| Block 4 -# 33| v33_1(Void) = NoOp : -# 34| r34_1(Int32) = Constant[100] : -# 34| r34_2(glval) = VariableAddress[select] : -# 34| mu34_3(Int32) = Store[select] : &:r34_2, r34_1 -# 35| v35_1(Void) = NoOp : -# 42| r42_1(glval) = VariableAddress[#return] : -# 42| r42_2(Int32) = Constant[0] : -# 42| mu42_3(Int32) = Store[#return] : &:r42_1, r42_2 -#-----| Goto -> Block 1 - -# 36| Block 5 -# 36| v36_1(Void) = NoOp : -# 37| r37_1(Int32) = Constant[101] : -# 37| r37_2(glval) = VariableAddress[select] : -# 37| mu37_3(Int32) = Store[select] : &:r37_2, r37_1 -# 38| v38_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 6 - -# 39| Block 6 -# 39| v39_1(Void) = NoOp : -# 40| r40_1(glval) = VariableAddress[#return] : -# 40| r40_2(glval) = VariableAddress[select] : -# 40| r40_3(Int32) = Load[select] : &:r40_2, ~m? -# 40| mu40_4(Int32) = Store[#return] : &:r40_1, r40_3 -#-----| Goto -> Block 1 - -# 45| test_stmts.tryCatchFinally() -# 45| Block 0 -# 45| v45_1(Void) = EnterFunction : -# 45| mu45_2() = AliasedDefinition : -# 47| r47_1(glval) = VariableAddress[x] : -# 47| r47_2(Int32) = Constant[5] : -# 47| mu47_3(Int32) = Store[x] : &:r47_1, r47_2 -# 50| r50_1(glval) = VariableAddress[x] : -# 50| r50_2(Int32) = Load[x] : &:r50_1, ~m? -# 50| r50_3(Int32) = Constant[0] : -# 50| r50_4(Boolean) = CompareNE : r50_2, r50_3 -# 50| v50_5(Void) = ConditionalBranch : r50_4 -#-----| False -> Block 4 -#-----| True -> Block 3 - -# 45| Block 1 -# 45| v45_3(Void) = AliasedUse : ~m? -# 45| v45_4(Void) = ExitFunction : - -# 45| Block 2 -# 45| v45_5(Void) = Unwind : -#-----| Goto -> Block 1 - -# 51| Block 3 -# 51| r51_1(glval) = VariableAddress[#throw51:17] : -# 51| r51_2(Exception) = NewObj : -# 51| r51_3() = FunctionAddress[Exception] : -# 51| v51_4(Void) = Call[Exception] : func:r51_3, this:r51_2 -# 51| mu51_5() = ^CallSideEffect : ~m? -# 51| mu51_6(Exception) = Store[#throw51:17] : &:r51_1, r51_2 -# 51| v51_7(Void) = ThrowValue : &:r51_1, ~m? -#-----| Exception -> Block 6 - -# 52| Block 4 -# 52| r52_1(Int32) = Constant[0] : -# 52| r52_2(glval) = VariableAddress[x] : -# 52| mu52_3(Int32) = Store[x] : &:r52_2, r52_1 -#-----| Goto -> Block 5 - -# 64| Block 5 -# 64| r64_1(Int32) = Constant[2] : -# 64| r64_2(glval) = VariableAddress[x] : -# 64| mu64_3(Int32) = Store[x] : &:r64_2, r64_1 -# 45| v45_6(Void) = ReturnVoid : -#-----| Goto -> Block 1 - -# 54| Block 6 -# 54| v54_1(Void) = CatchByType[Exception] : -#-----| Exception -> Block 8 -#-----| Goto -> Block 7 - -# 54| Block 7 -# 54| r54_2(glval) = VariableAddress[ex] : -# 54| mu54_3(Exception) = Uninitialized[ex] : &:r54_2 -# 56| r56_1(Int32) = Constant[1] : -# 56| r56_2(glval) = VariableAddress[x] : -# 56| mu56_3(Int32) = Store[x] : &:r56_2, r56_1 -#-----| Goto -> Block 5 - -# 58| Block 8 -# 58| v58_1(Void) = CatchAny : -# 60| v60_1(Void) = ReThrow : -#-----| Exception -> Block 2 - -# 68| test_stmts.forStmt() -# 68| Block 0 -# 68| v68_1(Void) = EnterFunction : -# 68| mu68_2() = AliasedDefinition : -# 70| r70_1(glval) = VariableAddress[x] : -# 70| r70_2(Int32) = Constant[0] : -# 70| mu70_3(Int32) = Store[x] : &:r70_1, r70_2 -# 71| r71_1(glval) = VariableAddress[i] : -# 71| r71_2(Int32) = Constant[0] : -# 71| mu71_3(Int32) = Store[i] : &:r71_1, r71_2 -# 71| r71_4(glval) = VariableAddress[j] : -# 71| r71_5(Int32) = Constant[10] : -# 71| mu71_6(Int32) = Store[j] : &:r71_4, r71_5 -#-----| Goto -> Block 2 - -# 68| Block 1 -# 68| v68_3(Void) = ReturnVoid : -# 68| v68_4(Void) = AliasedUse : ~m? -# 68| v68_5(Void) = ExitFunction : - -# 71| Block 2 -# 71| r71_7(glval) = VariableAddress[i] : -# 71| r71_8(Int32) = Load[i] : &:r71_7, ~m? -# 71| r71_9(glval) = VariableAddress[j] : -# 71| r71_10(Int32) = Load[j] : &:r71_9, ~m? -# 71| r71_11(Boolean) = CompareLT : r71_8, r71_10 -# 71| v71_12(Void) = ConditionalBranch : r71_11 -#-----| False -> Block 4 -#-----| True -> Block 3 - -# 73| Block 3 -# 73| r73_1(glval) = VariableAddress[x] : -# 73| r73_2(Int32) = Load[x] : &:r73_1, ~m? -# 73| r73_3(Int32) = Constant[1] : -# 73| r73_4(Int32) = Sub : r73_2, r73_3 -# 73| r73_5(glval) = VariableAddress[x] : -# 73| mu73_6(Int32) = Store[x] : &:r73_5, r73_4 -# 71| r71_13(glval) = VariableAddress[i] : -# 71| r71_14(Int32) = Load[i] : &:r71_13, ~m? -# 71| r71_15(Int32) = Constant[1] : -# 71| r71_16(Int32) = Add : r71_14, r71_15 -# 71| mu71_17(Int32) = Store[i] : &:r71_13, r71_16 -# 71| r71_18(glval) = VariableAddress[j] : -# 71| r71_19(Int32) = Load[j] : &:r71_18, ~m? -# 71| r71_20(Int32) = Constant[1] : -# 71| r71_21(Int32) = Sub : r71_19, r71_20 -# 71| mu71_22(Int32) = Store[j] : &:r71_18, r71_21 -#-----| Goto (back edge) -> Block 2 - -# 76| Block 4 -# 76| r76_1(glval) = VariableAddress[a] : -# 76| mu76_2(Int32) = Uninitialized[a] : &:r76_1 -# 76| r76_3(glval) = VariableAddress[b] : -# 76| r76_4(Int32) = Constant[10] : -# 76| mu76_5(Int32) = Store[b] : &:r76_3, r76_4 -# 77| r77_1(Int32) = Constant[0] : -# 77| r77_2(glval) = VariableAddress[a] : -# 77| mu77_3(Int32) = Store[a] : &:r77_2, r77_1 -#-----| Goto -> Block 5 - -# 77| Block 5 -# 77| r77_4(glval) = VariableAddress[a] : -# 77| r77_5(Int32) = Load[a] : &:r77_4, ~m? -# 77| r77_6(glval) = VariableAddress[b] : -# 77| r77_7(Int32) = Load[b] : &:r77_6, ~m? -# 77| r77_8(Boolean) = CompareLT : r77_5, r77_7 -# 77| v77_9(Void) = ConditionalBranch : r77_8 -#-----| False -> Block 7 -#-----| True -> Block 6 - -# 79| Block 6 -# 79| r79_1(glval) = VariableAddress[a] : -# 79| r79_2(Int32) = Load[a] : &:r79_1, ~m? -# 79| r79_3(Int32) = Constant[1] : -# 79| r79_4(Int32) = Add : r79_2, r79_3 -# 79| mu79_5(Int32) = Store[a] : &:r79_1, r79_4 -#-----| Goto (back edge) -> Block 5 - -# 83| Block 7 -# 83| v83_1(Void) = NoOp : -#-----| Goto (back edge) -> Block 7 - -# 88| test_stmts.doWhile() -# 88| Block 0 -# 88| v88_1(Void) = EnterFunction : -# 88| mu88_2() = AliasedDefinition : -# 90| r90_1(glval) = VariableAddress[x] : -# 90| r90_2(Int32) = Constant[0] : -# 90| mu90_3(Int32) = Store[x] : &:r90_1, r90_2 -#-----| Goto -> Block 2 - -# 88| Block 1 -# 88| v88_3(Void) = ReturnVoid : -# 88| v88_4(Void) = AliasedUse : ~m? -# 88| v88_5(Void) = ExitFunction : - -# 93| Block 2 -# 93| r93_1(glval) = VariableAddress[x] : -# 93| r93_2(Int32) = Load[x] : &:r93_1, ~m? -# 93| r93_3(Int32) = Constant[1] : -# 93| r93_4(Int32) = Add : r93_2, r93_3 -# 93| r93_5(glval) = VariableAddress[x] : -# 93| mu93_6(Int32) = Store[x] : &:r93_5, r93_4 -# 95| r95_1(glval) = VariableAddress[x] : -# 95| r95_2(Int32) = Load[x] : &:r95_1, ~m? -# 95| r95_3(Int32) = Constant[10] : -# 95| r95_4(Boolean) = CompareLT : r95_2, r95_3 -# 95| v95_5(Void) = ConditionalBranch : r95_4 -#-----| False -> Block 1 -#-----| True (back edge) -> Block 2 - -# 98| test_stmts.checkedUnchecked() -# 98| Block 0 -# 98| v98_1(Void) = EnterFunction : -# 98| mu98_2() = AliasedDefinition : -# 100| r100_1(glval) = VariableAddress[num] : -# 100| r100_2(Int32) = Constant[2147483647] : -# 100| r100_3(Int32) = Load[?] : &:r100_2, ~m? -# 100| mu100_4(Int32) = Store[num] : &:r100_1, r100_3 -# 103| r103_1(glval) = VariableAddress[num] : -# 103| r103_2(Int32) = Load[num] : &:r103_1, ~m? -# 103| r103_3(Int32) = Constant[1] : -# 103| r103_4(Int32) = Add : r103_2, r103_3 -# 103| r103_5(glval) = VariableAddress[num] : -# 103| mu103_6(Int32) = Store[num] : &:r103_5, r103_4 -# 107| r107_1(glval) = VariableAddress[num] : -# 107| r107_2(Int32) = Load[num] : &:r107_1, ~m? -# 107| r107_3(Int32) = Constant[1] : -# 107| r107_4(Int32) = Add : r107_2, r107_3 -# 107| r107_5(glval) = VariableAddress[num] : -# 107| mu107_6(Int32) = Store[num] : &:r107_5, r107_4 -# 98| v98_3(Void) = ReturnVoid : -# 98| v98_4(Void) = AliasedUse : ~m? -# 98| v98_5(Void) = ExitFunction : - -using.cs: -# 7| UsingStmt+MyDisposable.MyDisposable() -# 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| r7_3(glval) = InitializeThis : -# 7| r7_4(glval) = Convert[MyDisposable : Object] : r7_3 -# 7| r7_5() = FunctionAddress[Object] : -# 7| v7_6(Void) = Call[Object] : func:r7_5, this:r7_4 -# 7| mu7_7() = ^CallSideEffect : ~m? -# 7| v7_8(Void) = NoOp : -# 7| v7_9(Void) = ReturnVoid : -# 7| v7_10(Void) = AliasedUse : ~m? -# 7| v7_11(Void) = ExitFunction : - -# 8| UsingStmt+MyDisposable.DoSomething() -# 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 8| r8_3(glval) = InitializeThis : -# 8| v8_4(Void) = NoOp : -# 8| v8_5(Void) = ReturnVoid : -# 8| v8_6(Void) = AliasedUse : ~m? -# 8| v8_7(Void) = ExitFunction : - -# 9| UsingStmt+MyDisposable.Dispose() -# 9| Block 0 -# 9| v9_1(Void) = EnterFunction : -# 9| mu9_2() = AliasedDefinition : -# 9| r9_3(glval) = InitializeThis : -# 9| v9_4(Void) = NoOp : -# 9| v9_5(Void) = ReturnVoid : -# 9| v9_6(Void) = AliasedUse : ~m? -# 9| v9_7(Void) = ExitFunction : - -# 12| UsingStmt.Main() -# 12| Block 0 -# 12| v12_1(Void) = EnterFunction : -# 12| mu12_2() = AliasedDefinition : -# 14| r14_1(glval) = VariableAddress[o1] : -# 14| r14_2(MyDisposable) = NewObj : -# 14| r14_3() = FunctionAddress[MyDisposable] : -# 14| v14_4(Void) = Call[MyDisposable] : func:r14_3, this:r14_2 -# 14| mu14_5() = ^CallSideEffect : ~m? -# 14| mu14_6(MyDisposable) = Store[o1] : &:r14_1, r14_2 -# 16| r16_1(glval) = VariableAddress[o1] : -# 16| r16_2(MyDisposable) = Load[o1] : &:r16_1, ~m? -# 16| r16_3() = FunctionAddress[DoSomething] : -# 16| v16_4(Void) = Call[DoSomething] : func:r16_3, this:r16_2 -# 16| mu16_5() = ^CallSideEffect : ~m? -# 19| r19_1(glval) = VariableAddress[o2] : -# 19| r19_2(MyDisposable) = NewObj : -# 19| r19_3() = FunctionAddress[MyDisposable] : -# 19| v19_4(Void) = Call[MyDisposable] : func:r19_3, this:r19_2 -# 19| mu19_5() = ^CallSideEffect : ~m? -# 19| mu19_6(MyDisposable) = Store[o2] : &:r19_1, r19_2 -# 22| r22_1(glval) = VariableAddress[o2] : -# 22| r22_2(MyDisposable) = Load[o2] : &:r22_1, ~m? -# 22| r22_3() = FunctionAddress[DoSomething] : -# 22| v22_4(Void) = Call[DoSomething] : func:r22_3, this:r22_2 -# 22| mu22_5() = ^CallSideEffect : ~m? -# 25| r25_1(glval) = VariableAddress[o3] : -# 25| r25_2(MyDisposable) = NewObj : -# 25| r25_3() = FunctionAddress[MyDisposable] : -# 25| v25_4(Void) = Call[MyDisposable] : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~m? -# 25| mu25_6(MyDisposable) = Store[o3] : &:r25_1, r25_2 -# 26| r26_1(glval) = VariableAddress[o3] : -# 26| r26_2(MyDisposable) = Load[o3] : &:r26_1, ~m? -# 26| r26_3() = FunctionAddress[DoSomething] : -# 26| v26_4(Void) = Call[DoSomething] : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~m? -# 12| v12_3(Void) = ReturnVoid : -# 12| v12_4(Void) = AliasedUse : ~m? -# 12| v12_5(Void) = ExitFunction : - -variables.cs: -# 5| test_variables.f() -# 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 7| r7_1(glval) = VariableAddress[x] : -# 7| mu7_2(Int32) = Uninitialized[x] : &:r7_1 -# 7| r7_3(glval) = VariableAddress[y] : -# 7| r7_4(Int32) = Constant[5] : -# 7| mu7_5(Int32) = Store[y] : &:r7_3, r7_4 -# 8| r8_1(Int32) = Constant[4] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| mu8_3(Int32) = Store[x] : &:r8_2, r8_1 -# 9| r9_1(glval) = VariableAddress[y] : -# 9| r9_2(Int32) = Load[y] : &:r9_1, ~m? -# 9| r9_3(glval) = VariableAddress[x] : -# 9| mu9_4(Int32) = Store[x] : &:r9_3, r9_2 -# 10| r10_1(glval) = VariableAddress[z] : -# 10| r10_2(glval) = VariableAddress[y] : -# 10| r10_3(Int32) = Load[y] : &:r10_2, ~m? -# 10| mu10_4(Int32) = Store[z] : &:r10_1, r10_3 -# 5| v5_3(Void) = ReturnVoid : -# 5| v5_4(Void) = AliasedUse : ~m? -# 5| v5_5(Void) = ExitFunction : diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref deleted file mode 100644 index 336afc397f5..00000000000 --- a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected deleted file mode 100644 index 7f3591c786d..00000000000 --- a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected +++ /dev/null @@ -1,35 +0,0 @@ -missingOperand -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -containsLoopOfForwardEdges -missingIRType -multipleIRTypes -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -nonUniqueEnclosingIRFunction -fieldAddressOnNonPointer -| inoutref.cs:18:9:18:13 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | inoutref.cs:16:17:16:17 | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | -| inoutref.cs:19:13:19:17 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | inoutref.cs:16:17:16:17 | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | -| pointers.cs:35:17:35:24 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | pointers.cs:25:17:25:20 | Pointers.Main() | Pointers.Main() | -thisArgumentIsNonPointer -| inoutref.cs:32:22:32:35 | Call: object creation of type MyStruct | Call instruction 'Call: object creation of type MyStruct' has a `this` argument operand that is not an address, in function '$@'. | inoutref.cs:29:17:29:20 | InOutRef.Main() | InOutRef.Main() | -| pointers.cs:27:22:27:35 | Call: object creation of type MyStruct | Call instruction 'Call: object creation of type MyStruct' has a `this` argument operand that is not an address, in function '$@'. | pointers.cs:25:17:25:20 | Pointers.Main() | Pointers.Main() | -nonUniqueIRVariable diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref deleted file mode 100644 index 3059c9b7b77..00000000000 --- a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/simple_call.cs b/csharp/ql/test/experimental/ir/ir/simple_call.cs deleted file mode 100644 index 7505bd8001c..00000000000 --- a/csharp/ql/test/experimental/ir/ir/simple_call.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -public class test_simple_call -{ - public static int f() - { - return 0; - } - - public int g() - { - return f(); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/simple_function.cs b/csharp/ql/test/experimental/ir/ir/simple_function.cs deleted file mode 100644 index 76dade38fb6..00000000000 --- a/csharp/ql/test/experimental/ir/ir/simple_function.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -public class test_simple_function -{ - public static int f() - { - return 0; - } -} diff --git a/csharp/ql/test/experimental/ir/ir/stmts.cs b/csharp/ql/test/experimental/ir/ir/stmts.cs deleted file mode 100644 index db0b523a434..00000000000 --- a/csharp/ql/test/experimental/ir/ir/stmts.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; - -public class test_stmts -{ - public static int ifStmt(int x) - { - if (x == 5) - return 0; - else - return 1; - } - - public static void whileStmt(int x) - { - int i = 0; - while (i < 10) - { - x = x + 1; - } - } - - public static int switchStmt() - { - object caseSwitch = new object(); - int select = 0; - - switch (caseSwitch) - { - case -1: - goto case true; - case 0: - goto case "123"; - case "123": - select = 100; - break; - case true: - select = 101; - goto default; - default: - return select; - } - return 0; - } - - public static void tryCatchFinally() - { - int x = 5; - try - { - if (x != 0) - throw (new System.Exception()); - x = 0; - } - catch(System.Exception ex) - { - x = 1; - } - catch - { - throw; - } - finally - { - x = 2; - } - } - - public static void forStmt() - { - int x = 0; - for (int i = 0, j = 10; i < j; i++, j--) - { - x = x - 1; - } - - int a, b = 10; - for (a = 0; a < b; ) - { - a++; - } - - for( ; ; ) - { - - } - } - - public static void doWhile() - { - int x = 0; - do - { - x = x + 1; - } - while (x < 10); - } - - public static void checkedUnchecked() - { - int num = Int32.MaxValue; - unchecked - { - num = num + 1; - } - checked - { - num = num + 1; - } - } -} diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected deleted file mode 100644 index 7f3591c786d..00000000000 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected +++ /dev/null @@ -1,35 +0,0 @@ -missingOperand -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -memoryOperandDefinitionIsUnmodeled -operandAcrossFunctions -instructionWithoutUniqueBlock -missingCanonicalLanguageType -multipleCanonicalLanguageTypes -containsLoopOfForwardEdges -missingIRType -multipleIRTypes -lostReachability -backEdgeCountMismatch -useNotDominatedByDefinition -switchInstructionWithoutDefaultEdge -notMarkedAsConflated -wronglyMarkedAsConflated -invalidOverlap -nonUniqueEnclosingIRFunction -fieldAddressOnNonPointer -| inoutref.cs:18:9:18:13 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | inoutref.cs:16:17:16:17 | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | -| inoutref.cs:19:13:19:17 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | inoutref.cs:16:17:16:17 | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | InOutRef.F(ref int, ref MyStruct, MyStruct, ref MyClass, MyClass) | -| pointers.cs:35:17:35:24 | FieldAddress: access to field fld | FieldAddress instruction 'FieldAddress: access to field fld' has an object address operand that is not an address, in function '$@'. | pointers.cs:25:17:25:20 | Pointers.Main() | Pointers.Main() | -thisArgumentIsNonPointer -| inoutref.cs:32:22:32:35 | Call: object creation of type MyStruct | Call instruction 'Call: object creation of type MyStruct' has a `this` argument operand that is not an address, in function '$@'. | inoutref.cs:29:17:29:20 | InOutRef.Main() | InOutRef.Main() | -| pointers.cs:27:22:27:35 | Call: object creation of type MyStruct | Call instruction 'Call: object creation of type MyStruct' has a `this` argument operand that is not an address, in function '$@'. | pointers.cs:25:17:25:20 | Pointers.Main() | Pointers.Main() | -nonUniqueIRVariable diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref deleted file mode 100644 index 65c39482529..00000000000 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected deleted file mode 100644 index 21782bd5ef1..00000000000 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected +++ /dev/null @@ -1,3 +0,0 @@ -multipleOperandMemoryLocations -missingVirtualVariableForMemoryLocation -multipleVirtualVariablesForMemoryLocation diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref deleted file mode 100644 index 8d24936ecea..00000000000 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/using.cs b/csharp/ql/test/experimental/ir/ir/using.cs deleted file mode 100644 index f81b2f128f1..00000000000 --- a/csharp/ql/test/experimental/ir/ir/using.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -class UsingStmt -{ - public class MyDisposable : IDisposable - { - public MyDisposable() { } - public void DoSomething() { } - public void Dispose() { } - } - - static void Main() - { - using (var o1 = new MyDisposable()) - { - o1.DoSomething(); - } - - var o2 = new MyDisposable(); - using (o2) - { - o2.DoSomething(); - } - - using var o3 = new MyDisposable(); - o3.DoSomething(); - } -} diff --git a/csharp/ql/test/experimental/ir/ir/variables.cs b/csharp/ql/test/experimental/ir/ir/variables.cs deleted file mode 100644 index 1855f287190..00000000000 --- a/csharp/ql/test/experimental/ir/ir/variables.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -public class test_variables -{ - public static void f() - { - int x, y = 5; - x = 4; - x = y; - int z = y; - } -} diff --git a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected deleted file mode 100644 index 0c16c9ff134..00000000000 --- a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected +++ /dev/null @@ -1,5 +0,0 @@ -| test.cs:21:17:21:21 | Test2 | test.cs:34:41:34:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:56:17:56:21 | Test4 | test.cs:67:41:67:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:71:17:71:21 | Test5 | test.cs:77:22:77:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:81:17:81:21 | Test6 | test.cs:90:41:90:55 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:94:17:94:21 | Test7 | test.cs:104:41:104:50 | access to array element | This array access might be out of bounds, as the index might be equal to the array length + 1 | diff --git a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql deleted file mode 100644 index 38386d47568..00000000000 --- a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql +++ /dev/null @@ -1,50 +0,0 @@ -import csharp -import experimental.ir.IR -import experimental.ir.rangeanalysis.RangeAnalysis -import experimental.ir.rangeanalysis.RangeUtils - -/** - * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. - */ -predicate boundedArrayAccess(ElementAccess aa, int k) { - exists(Instruction index, Instruction usage, Bound b, int delta | - ( - // indexer access - usage.(CallInstruction).getAst() = aa - or - // array access - usage.(PointerAddInstruction).getAst() = aa - ) and - usage.getAnOperand().getDef() = index and - boundedInstruction(index, b, delta, true, _) - | - exists(PropertyAccess pa | - k = delta and - b.getInstruction().getAst() = pa and - pa.getProperty().getName() = "Length" and - pa.(QualifiableExpr).getQualifier().(VariableAccess).getTarget() = - aa.getQualifier().(VariableAccess).getTarget() - ) - or - b instanceof ZeroBound and - k = delta - getArrayDim(aa.getQualifier().(VariableAccess).getTarget()) - ) -} - -/** - * Holds if the index expression is less than or equal to the array length plus `k`, - * but not necessarily less than or equal to the array length plus `k-1`. - */ -predicate bestArrayAccessBound(ElementAccess aa, int k) { - k = min(int k0 | boundedArrayAccess(aa, k0)) -} - -from ElementAccess aa, int k, string msg, string add -where - bestArrayAccessBound(aa, k) and - k >= 0 and - (if k = 0 then add = "" else add = " + " + k) and - msg = - "This array access might be out of bounds, as the index might be equal to the array length" + - add -select aa.getEnclosingCallable(), aa, msg diff --git a/csharp/ql/test/experimental/ir/offbyone/null.cs b/csharp/ql/test/experimental/ir/offbyone/null.cs deleted file mode 100644 index a1d7adf1511..00000000000 --- a/csharp/ql/test/experimental/ir/offbyone/null.cs +++ /dev/null @@ -1,5 +0,0 @@ -class Null { - public static void Main() { - object o = null; - } -} diff --git a/csharp/ql/test/experimental/ir/offbyone/test.cs b/csharp/ql/test/experimental/ir/offbyone/test.cs deleted file mode 100644 index 74bf155420f..00000000000 --- a/csharp/ql/test/experimental/ir/offbyone/test.cs +++ /dev/null @@ -1,107 +0,0 @@ -class ContainerLengthOffByOne -{ - public int[] arr; - public string str; - - public static void Fun(int elem) - { - } - - public void Test1() - { - int len1 = this.arr.Length; - int len2 = len1 + 1; - // OK - for(int i = 0; i < len2 - 1; i++) - { - ContainerLengthOffByOne.Fun(this.arr[i]); - } - } - - public void Test2() - { - int len1 = this.arr.Length; - - int len2; - if (len1 % 2 == 0) - len2 = len1 + 1; - else - len2 = len1; - // Not OK, PHI node where the upper bound - // exceeds the size of the array. - for(int i = 0; i < len2; i++) - { - ContainerLengthOffByOne.Fun(this.arr[i]); - } - } - - public void Test3() - { - int len1 = this.arr.Length; - int len2 = len1 - 1; - - int len3; - if (len2 % 2 == 0) - len3 = len2 + 1; - else - len3 = len2; - // OK, PHI node has bounds that ensure - // we don't get an off by one error. - for(int i = 0; i < len3; i++) - { - ContainerLengthOffByOne.Fun(this.arr[i]); - } - } - - public void Test4() - { - int len1 = this.arr.Length; - - int len2 = len1 + 1; - int len3 = len2 - 1; - int len4 = len3 + 2; - int len5 = len4 - 1; - // Not OK, len5 is off by one. - for(int i = 0; i < len5; i++) - { - ContainerLengthOffByOne.Fun(this.arr[i]); - } - } - - public void Test5() - { - int len = this.str.Length; - // Not OK; test for indexers - for (int i = 0; i <= len; i++) - { - char c = str[i]; - } - } - - public void Test6() - { - int len = this.arr.Length - 2; - int len1 = len + 3; - int len2 = len1 - 1; - // Not OK, off by one - // The test shows that more complex expressions are treated correctly - for (int i = 0; i < len2; i++) - { - ContainerLengthOffByOne.Fun(this.arr[i + 1]); - } - } - - public void Test7() - { - int[] arrInit = { 1, 2, 3 }; - int len = (arrInit.Length * 2 + 2) / 2 * 2; - int len1 = len / 2 - 3 + 4; - // Not OK, len1 == this.arrInit + 1 - // This test shows that array initializer's length - // are used in bounds - for (int i = 0; i < len1; i++) - { - ContainerLengthOffByOne.Fun(arrInit[i]); - } - } -} diff --git a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected deleted file mode 100644 index 329bbd3bff0..00000000000 --- a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected +++ /dev/null @@ -1,18 +0,0 @@ -| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:24:16:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:18:9:18:13 | test.cs:18:9:18:13 | -| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:36:12:36:12 | Store: access to parameter x | test.cs:26:24:26:24 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:36:12:36:12 | Store: access to parameter x | test.cs:26:31:26:31 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cs:28:9:28:13 | test.cs:28:9:28:13 | -| test.cs:45:12:45:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:45:12:45:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cs:43:20:43:24 | test.cs:43:20:43:24 | -| test.cs:49:12:49:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cs:47:20:47:24 | test.cs:47:20:47:24 | -| test.cs:49:12:49:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:49:12:49:12 | Load: access to local variable i | test.cs:43:20:43:20 | Phi: access to local variable i | 0 | true | CompareLT: ... < ... | test.cs:43:20:43:24 | test.cs:43:20:43:24 | -| test.cs:53:12:53:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cs:51:20:51:28 | test.cs:51:20:51:28 | -| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:43:20:43:20 | Phi: access to local variable i | 1 | true | CompareLT: ... < ... | test.cs:51:20:51:28 | test.cs:51:20:51:28 | -| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:47:20:47:20 | Phi: access to local variable i | 0 | false | CompareGT: ... > ... | test.cs:47:20:47:24 | test.cs:47:20:47:24 | -| test.cs:62:13:62:17 | Load: access to parameter begin | test.cs:58:33:58:37 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:74:14:74:14 | Load: access to parameter x | test.cs:68:32:68:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:72:11:72:15 | test.cs:72:11:72:15 | -| test.cs:74:14:74:14 | Load: access to parameter x | test.cs:68:39:68:39 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cs:72:11:72:15 | test.cs:72:11:72:15 | -| test.cs:81:14:81:14 | Load: access to parameter x | test.cs:68:32:68:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:77:9:77:13 | test.cs:77:9:77:13 | diff --git a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql deleted file mode 100644 index ab62db5e5ff..00000000000 --- a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql +++ /dev/null @@ -1,25 +0,0 @@ -import experimental.ir.rangeanalysis.RangeAnalysis -import experimental.ir.IR -import experimental.ir.internal.IRGuards -import experimental.ir.ValueNumbering - -query predicate instructionBounds( - Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc -) { - ( - i.getAUse() instanceof ArgumentOperand - or - exists(ReturnValueInstruction retInstr | retInstr.getReturnValueOperand() = i.getAUse()) - ) and - ( - upper = true and - delta = min(int d | boundedInstruction(i, b, d, upper, reason)) - or - upper = false and - delta = max(int d | boundedInstruction(i, b, d, upper, reason)) - ) and - not valueNumber(b.getInstruction()) = valueNumber(i) and - if reason instanceof CondReason - then reasonLoc = reason.(CondReason).getCond().getLocation() - else reasonLoc instanceof EmptyLocation -} diff --git a/csharp/ql/test/experimental/ir/rangeanalysis/null.cs b/csharp/ql/test/experimental/ir/rangeanalysis/null.cs deleted file mode 100644 index a1d7adf1511..00000000000 --- a/csharp/ql/test/experimental/ir/rangeanalysis/null.cs +++ /dev/null @@ -1,5 +0,0 @@ -class Null { - public static void Main() { - object o = null; - } -} diff --git a/csharp/ql/test/experimental/ir/rangeanalysis/test.cs b/csharp/ql/test/experimental/ir/rangeanalysis/test.cs deleted file mode 100644 index 018d7b76a59..00000000000 --- a/csharp/ql/test/experimental/ir/rangeanalysis/test.cs +++ /dev/null @@ -1,85 +0,0 @@ -class RangeAnalysis { - static void Sink(int val) - { - } - - static unsafe void Sinkp(int* p) - { - } - - static int Source() - { - return 0; - } - - // Guards, inference, critical edges - static int Test1(int x, int y) - { - if (x < y) - { - x = y; - } - return x; - } - - // Bounds mergers at phi nodes - static int Test2(int x, int y) - { - if (x < y) - { - x = y; - } - else - { - x = x - 2; - } - return x; - } - - // for loops - static void Test3(int x) - { - int y = x; - for(int i = 0; i < x; i++) - { - Sink(i); - } - for(int i = y; i > 0; i--) - { - Sink(i); - } - for(int i = 0; i < y + 2; i++) - { - Sink(i); - } - } - - // pointer bounds - unsafe static void Test4(int *begin, int *end) - { - while (begin < end) - { - Sinkp(begin); - begin++; - } - } - - // bound propagation through conditionals - static void Test5(int x, int y, int z) - { - if (y < z) - { - if (x < y) - { - Sink(x); - } - } - if (x < y) - { - if (y < z) - { - Sink(x); // x < z is not inferred here - } - } - } -} From f2e467d8eae03df75e824acc0f21a9a454067de3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 7 Mar 2024 10:02:27 +0100 Subject: [PATCH 2/2] C#: Cleanup identical-files. --- config/identical-files.json | 158 ++++-------------------------------- 1 file changed, 16 insertions(+), 142 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index a24b5a3a618..ce0e3a67f35 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -88,123 +88,46 @@ "IR Instruction": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/experimental/ir/implementation/raw/Operand.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll" - ], - "IR IRType": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/IRType.qll", - "csharp/ql/src/experimental/ir/implementation/IRType.qll" - ], - "IR IRConfiguration": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/IRConfiguration.qll", - "csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll" - ], - "IR UseSoundEscapeAnalysis": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll", - "csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll" - ], - "IR IRFunctionBase": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll", - "csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll" - ], - "IR Operand Tag": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", - "csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll" - ], - "IR TInstruction": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll", - "csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll" - ], - "IR TIRVariable": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll", - "csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll" ], "IR IR": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/experimental/ir/implementation/raw/IR.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll" ], "IR IRConsistency": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll", - "csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll" ], "IR PrintIR": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll" - ], - "IR IntegerConstant": [ - "cpp/ql/lib/semmle/code/cpp/ir/internal/IntegerConstant.qll", - "csharp/ql/src/experimental/ir/internal/IntegerConstant.qll" - ], - "IR IntegerInteval": [ - "cpp/ql/lib/semmle/code/cpp/ir/internal/IntegerInterval.qll", - "csharp/ql/src/experimental/ir/internal/IntegerInterval.qll" - ], - "IR IntegerPartial": [ - "cpp/ql/lib/semmle/code/cpp/ir/internal/IntegerPartial.qll", - "csharp/ql/src/experimental/ir/internal/IntegerPartial.qll" - ], - "IR Overlap": [ - "cpp/ql/lib/semmle/code/cpp/ir/internal/Overlap.qll", - "csharp/ql/src/experimental/ir/internal/Overlap.qll" - ], - "IR EdgeKind": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll", - "csharp/ql/src/experimental/ir/implementation/EdgeKind.qll" - ], - "IR MemoryAccessKind": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll", - "csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll" - ], - "IR TempVariableTag": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/TempVariableTag.qll", - "csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll" - ], - "IR Opcode": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll", - "csharp/ql/src/experimental/ir/implementation/Opcode.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll" ], "IR SSAConsistency": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll" ], "C++ IR InstructionImports": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", @@ -252,8 +175,7 @@ ], "SSA AliasAnalysis": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll" ], "SSA PrintAliasAnalysis": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintAliasAnalysis.qll", @@ -268,44 +190,28 @@ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll" ], - "IR SSA SimpleSSA": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" - ], - "IR AliasConfiguration (unaliased_ssa)": [ - "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" - ], "IR SSA SSAConstruction": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll" ], "IR SSA PrintSSA": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll" ], "IR ValueNumberInternal": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll" ], "C++ IR ValueNumber": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll", - "csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll" ], "C++ IR PrintValueNumbering": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll", - "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll", - "csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" + "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll" ], "C++ IR ConstantAnalysis": [ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll", @@ -333,38 +239,6 @@ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], - "C# IR InstructionImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" - ], - "C# IR IRImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll" - ], - "C# IR IRBlockImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" - ], - "C# IR IRFunctionImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll" - ], - "C# IR IRVariableImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" - ], - "C# IR OperandImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll" - ], - "C# IR PrintIRImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" - ], - "C# IR ValueNumberingImports": [ - "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", - "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" - ], "C# ControlFlowReachability": [ "csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll" @@ -498,4 +372,4 @@ "python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml", "python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml" ] -} \ No newline at end of file +}