-- (C) Copyright International Business Machines Corporation 23 January 
-- 1990.  All Rights Reserved. 
--  
-- See the file USERAGREEMENT distributed with this software for full 
-- terms and conditions of use. 
-- File: cgblock.pp
-- Author: Andy Lowry
-- SCCS Info: @(#)cgblock.pp	1.12 3/13/90

-- This process translates an absprog 'block', including its handlers,
-- into a collection of basic blocks.  If there are no handlers
-- attached to this block, we just translate the main clause of the
-- block without generating anything before or after it (this occurs
-- frequently when a block is used only to introduce new
-- declarations).  If there are handlers, we do the following:
--    1. Allocate a new basic block ID for the merge point from all
--       handlers.
--    2. Allocate a new basic block ID for the main clause and for
--       each handler clause.
--    3. Tie off the currnet BB with a block exit referencing the BB
--       ID's allocated in step 2.
--    4. For the main clause and each handler clause:
--    4.a. Open up a new BB with the ID allocated in step 2.
--    4.b. Translate the clause
--    4.c. For the main clause ONLY, generate an 'endblock' operation
--    4.d. Tie off the current BB (not necessarily the one allocated
--         in 4.a.) with an unconditional branch to the merge point.
--    5. Open the merge point BB

#include "typemark.h"
#include "codegen.h"

cgBlock: using (interpform, cgInternal)

process (Q: cgStmtQ)

declare
  args: cgStmt;
  main: clauseid;
  empty: empty;
begin
  receive args from Q;
  reveal args.stmt.qualifier.block;

  -- extract the main clause of the block
  inspect proc in ABSPROG.programs[args.cgData.Proc.id] begin
    inspect scope in proc.executable_part.scopes 
	[args.stmt.qualifier.block.scope]
    begin
      main := scope.clause;
    end inspect;
  end inspect;

  if B(I(size of args.stmt.qualifier.block.handlers) = ZERO) then
    call FNS.cgClause(main,args.cgData);
  else
    block declare
      mergeBBid: BBid;
      clauseids: clauseidList;
      BBids: BBidList;
    begin
      -- Allocate a BBid for the merge point
      mergeBBid <- BBid#(unique);

      -- Build parallel lists of clause ID's and BB ID's for the main
      -- clause and all handler clauses
      new clauseids;
      new BBids;
				-- main clause first
      insert clauseid#(copy of main) into clauseids;
      insert BBid#(unique) into BBids;
				-- then all the handler clauses
      for handler in args.stmt.qualifier.block.handlers[] inspect
	insert clauseid#(copy of handler.clause) into clauseids;
	insert BBid#(unique) into BBids;
      end for;
      
      -- Now generate the 'handlers' type exit structure and install
      -- it in the current BB
      block declare
	he: BBHandlersExit;
	BBidsCopy: BBidList;
      begin
	new he;			-- allocate the exit structure
	BBidsCopy := BBids;	-- make a copy we can destroy

	-- entry BB is the one generated by main clause
	remove he.entry from AREF(tmp,BBidsCopy,ZERO); 

	-- remaining BB ID's constitute our handler targets
	he.targets <- BBidsCopy;

	-- fill in handler names from the statement qualifier
	new he.names;
	for handler in args.stmt.qualifier.block.handlers[] inspect
	  insert handlername#(copy of handler.id) into he.names;
	end for;

	-- install the exit structure in the current BB
	unite CURBB.exit.handlers from he;
      end block;

      -- Translate each clause in turn
      for clauseid in clauseids[] inspect
	-- allocate a new BB for the clause and make it current
	block declare
	  BBid: BBid;
	begin
	  remove BBid from AREF(tmp,BBids,ZERO);
	  NEWBB(BBid);
	end block;
	
	-- Now codegen the clause, filling up the BB and maybe
	-- creating others in the process
	call FNS.cgClause(clauseid,args.cgData);

	-- Add an 'endblock' instruction to end the main clause
	if B(main = clauseid) then
	  ADDTPLT(endblock);
	end if;

	-- tie off each clause with a jump to the merge point
	unite CURBB.exit.jump from BBid#(copy of mergeBBid);

      end for;

      -- Merge point BB is now current
      NEWBB(mergeBBid);

    end block;

  end if;

  return args;

end process
