Skip to content

Commit 5fcf646

Browse files
committed
this contributed to solving the FP completeness issues in #1723
1 parent 3b7175e commit 5fcf646

6 files changed

Lines changed: 227 additions & 1 deletion

File tree

key.core/src/main/antlr4/KeYLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ DEPENDINGON : '\\dependingOn';
122122
DISJOINTMODULONULL : '\\disjointModuloNull';
123123
DROP_EFFECTLESS_ELEMENTARIES : '\\dropEffectlessElementaries';
124124
DROP_EFFECTLESS_STORES : '\\dropEffectlessStores';
125+
FLOATING_POINT_BALANCED : '\\floatingPointBalanced';
125126
SIMPLIFY_IF_THEN_ELSE_UPDATE : '\\simplifyIfThenElseUpdate';
126127
ENUM_CONST : '\\enumConstant';
127128
FREELABELIN : '\\freeLabelIn';

key.core/src/main/antlr4/KeYParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ varexpId: // weigl, 2021-03-12: This will be later just an arbitrary identifier.
618618
| SAME_OBSERVER
619619
| DROP_EFFECTLESS_ELEMENTARIES
620620
| DROP_EFFECTLESS_STORES
621+
| FLOATING_POINT_BALANCED
621622
| DIFFERENTFIELDS
622623
| SIMPLIFY_IF_THEN_ELSE_UPDATE
623624
| CONTAINS_ASSIGNMENT

key.core/src/main/java/de/uka/ilkd/key/logic/sort/ProgramSVSort.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.LinkedHashMap;
44
import java.util.Map;
55

6+
import de.uka.ilkd.key.java.expression.operator.BinaryOperator;
67
import org.key_project.util.ExtList;
78
import org.key_project.util.collection.DefaultImmutableSet;
89

@@ -231,6 +232,9 @@ public abstract class ProgramSVSort extends AbstractSort {
231232
new SimpleExpressionExceptingTypeSort("SimpleExpressionNonFloatDouble",
232233
new PrimitiveType[] { PrimitiveType.JAVA_FLOAT, PrimitiveType.JAVA_DOUBLE });
233234

235+
public static final ProgramSVSort FLOAT_BINARY_EXP =
236+
new FloatingPointBinaryExprSort("FloatingPointBinaryExpression");
237+
234238
// --------------- Specials that can be get rid of perhaps--------------
235239

236240
public static final ProgramSVSort LOOPINIT = new LoopInitSort();
@@ -1093,6 +1097,39 @@ public boolean canStandFor(ProgramElement check, ExecutionContext ec, Services s
10931097
}
10941098
}
10951099

