MODULE TestIF;  (** CS, 18 Dec 98 - 25 Jan 99 *)

PROCEDURE UseAndChangePar* (VAR i: INTEGER): INTEGER;  (** uses parameter, side-effects it, and then returns it (usage and non-killing definition of parameter) *)
BEGIN
  INC(i); RETURN i
END UseAndChangePar;

PROCEDURE ChangePar* (VAR i: INTEGER): INTEGER;  (** side-effects parameter, and then returns it (does not use it, killing definition of parameter) *)
BEGIN
  i := 0; RETURN 0
END ChangePar;

PROCEDURE ChangeParSometimes* (VAR i: INTEGER): INTEGER;  (** side-effects parameter, and then returns it (does not use it, non-killing definition of parameter) *)
  VAR local: INTEGER;
BEGIN
  IF local # 0 THEN
    i := 0; RETURN 0
  ELSE
    RETURN 3
  END
END ChangeParSometimes;

PROCEDURE DoNoELSE*;  (** def in THEN branch, not killing previous defs *)
  VAR i, j: INTEGER;
BEGIN
  i := 1;
  j :=2;
  IF j # 0 THEN  (* value of j used in expression, def of j must reach this expression *)
    j := i;  (* def of i must reach this assignment *)
  END ;
  j := j;  (* both defs of j must reach this assignment *)
  i := i  (* def of i must reach this assignment *)
END DoNoELSE;

PROCEDURE DoWithELSE*;  (** defs in both branches, killing previous defs *)
  VAR i, j: INTEGER;
BEGIN
  i := 1;
  j :=2;
  IF j # 0 THEN  (* value of j used in expression, def of j must reach this expression *)
    j := i;  (* def of i must reach this assignment *)
  ELSE
    j := -i;  (* def of i must reach this assignment *)
  END ;
  j := j;  (* defs of j due to IF must reach this assignment, first def is used by expression *)
  i := i  (* def of i must reach this assignment *)
END DoWithELSE;

PROCEDURE DoWithELSE2*;  (** defs in both branches, killing previous defs *)
  VAR i, j: INTEGER;
BEGIN
  i := 1;
  j :=2;
  IF i # 0 THEN  (* value of i used in expression, def of i must reach this expression *)
    j := i;  (* def of i must reach this assignment *)
  ELSE
    j := -i;  (* def of i must reach this assignment *)
  END ;
  j := j;  (* defs of j due to IF must reach this assignment, first def must not reach *)
  i := i  (* def of i must reach this assignment *)
END DoWithELSE2;

PROCEDURE DoWithELSIFNoELSE*;  (** def in THEN and ELSIF branch, not killing previous defs *)
  VAR i, j: INTEGER;
BEGIN
  i := 1;
  j :=2;
  IF i > 0 THEN  (* value of i used in expression, def of i must reach this expression *)
    j := i  (* def of i must reach this assignment *)
  ELSIF j < 0 THEN  (* value of j used in expression, def of j must reach this expression *)
    j := -i  (* def of i must reach this assignment *)
  END ;
  j := j;  (* all three defs of j must reach this assignment *)
  i := i  (* def of i must reach this assignment *)
END DoWithELSIFNoELSE;

PROCEDURE DoWithELSIFWithELSE*;  (** defs in both branches, killing previous defs *)
  VAR i, j: INTEGER;
BEGIN
  i := 1;
  j :=2;
  IF i > 0 THEN  (* value of i used in expression, def of i must reach this expression *)
    j := i;  (* def of i must reach this assignment *)
  ELSIF i < 0 THEN  (* value of i used in expression, def of i must reach this expression *)
    j := -i  (* def of i must reach this assignment *)
  ELSE
    j := 0;
  END ;
  j := j;  (* defs of j due to IF must reach this assignment, first def must not reach *)
  i := i  (* def of i must reach this assignment *)
END DoWithELSIFWithELSE;

PROCEDURE DoSideEffects00*;  (** side-effect in expression of IF (killing def), def and usage in THEN branch, no ELSE *)
  VAR i, j: INTEGER;
BEGIN
  i := 0;
  j := 2;
  IF ChangePar(i) < 0 THEN  (* first def of i is killed by function call *)
    INC(j)
  END ;
  i := i;  (* first def of i is not reaching *)
  j := j
END DoSideEffects00;

PROCEDURE DoSideEffects01*;  (** side-effect in expression of IF (killing def), def in THEN branch, no ELSE *)
  VAR i: INTEGER;
BEGIN
  i := 0;
  IF ChangePar(i) < 0 THEN  (* first def of i is killed by function call *)
    i := 2  (* kills def due to function call *)
  END ;
  i := i  (* first def of i is not reaching, def due to function call (via non-existing ELSE) and def within IF are reaching *)
END DoSideEffects01;

PROCEDURE DoSideEffects02*;  (** side-effect in expression of IF (killing def), defs in both branches *)
  VAR i: INTEGER;
BEGIN
  i := 0;
  IF ChangePar(i) < 0 THEN  (* first def of i is killed by function call *)
    i := 2  (* kills def due to function call *)
  ELSE
    i := 1
  END ;
  i := i  (* first def of i is not reaching, defs in THEN and in ELSE branch are reaching, def due to function call is not reaching*)
