1 % (c) 2009-2025 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. % activation_independent or independent
33
34 :- dynamic static_activation_dependence_cache/3.
35 static_activation_dependence(OpName1,OpName2,Res) :-
36 static_activation_dependence_cache(OpName1,OpName2,Cached),!,
37 Res=Cached.
38 static_activation_dependence(OpName1,OpName2,Res) :-
39 b_top_level_operation(OpName1),
40 b_get_read_write(OpName1,_,Writes1),
41 b_top_level_operation(OpName2),
42 b_get_operation_read_guard_vars(OpName2,true,GuardReads2,Precise),
43 (vars_ord_intersect(Writes1,GuardReads2)
44 -> Cached = dependent % OpName1 could enable or disable OpName2
45 ; %print(indep(OpName1,Writes1,OpName2,GuardReads2)),nl,
46 b_get_read_write(OpName2,Reads2,_Writes2),
47 (vars_ord_intersect(Writes1,Reads2)
48 -> (Precise==precise
49 -> Cached = activation_independent % OpName1 cannot enable or disable OpName2, but can influence effect
50 ; Cached = dependent % Computation of GuardReads2 was not precise (while loops, ... in operation)
51 )
52 ; Cached = independent % but order could still matter; for this we would need to look at Writes2
53 )
54 ),
55 debug_format(19,'Computed static dependence ~w -> ~w : ~w~n',[OpName1,OpName2,Cached]),
56 assertz(static_activation_dependence_cache(OpName1,OpName2,Cached)),
57 Res=Cached.
58
59
60 :- use_module(library(ordsets),[ord_intersect/2]).
61 % a version of ord_intersect(ion) which deals with the '$all' term
62 vars_ord_intersect('$all',_) :- !.
63 vars_ord_intersect(_,'$all') :- !.
64 vars_ord_intersect(A,B) :- ord_intersect(A,B).
65
66
67
68 :- use_module(probsrc(eventhandling),[register_event_listener/3]).
69 :- register_event_listener(specification_initialised,reset_static_enabling_analysis,
70 'Initialise module static_enabling analysis.').
71
72 reset_static_enabling_analysis :-
73 retractall(static_activation_dependence_cache(_,_,_)),
74 retractall(static_disabled_after_cache(_,_)).
75
76
77
78 :- use_module(probsrc(bmachine),[b_get_machine_operation_for_animation/4]).
79 :- use_module(probsrc(b_state_model_check), [get_guard_and_precision/3]).
80 :- use_module(probsrc(bsyntaxtree),[get_texpr_expr/2,different_texpr_values/2,select_member_in_conjunction/3]).
81
82 % check statically if an operation must disable itself
83 % the check is aimed to detect typical control flow encoding using booleans or program counters
84 % example op = SELECT op_done=FALSE THEN .... op_done := TRUE END
85 static_disables_itself(OpName) :- static_disabled_after(OpName,OpName,true).
86
87 % check statically if executing OpName1 guarantees that OpName2 is disabled after execution
88 static_disabled_after(OpName1,OpName2) :- static_disabled_after(OpName1,OpName2,true).
89
90 :- dynamic static_disabled_after_cache/3.
91 static_disabled_after(OpName1,OpName2,Res) :-
92 static_disabled_after_cache(OpName1,OpName2,Cached),!,
93 Res=Cached.
94 static_disabled_after(OpName1,OpName2,Res) :- % TODO: separate into Op1, Op2
95 b_top_level_operation(OpName1),
96 b_top_level_operation(OpName2),
97 get_guard_and_precision(OpName2,Guard2,_),
98 b_get_machine_operation_for_animation(OpName1,_Results,_Parameters,TBody1),
99 (get_definite_assignment(TBody1,TLHS1,TRHS), % we must assign LHS := RHS
100 norm_lhs(TLHS1,LHS),
101 select_member_in_conjunction(TC,Guard2,_RestProp),
102 get_texpr_expr(TC,C),
103 property_false_due_to_assignment(C,LHS,TRHS) % C is in contradiction with the assignment
104 -> Cached=true
105 ; Cached=false
106 ),
107 % TODO: if OpName1 /= OpName2 we could look for guard equality in OpName1 for unmodified var
108 debug_println(19,static_disabled_after(OpName1,OpName2,Cached)),
109 assertz(static_disabled_after_cache(OpName1,OpName2,Cached)),
110 Res=Cached.
111
112 :- use_module(library(lists)).
113 % get assignments that must definitely be executed when the operation is successful
114 get_definite_assignment(b(B,subst,_),LHS,RHS) :- !, get_definite_assignment(B,LHS,RHS).
115 get_definite_assignment(assign(LLHS,RRHS),LHS,RHS) :- !, nth1(N,LLHS,LHS), nth1(N,RRHS,RHS).
116 get_definite_assignment(assign_single_id(LHS,RHS),LHS,RHS) :- !.
117 get_definite_assignment(parallel(L),LHS,RHS) :- !, member(S,L), get_definite_assignment(S,LHS,RHS).
118 get_definite_assignment(sequence(L),LHS,RHS) :- !, last(L,S), get_definite_assignment(S,LHS,RHS).
119 get_definite_assignment(var(_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
120 get_definite_assignment(precondition(_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
121 get_definite_assignment(block(S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
122 get_definite_assignment(let(_,_,S),LHS,RHS) :- !, get_definite_assignment(S,LHS,RHS).
123 get_definite_assignment(select([b(select_when(_Cond,Then),_,_)]),LHS,RHS) :- !, get_definite_assignment(Then,LHS,RHS).
124 get_definite_assignment(skip,_,_) :- !,fail.
125 get_definite_assignment(while(_,_,_,_),_,_) :- !,fail.
126 get_definite_assignment(choice(_),_,_) :- !,fail.
127 get_definite_assignment(becomes_element_of(_,_),_,_) :- !,fail.
128 get_definite_assignment(becomes_such(_,_),_,_) :- !,fail.
129 get_definite_assignment(operation_call(_,_,_),_,_) :- !,fail.
130 get_definite_assignment(S,_,_) :- functor(S,F,N),write(uncov_def_assign(F,N)),nl,fail.
131
132
133 property_false_due_to_assignment(equal(TA,TB),NLHS,TRHS) :-
134 norm_lhs(TA,NLHS),different_texpr_values(TRHS,TB).
135 property_false_due_to_assignment(equal(TB,TA),NLHS,TRHS) :-
136 norm_lhs(TA,NLHS),different_texpr_values(TRHS,TB).
137 property_false_due_to_assignment(not_equal(TA,TB),NLHS,TRHS) :-
138 norm_lhs(TA,NLHS), guaranteed_same_value(TRHS,TB).
139 property_false_due_to_assignment(not_equal(TB,TA),NLHS,TRHS) :-
140 norm_lhs(TA,NLHS), guaranteed_same_value(TRHS,TB).
141 % TODO: greater, ... for integer values
142
143 guaranteed_same_value(TA,TB) :- norm_arg(TA,Val), norm_arg(TB,Val).
144
145 get_equality(Properties,TLHS,TRHS) :-
146 select_member_in_conjunction(C,Properties,_RestProp),
147 get_texpr_expr(C,equal(TLHS1,TRHS1)),
148 ( TLHS = TLHS1, TRHS = TRHS1
149 ; TLHS = TRHS1, TRHS = TLHS1 ).
150
151 % only accept Identifier or F(value_wo_ids)
152 norm_lhs(b(E,_,_),NE) :- !, norm_lhs(E,NE).
153 norm_lhs(identifier(ID),ID) :- !.
154 norm_lhs(function(TF,TA),function(NF,NA)) :- !,
155 norm_lhs(TF,NF), norm_arg(TA,NA).
156 % TODO: record field assign x's := ..., nested function assignment
157
158 norm_arg(b(E,_,_),NE) :- !, norm_arg(E,NE).
159 norm_arg(integer(Nr),NE) :- !,NE=Nr.
160 norm_arg(empty_sequence,N) :- !, N=empty_set.
161 norm_arg(couple(A,B),couple(NA,NB)) :- !, norm_arg(A,NA), norm_arg(B,NB).
162 % TODO: records, ...
163 norm_arg(X,N) :- norm_literal(X),!,N=X.
164 norm_arg(S,_) :- functor(S,F,N),write(uncov_norm_arg(F,N,S)),nl,fail.
165
166 norm_literal(string(_)).
167 norm_literal(real(_)).
168 norm_literal(boolean_true).
169 norm_literal(boolean_false).
170 norm_literal(empty_set).
171
172