|
| 1 | +private import ql |
| 2 | +private import codeql_ql.ast.internal.Predicate |
| 3 | +private import codeql_ql.ast.internal.Type |
| 4 | +private import codeql_ql.ast.internal.Builtins |
| 5 | + |
| 6 | +private newtype TValueNumber = |
| 7 | + TVariableValueNumber(VarDecl var) { variableAccessValueNumber(_, var) } or |
| 8 | + TPredicateValueNumber(PredicateOrBuiltin pred, ValueNumberList args) { |
| 9 | + predicateCallValueNumber(_, pred, args) |
| 10 | + } or |
| 11 | + TLiteralValueNumber(string value, Type t) { literalValueNumber(_, value, t) } or |
| 12 | + TBinaryOpValueNumber(FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand) { |
| 13 | + binaryOperandValueNumber(_, symbol, leftOperand, rightOperand) |
| 14 | + } or |
| 15 | + TUnaryOpValueNumber(FunctionSymbol symbol, ValueNumber operand) { |
| 16 | + unaryOperandValueNumber(_, symbol, operand) |
| 17 | + } or |
| 18 | + TUniqueValueNumber(Expr e) { uniqueValueNumber(e) } |
| 19 | + |
| 20 | +private newtype ValueNumberList = |
| 21 | + MkNil() or |
| 22 | + MkCons(ValueNumber head, ValueNumberList tail) { globalValueNumbers(_, _, head, tail) } |
| 23 | + |
| 24 | +private ValueNumberList globalValueNumbers(Call call, int start) { |
| 25 | + start = call.getNumberOfArguments() and |
| 26 | + result = MkNil() |
| 27 | + or |
| 28 | + exists(ValueNumber head, ValueNumberList tail | |
| 29 | + globalValueNumbers(call, start, head, tail) and |
| 30 | + result = MkCons(head, tail) |
| 31 | + ) |
| 32 | +} |
| 33 | + |
| 34 | +private predicate globalValueNumbers(Call call, int start, ValueNumber head, ValueNumberList tail) { |
| 35 | + head = valueNumber(call.getArgument(start)) and |
| 36 | + tail = globalValueNumbers(call, start + 1) |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * A value number. A value number represents a collection of expressions that compute to the same value |
| 41 | + * at runtime. |
| 42 | + */ |
| 43 | +class ValueNumber extends TValueNumber { |
| 44 | + string toString() { result = "GVN" } |
| 45 | + |
| 46 | + /** Gets an expression that has this value number. */ |
| 47 | + final Expr getAnExpr() { this = valueNumber(result) } |
| 48 | +} |
| 49 | + |
| 50 | +private predicate uniqueValueNumber(Expr e) { not numberable(e) } |
| 51 | + |
| 52 | +private predicate numberable(Expr e) { |
| 53 | + e instanceof VarAccess or |
| 54 | + e instanceof Call or |
| 55 | + e instanceof Literal or |
| 56 | + e instanceof BinOpExpr or |
| 57 | + e instanceof UnaryExpr |
| 58 | +} |
| 59 | + |
| 60 | +private predicate variableAccessValueNumber(VarAccess access, VarDecl var) { |
| 61 | + access.getDeclaration() = var |
| 62 | +} |
| 63 | + |
| 64 | +private predicate predicateCallValueNumber(Call call, PredicateOrBuiltin pred, ValueNumberList args) { |
| 65 | + exists(pred.getReturnType()) and |
| 66 | + call.getTarget() = pred and |
| 67 | + args = globalValueNumbers(call, 0) |
| 68 | +} |
| 69 | + |
| 70 | +private predicate literalValueNumber(Literal lit, string value, Type t) { |
| 71 | + lit.(String).getValue() = value and |
| 72 | + t instanceof StringClass |
| 73 | + or |
| 74 | + lit.(Integer).getValue().toString() = value and |
| 75 | + t instanceof IntClass |
| 76 | + or |
| 77 | + lit.(Float).getValue().toString() = value and |
| 78 | + t instanceof FloatClass |
| 79 | + or |
| 80 | + lit.(Boolean).isFalse() and |
| 81 | + value = "false" and |
| 82 | + t instanceof BooleanClass |
| 83 | + or |
| 84 | + lit.(Boolean).isTrue() and |
| 85 | + value = "true" and |
| 86 | + t instanceof BooleanClass |
| 87 | +} |
| 88 | + |
| 89 | +private predicate binaryOperandValueNumber( |
| 90 | + BinOpExpr e, FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand |
| 91 | +) { |
| 92 | + e.getOperator() = symbol and |
| 93 | + valueNumber(e.getLeftOperand()) = leftOperand and |
| 94 | + valueNumber(e.getRightOperand()) = rightOperand |
| 95 | +} |
| 96 | + |
| 97 | +private predicate unaryOperandValueNumber(UnaryExpr e, FunctionSymbol symbol, ValueNumber operand) { |
| 98 | + e.getOperator() = symbol and |
| 99 | + valueNumber(e.getOperand()) = operand |
| 100 | +} |
| 101 | + |
| 102 | +private TValueNumber nonUniqueValueNumber(Expr e) { |
| 103 | + exists(VarDecl var | |
| 104 | + variableAccessValueNumber(e, var) and |
| 105 | + result = TVariableValueNumber(var) |
| 106 | + ) |
| 107 | + or |
| 108 | + exists(PredicateOrBuiltin pred, ValueNumberList args | |
| 109 | + predicateCallValueNumber(e, pred, args) and |
| 110 | + result = TPredicateValueNumber(pred, args) |
| 111 | + ) |
| 112 | + or |
| 113 | + exists(string value, Type t | |
| 114 | + literalValueNumber(e, value, t) and |
| 115 | + result = TLiteralValueNumber(value, t) |
| 116 | + ) |
| 117 | + or |
| 118 | + exists(FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand | |
| 119 | + binaryOperandValueNumber(e, symbol, leftOperand, rightOperand) and |
| 120 | + result = TBinaryOpValueNumber(symbol, leftOperand, rightOperand) |
| 121 | + ) |
| 122 | + or |
| 123 | + exists(FunctionSymbol symbol, ValueNumber operand | |
| 124 | + unaryOperandValueNumber(e, symbol, operand) and |
| 125 | + result = TUnaryOpValueNumber(symbol, operand) |
| 126 | + ) |
| 127 | +} |
| 128 | + |
| 129 | +/** Gets the value number of an expression `e`. */ |
| 130 | +cached |
| 131 | +TValueNumber valueNumber(Expr e) { |
| 132 | + result = nonUniqueValueNumber(e) |
| 133 | + or |
| 134 | + uniqueValueNumber(e) and |
| 135 | + result = TUniqueValueNumber(e) |
| 136 | +} |
0 commit comments