END DoSideEffects02;

PROCEDURE DoSideEffects10*;  (** side-effect in expression with short circuit evaluation (&) of IF (killing def), defs in both branches *)
  VAR i, j: INTEGER;
BEGIN
  i := 0;
  j := 2;
  IF (ChangePar(i) < 0) & (ChangePar(j) < 0) THEN
    (* i defined and j defined by function calls *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j  (* first def of j is not reaching, only def of j due to function call is reaching *)
  ELSE
    (* i defined OR
      i defined and j defined by function calls
    *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j  (* first def of j may be reaching (if left expression of & failed) *)
  END ;
  i := i;  (* first def of i is not reaching, only defs of i within IF are reaching *)
  j := j  (* first def of j may be reaching, as well as defs of j within IF *)
END DoSideEffects10;

PROCEDURE DoSideEffects11*;  (** side-effect in expression with short circuit evaluation (~, &) of IF (killing def), defs in both branches *)
  VAR i, j: INTEGER;
BEGIN
  i := 0;
  j := 2;
  IF ~((ChangePar(i) < 0) & (ChangePar(j) < 0)) THEN
    (* i defined OR
      i defined and j defined by function calls
    *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j  (* first def of j may be reaching (if left expression of & failed) *)
  ELSE
    (* i defined and j defined by function calls *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j  (* first def of j is not reaching, only def of j due to function call is reaching *)
  END ;
  i := i;  (* first def of i is not reaching, only defs of i within IF are reaching *)
  j := j  (* first def of j may be reaching, as well as defs of j within IF *)
END DoSideEffects11;

PROCEDURE DoSideEffects20*;  (** side-effect in expression with short circuit evaluation (&) of IF (killing def), defs in both branches *)
  VAR i, j, k: INTEGER;
BEGIN
  i := 0;
  j := 1;
  k := 2;
  IF (ChangePar(i) < 0) & ((ChangePar(j) < 0) & (ChangePar(k) < 0)) THEN
    (* i defined, j defined, and k defined by function calls *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j;  (* first def of j is not reaching, only def of j due to function call is reaching *)
    k := k  (* first def of k is not reaching, only def of k due to function call is reaching *)
  ELSE
    (* i defined OR
      i defined and j defined OR
      i defined, j defined and k defined by function calls
    *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j;  (* first def of j may be reaching (if left expression of & failed) *)
    k := k  (* first def of j may be reaching (if left expression of & failed) *)
  END ;
  i := i;  (* only defs of i within IF must be reaching *)
  j := j;  (* all defs of j can be reaching *)
  k := k  (* all defs of j can be reaching *)
END DoSideEffects20;

PROCEDURE DoSideEffects30*;  (** side-effect in expression with short circuit evaluation (OR) of IF (killing def), defs in both branches *)
  VAR i, j, k: INTEGER;
BEGIN
  i := 0;
  j := 1;
  k := 2;
  IF (ChangePar(i) < 0) OR ((ChangePar(j) < 0) OR (ChangePar(k) < 0)) THEN
    (* i defined OR
      i defined and j defined OR
      i defined, j defined and k defined by function calls
    *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j;  (* first def of j is may be reaching (if left expression of & failed) *)
    k := k  (* first def of k j may be reaching (if left expression of & failed) *)
  ELSE  (* i defined, j defined, and k defined by function calls *)
    i := i;  (* first def of i is not reaching, only def of i due to function call is reaching *)
    j := j;  (* first def of j is not reaching, only def of j due to function call is reaching *)
    k := k  (* first def of k is not reaching, only def of k due to function call is reaching *)
  END ;
  i := i;  (* only defs of i within IF must be reaching *)
  j := j;  (* all defs of j can be reaching *)
  k := k  (* all defs of j can be reaching *)
END DoSideEffects30;

PROCEDURE DoSideEffects2*;  (** side-effects in expressions of IF and ELSIF *)
  VAR i, j: INTEGER;
BEGIN
  i := 0;
  j := 1;
  IF ChangePar(i) < 0 THEN  (* first def of i is killed by function call *)
    j := 1
  ELSIF ChangePar(i) > 0 THEN  (* previous defs of i are killed by function call *)
    j := 2;
    i := 3
  ELSE
    j := 3
  END ;
  i := i;  (* first def of i is not reaching, def of i due to function calls are reaching *)
  j := j  (* first def of j is not reaching, since all branches of IF define j *)
END DoSideEffects2;

PROCEDURE DoSideEffects3*;  (** side-effect in expression of IF (non-killing def), def in THEN branch, no ELSE *)
  VAR i: INTEGER;
BEGIN
  i := 0;
  IF ChangeParSometimes(i) < 0 THEN  (* first def of i is not killed by function call *)
    i := 2  (* kills def due to function call *)
  END ;
  i := i  (* first def of i is reaching, def due to function call (via non-existing ELSE) and def within IF are reaching *)
END DoSideEffects3;

END TestIF.