1100+
/**
1101+
* A schema variable for a binary operation in which at least one floating
1102+
* point type is involved.
1103+
* Needed for numeric promotion with floating point types.
1104+
*
1105+
* @see de.uka.ilkd.key.rule.conditions.FloatingPointBalancedCondition
1106+
*/
1107+
private static final class FloatingPointBinaryExprSort extends ExpressionSort {
1108+
1109+
public FloatingPointBinaryExprSort(String name) {
1110+
super(new Name(name));
1111+
}
1112+
1113+
@Override
1114+
public boolean canStandFor(ProgramElement check, ExecutionContext ec, Services services) {
1115+
if (!(check instanceof BinaryOperator)) {
1116+
return false;
1117+
}
1118+
BinaryOperator bin = (BinaryOperator) check;
1119+
KeYJavaType t1 = getKeYJavaType(bin.getChildAt(0), ec, services);
1120+
KeYJavaType t2 = getKeYJavaType(bin.getChildAt(1), ec, services);
1121+
1122+
Sort floatSort = services.getTypeConverter().getFloatLDT().targetSort();
1123+
Sort doubleSort = services.getTypeConverter().getDoubleLDT().targetSort();
1124+
if (t1.getSort() != floatSort && t1.getSort() != doubleSort &&
1125+
t2.getSort() != floatSort && t2.getSort() != doubleSort) {
1126+
return false;
1127+
}
1128+
1129+
return true;
1130+
}
1131+
}
1132+
10961133
/**
10971134
* This sort represents a type of program schema variables that match on simple expressions,
10981135
* except if they match a special primitive type.

key.core/src/main/java/de/uka/ilkd/key/nparser/varexp/TacletBuilderManipulators.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ public VariableCondition build(Object[] arguments, List<String> parameters,
259259
public static final AbstractConditionBuilder DROP_EFFECTLESS_ELEMENTARIES =
260260
new ConstructorBasedBuilder("dropEffectlessElementaries",
261261
DropEffectlessElementariesCondition.class, USV, SV, SV);
262+
public static final AbstractConditionBuilder FLOATING_POINT_BALANCED =
263+
new ConstructorBasedBuilder("floatingPointBalanced",
264+
FloatingPointBalancedCondition.class, SV, SV);
262265
public static final AbstractConditionBuilder SIMPLIFY_ITE_UPDATE =
263266
new ConstructorBasedBuilder("simplifyIfThenElseUpdate",
264267
SimplifyIfThenElseUpdateCondition.class, FSV, USV, USV, FSV, SV);
@@ -359,7 +362,8 @@ public IsLabeledCondition build(Object[] arguments, List<String> parameters,
359362
CONTAINS_ASSIGNMENT, FIELD_TYPE, STATIC_REFERENCE, DIFFERENT_FIELDS, SAME_OBSERVER,
360363
applyUpdateOnRigid, DROP_EFFECTLESS_ELEMENTARIES, SIMPLIFY_ITE_UPDATE, SUBFORMULAS,
361364
STATIC_FIELD, SUBFORMULA, DROP_EFFECTLESS_STORES, EQUAL_UNIQUE, META_DISJOINT,
362-
IS_OBSERVER, CONSTANT, HAS_SORT, LABEL, NEW_LABEL, HAS_ELEM_SORT, IS_IN_STRICTFP);
365+
IS_OBSERVER, CONSTANT, HAS_SORT, LABEL, NEW_LABEL, HAS_ELEM_SORT, IS_IN_STRICTFP,
366+
FLOATING_POINT_BALANCED);
363367
register(STORE_TERM_IN, STORE_STMT_IN, HAS_INVARIANT, GET_INVARIANT, GET_FREE_INVARIANT,
364368
GET_VARIANT, IS_LABELED);
365369
loadWithServiceLoader();
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package de.uka.ilkd.key.rule.conditions;
2+
3+
import de.uka.ilkd.key.java.Expression;
4+
import de.uka.ilkd.key.java.JavaProgramElement;
5+
import de.uka.ilkd.key.java.ProgramElement;
6+
import de.uka.ilkd.key.java.Services;
7+
import de.uka.ilkd.key.java.abstraction.KeYJavaType;
8+
import de.uka.ilkd.key.java.expression.operator.BinaryOperator;
9+
import de.uka.ilkd.key.java.expression.operator.TypeCast;
10+
import de.uka.ilkd.key.java.reference.TypeRef;
11+
import de.uka.ilkd.key.java.visitor.ProgramElementReplacer;
12+
import de.uka.ilkd.key.logic.Term;
13+
import de.uka.ilkd.key.logic.TermServices;
14+
import de.uka.ilkd.key.logic.op.ElementaryUpdate;
15+
import de.uka.ilkd.key.logic.op.LocationVariable;
16+
import de.uka.ilkd.key.logic.op.SVSubstitute;
17+
import de.uka.ilkd.key.logic.op.SchemaVariable;
18+
import de.uka.ilkd.key.logic.op.UpdateApplication;
19+
import de.uka.ilkd.key.logic.op.UpdateJunctor;
20+
import de.uka.ilkd.key.logic.sort.Sort;
21+
import de.uka.ilkd.key.proof.TermProgramVariableCollector;
22+
import de.uka.ilkd.key.rule.MatchConditions;
23+
import de.uka.ilkd.key.rule.VariableCondition;
24+
import de.uka.ilkd.key.rule.inst.SVInstantiations;
25+
26+
import javax.annotation.Nullable;
27+
import java.util.Set;
28+
29+
30+
/**
31+
* This variable condition adds required numeric promotions to Java operations
32+
* with floating point arguments.
33+
*
34+
* For example: In the expression 1.0f + 1.0d, the first argument will be implicitly
35+
* cast to double like (double)1.0f + 1.0d.
36+
*
37+
* If such an unbalanced expression occurs in the program, according casts are
38+
* introduced by this varcond.
39+
*
40+
* The varcond is used like \floatingPointBalanced(#unbalanced, #balanced)
41+
* where the first argument is the one from the find expression of the rule
42+
* and the second one is the one that will be changed.
43+
*
44+
* @author Mattias Ulbrich
45+
* @see de.uka.ilkd.key.logic.sort.ProgramSVSort.FloatingPointBinaryExprSort
46+
*/
47+
public final class FloatingPointBalancedCondition implements VariableCondition {
48+
/**
49+
* The first SV: It holds the unbalanced input expression
50+
*/
51+
private final SchemaVariable unbalanced;
52+
/**
53+
* The 2nd SV: It holds the balanced computed expression
54+
*/
55+
private final SchemaVariable balanced;
56+
57+
public FloatingPointBalancedCondition(SchemaVariable unbalanced, SchemaVariable balanced) {
58+
this.unbalanced = unbalanced;
59+
this.balanced = balanced;
60+
}
61+
62+
@Override
63+
public MatchConditions check(SchemaVariable var, SVSubstitute instCandidate, MatchConditions mc,
64+
Services services) {
65+
66+
SVInstantiations svInst = mc.getInstantiations();
67+
BinaryOperator inInst = (BinaryOperator) svInst.getInstantiation(unbalanced);
68+
JavaProgramElement outInst = (JavaProgramElement) svInst.getInstantiation(balanced);
69+
if (inInst == null) {
70+
return mc;
71+
}
72+
73+
BinaryOperator properResultInst = balance(inInst, services);
74+
if (properResultInst == null) {
75+
return null;
76+
} else if (outInst == null) {
77+
svInst = svInst.add(balanced, properResultInst, services);
78+
return mc.setInstantiations(svInst);
79+
} else if (outInst.equals(properResultInst)) {
80+
return mc;
81+
} else {
82+
return null;
83+
}
84+
}
85+
86+
@Override
87+
public String toString() {
88+
return "\\floatingPointBalanced(" + unbalanced + ", " + balanced + ")";
89+
}
90+
91+
private static KeYJavaType getKeYJavaType(ProgramElement pe, Services services) {
92+
return services.getTypeConverter().getKeYJavaType((Expression) pe);
93+
}
94+
95+
/**
96+
* Make sure the result is a binary operation with same types on lhs
97+
* and rhs. do this by adding cast if needed.
98+
*
99+
* If no cast is needed, return null.
100+
*
101+
* @param inInst the binary AST element to balance
102+
* @param services as usual ... to lookup everything
103+
* @return null if already same types. Otherwise a binary operator which
104+
* has an added cast compared to the input
105+
*/
106+
private static @Nullable BinaryOperator balance(BinaryOperator inInst, Services services) {
107+
108+
ProgramElement child0 = inInst.getChildAt(0);
109+
ProgramElement child1 = inInst.getChildAt(1);
110+
111+
KeYJavaType type0 = getKeYJavaType(child0, services);
112+
KeYJavaType type1 = getKeYJavaType(child1, services);
113+
if (type0.getSort() == type1.getSort()) {
114+
// nothing to be done ... same type
115+
return null;
116+
}
117+
118+
Sort doubleSort = services.getTypeConverter().getDoubleLDT().targetSort();
119+
Sort floatSort = services.getTypeConverter().getFloatLDT().targetSort();
120+
if (type0.getSort() == doubleSort) {
121+
return cast(inInst, 1, type0, services);
122+
}
123+
if (type1.getSort() == doubleSort) {
124+
return cast(inInst, 0, type1, services);
125+
}
126+
if (type0.getSort() == floatSort) {
127+
return cast(inInst, 1, type0, services);
128+
}
129+
if (type1.getSort() == floatSort) {
130+
return cast(inInst, 0, type1, services);
131+
}
132+
return null;
133+
}
134+
135+
/**
136+
* Add a cast to a binary operation.
137+
*
138+
* @param inInst the tree to modify
139+
* @param childNo the child to which a cast is to be added
140+
* @param kjt the type to which to cast
141+
* @param services as usual
142+
* @return a binary operation similar to the input, but with one
143+
* cast added to child childNo.
144+
*/
145+
private static BinaryOperator cast(BinaryOperator inInst, int childNo, KeYJavaType kjt,
146+
Services services) {
147+
Expression child = (Expression) inInst.getChildAt(childNo);
148+
TypeCast cast = new TypeCast(child, new TypeRef(kjt));
149+
ProgramElementReplacer per = new ProgramElementReplacer(inInst, services);
150+
ProgramElement result = per.replace(child, cast);
151+
return (BinaryOperator) result;
152+
}
153+
}

