1 % (c) 2009-2026 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(static_enabling_analysis,[
6 %static_activation_dependent/2,
7 static_cannot_enable/2,
8 vars_ord_intersect/2,
9 static_disables_itself/1,
10 static_disabled_after/2
11 ]).
12
13 :- use_module(probsrc(module_information),[module_info/2]).
14 :- module_info(group,cbc).
15 :- module_info(description,'This module computes static enabling infos for B operations, without using the constraint solver.').
16
17 :- use_module(probsrc(debug), [debug_format/3, debug_println/2]).
18 :- use_module(probsrc(bmachine),[b_top_level_operation/1]).
19 :- use_module(probsrc(b_read_write_info),
20 [b_get_read_write/3, b_get_operation_read_guard_vars/4]).
21
22 % -------------------- BINARY STATIC ANALYSIS -------------------------
23
24 % certain static analyses used by CBC Test case generation
25
26 % check if OpName1 can influence the truth value of the guard of OpName2 by looking at read/write info
27 %static_activation_dependent(OpName1,OpName2) :- static_activation_dependence(OpName1,OpName2,dependent).
28
29 % true when OpName1 cannot enable a previously disabled OpName2
30 static_cannot_enable(OpName1,OpName2) :-
31 static_activation_dependence(OpName1,OpName2,Res),
32 (Res \= dependent
33 -> true % activation_independent or independent
34 ; static_disabled_after(OpName1,OpName2)
35 ).
36
37 :- dynamic static_activation_dependence_cache/3.
38 static_activation_dependence(OpName1,OpName2,Res) :-
39 static_activation_dependence_cache(OpName1,OpName2,Cached),!,
40 Res=Cached.
41 static_activation_dependence(OpName1,OpName2,Res) :-
42 b_top_level_operation(OpName1),
43 b_get_read_write(OpName1,_,Writes1),
44 b_top_level_operation(OpName2),
45 b_get_operation_read_guard_vars(OpName2,true,GuardReads2,Precise),
46 (vars_ord_intersect(Writes1,GuardReads2)
47 -> Cached = dependent % OpName1 could enable or disable OpName2
48 ; %print(indep(OpName1,Writes1,OpName2,GuardReads2)),nl,
49 b_get_read_write(OpName2,Reads2,_Writes2),
50 (vars_ord_intersect(Writes1,Reads2)
51 -> (Precise==precise
52 -> Cached = activation_independent % OpName1 cannot enable or disable OpName2, but can influence effect
53 ; Cached = dependent % Computation of GuardReads2 was not precise (while loops, ... in operation)
54 )
55 ; Cached = independent % but order could still matter; for this we would need to look at Writes2
56 )
57 ),
58 debug_format(19,'Computed static dependence ~w -> ~w : ~w~n',[OpName1,OpName2,Cached]),
59 assertz(static_activation_dependence_cache(OpName1,OpName2,Cached)),
60 Res=Cached.
61
62
63 :- use_module(library(ordsets),[ord_intersect/2]).
64 % a version of ord_intersect(ion) which deals with the '$all' term
65 vars_ord_intersect('$all',_) :- !.
66 vars_ord_intersect(_,'$all') :- !.
67 vars_ord_intersect(A,B) :- ord_intersect(A,B).
68
69
70
71 :- use_module(probsrc(eventhandling),[register_event_listener/3]).
72 :- register_event_listener(specification_initialised,reset_static_enabling_analysis,
73 'Initialise module static_enabling analysis.').
74
75 reset_static_enabling_analysis :-
76 retractall(static_activation_dependence_cache(_,_,_)),
77 retractall(static_disabled_after_cache(_,_,_)).
78
79
80
81 :- use_module(probsrc(bmachine),[b_get_machine_operation_for_animation/4]).
82 :- use_module(probsrc(b_state_model_check), [get_guard_and_precision/3]).
83 :- use_module(probsrc(bsyntaxtree),[get_texpr_expr/2,different_texpr_values/2,select_member_in_conjunction/3]).
84
85 % check statically if an operation must disable itself
86 % the check is aimed to detect typical control flow encoding using booleans or program counters
87 % example op = SELECT op_done=FALSE THEN .... op_done := TRUE END
88 static_disables_itself(OpName) :- static_disabled_after(OpName,OpName,true).
89
90 % check statically if executing OpName1 guarantees that OpName2 is disabled after execution
91 static_disabled_after(OpName1,OpName2) :- static_disabled_after(OpName1,OpName2,true).
92
93 :- dynamic static_disabled_after_cache/3.
94 static_disabled_after(OpName1,OpName2,Res) :-
95 static_disabled_after_cache(OpName1,OpName2,Cached),!,
96 Res=Cached.
97 static_disabled_after(OpName1,OpName2,Res) :- % TODO: separate into Op1, Op2
98 b_top_level_operation(OpName1),
99 b_top_level_operation(OpName2),
100 get_guard_and_precision(OpName2,Guard2,_),
101 b_get_machine_operation_for_animation(OpName1,_Results,_Parameters,TBody1),
102 (get_definite_assignment(TBody1,TLHS1,TRHS), % we must assign LHS := RHS
103 norm_lhs(TLHS1,LHS),
104 select_member_in_conjunction(TC,Guard2,_RestProp),
105 get_texpr_expr(TC,C),
106 property_false_due_to_assignment(C,LHS,TRHS) % C is in contradiction with the assignment
107 -> Cached=true
108 ; Cached=false
109 ),
110 % TODO: if OpName1 /= OpName2 we could look for guard equality in OpName1 for unmodified var
111 debug_format(19,'Computed static_disabled_after: after ~w the operation ~w is guaranteed to be disabled: ~w~n',[OpName1,OpName2,Cached]),
112 assertz(static_disabled_after_cache(OpName1,OpName2,Cached)),
113 Res=Cached.
114
115 :- use_module(library(lists)).
116 % get assignments that must definitely be executed when the operation is successful
117 get_definite_assignment(b(B,subst,_),LHS,RHS) :- !, get_definite_assignment(B,LHS,RHS).
118 get_definite_assignment(assign(LLHS,RRHS),LHS,RHS) :- !, nth1(N,LLHS,LHS), nth1(N,RRHS,RHS).
119 get_definite_assignment(assign_single_id(LHS,RHS),LHS,RHS) :- !.
120 get_definite_assignment(parallel(L),LHS,RHS) :- !, member(S,L), get_definite_assignment(S,LHS,RHS).
121 get_definite_assignment(sequence(L),LHS,RHS) :- !, last(L,S), get_definite_assignment(S,LHS,RHS).
122 get_definite_assignment(var(_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
123 get_definite_assignment(precondition(_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
124 get_definite_assignment(block(S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
125 get_definite_assignment(let(_,_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
126 get_definite_assignment(select([b(select_when(_Cond,Then),_,_)]),LHS,RHS) :- !, get_definite_assignment(Then,LHS,RHS).
127 get_definite_assignment(any(_,_,S),LHS,RHS) :- !,
128 get_definite_assignment(S,LHS,RHS). % ok since different_texpr_values used above does not use quantified ids
129 get_definite_assignment(skip,_,_) :- !,fail.
130 get_definite_assignment(while(_,_,_,_),_,_) :- !,fail.
131 get_definite_assignment(choice(_),_,_) :- !,fail.
132 get_definite_assignment(becomes_element_of(_,_),_,_) :- !,fail.
133 get_definite_assignment(becomes_such(_,_),_,_) :- !,fail.
134 get_definite_assignment(operation_call(_,_,_),_,_) :- !,fail.
135 get_definite_assignment(if(_IfList),_,_) :- !, fail.
136 get_definite_assignment(external_subst_call(_,_),_,_) :- !, fail.
137 get_definite_assignment(S,_,_) :- functor(S,F,N),write(uncov_def_assign(F,N)),nl,fail.
138
139
140 property_false_due_to_assignment(equal(TA,TB),NLHS,TRHS) :-
141 norm_lhs(TA,NLHS),different_texpr_values(TRHS,TB).
142 property_false_due_to_assignment(equal(TB,TA),NLHS,TRHS) :-
143 norm_lhs(TA,NLHS),different_texpr_values(TRHS,TB).
144 property_false_due_to_assignment(not_equal(TA,TB),NLHS,TRHS) :-
145 norm_lhs(TA,NLHS), guaranteed_same_value(TRHS,TB).
146 property_false_due_to_assignment(not_equal(TB,TA),NLHS,TRHS) :-
147 norm_lhs(TA,NLHS), guaranteed_same_value(TRHS,TB).
148 % TODO: greater, ... for integer values
149
150 guaranteed_same_value(TA,TB) :- norm_arg(TA,Val), norm_arg(TB,Val).
151
152 get_equality(Properties,TLHS,TRHS) :-
153 select_member_in_conjunction(C,Properties,_RestProp),
154 get_texpr_expr(C,equal(TLHS1,TRHS1)),
155 ( TLHS = TLHS1, TRHS = TRHS1
156 ; TLHS = TRHS1, TRHS = TLHS1 ).
157
158 % only accept Identifier or F(value_wo_ids)
159 norm_lhs(b(E,_,_),NE) :- !, norm_lhs(E,NE).
160 norm_lhs(identifier(ID),ID) :- !.
161 norm_lhs(function(TF,TA),function(NF,NA)) :- !,
162 norm_lhs(TF,NF), norm_arg(TA,NA).
163 % TODO: record field assign x's := ..., nested function assignment
164
165 norm_arg(b(E,_,_),NE) :- !, norm_arg(E,NE).
166 norm_arg(integer(Nr),NE) :- !,NE=Nr.
167 norm_arg(identifier(ID),NE) :- !,NE=identifier(ID).
168 norm_arg(empty_sequence,N) :- !, N=empty_set.
169 norm_arg(couple(A,B),couple(NA,NB)) :- !, norm_arg(A,NA), norm_arg(B,NB).
170 % TODO: records, ...
171 norm_arg(X,N) :- norm_literal(X),!,N=X.
172 norm_arg(S,_) :- functor(S,F,N),write(uncov_norm_arg(F,N,S)),nl,fail.
173
174 norm_literal(string(_)).
175 norm_literal(real(_)).
176 norm_literal(boolean_true).
177 norm_literal(boolean_false).
178 norm_literal(empty_set).
179
180