key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatAssignment2UpdateRules.key

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,16 @@
427427
\displayname "cast"
428428
};
429429

430+
wideningCastFloatToDouble {
431+
\find(\modality{#normalassign}{..
432+
#loc = (double) #seFloat;
433+
...}\endmodality (post))
434+
\replacewith({#loc := (double)#seFloat}
435+
\modality{#normalassign}{.. ...}\endmodality (post))
436+
\heuristics(executeFloatAssignment)
437+
\displayname "cast"
438+
};
439+
430440
wideningCastIntToFloat {
431441
\find(\modality{#normalassign}{..
432442
#loc = (float) #seCharByteShortInt;
@@ -469,6 +479,16 @@
469479
\displayname "cast"
470480
};
471481

482+
narrowingCastDoubleToFloat {
483+
\find(\modality{#normalassign}{..
484+
#loc = (float) #seDouble;
485+
...}\endmodality (post))
486+
\replacewith({#loc := (float)(#seDouble)}
487+
\modality{#normalassign}{.. ...}\endmodality (post))
488+
\heuristics(executeFloatAssignment)
489+
\displayname "cast"
490+
};
491+
472492
narrowingCastFloatToLong {
473493
\find(\modality{#normalassign}{..
474494
#loc = (long) #seFloat;
@@ -497,4 +517,14 @@
497517
\displayname "cast"
498518
};
499519

520+
unbalanced_float_expression {
521+
\schemaVar \program FloatingPointBinaryExpression #unbalancedFloat;
522+
\schemaVar \program FloatingPointBinaryExpression #balancedFloat;
523+
524+
\find(\modality{#normalassign}{.. #loc = #unbalancedFloat; ...}\endmodality (post))
525+
\varcond(\floatingPointBalanced(#unbalancedFloat, #balancedFloat))
526+
\replacewith(\modality{#normalassign}{.. #loc = #balancedFloat; ...}\endmodality (post))
527+
\heuristics(simplify_prog)
528+
\displayname "cast"
529+
};
500530
}

0 commit comments

Comments
 (0)