-- (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: cgprocess.pp
-- Author: Andy Lowry
-- SCCS Info: @(#)cgprocess.pp	1.28 2/16/92

-- This function generates LI code for a single Hermes absprog
-- process.  The process is first transformed into a collection of
-- basic blocks containing LI instructions, with all branch targets
-- set to basic block ID's.  Next the basic blocks are submitted to
-- the optimizer, which returns a (hopefully) improved set of basic
-- blocks.  Finally, the basic blocks are strung together into a
-- single ordered table of LI code instructions, with branch targets
-- resolved to indices into the table.

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

cgProcess: using (interpform, cgInternal, common, parse)
#ifdef CGLINK
linking (cgprocinit)
#endif
process (Q: cgProcessQ)

declare
  args: cgProcess;
  shutdown: signalPort;
  empty: empty;
  cgProcInit: cgProcInitFn;
begin
  receive args from Q;
    
  -- initialize per-process auxiliary data
  cgProcInit <- cgProcInitFn#(CREATEOF(cgprocinit, "cgprocinit"));  call cgProcInit(args.proc,args.cgData,shutdown);

  -- allocate the result object
  new args.LIprog;
  args.LIprog.id <- liprogid#(unique);-- all li progs get different id's

  inspect scope in args.proc.executable_part.scopes
	[args.cgData.Proc.proc.executable_part.main_scope]
  begin

    -- codegen the main clause and, recursively, all the other
    -- clauses in the process
    call FNS.cgClause(scope.clause,args.cgData);

    -- fill in the initport typename while we've got the main
    -- scope isolated
    inspect decl in scope.declarations[args.proc.initport] begin
      reveal decl.typename.typename; -- initport must be named
      args.LIprog.type := decl.typename.typename;
    end inspect;

  end inspect;

  -- Tie off the code with an 'endprocess' instruction in the final
  -- basic block, then install the final BB in BBData
  ADDTPLT(endprocess);
  unite CURBB.exit.none from empty;
  insert BBid#(copy of CURBB.id) into BBDATA.BBOrder;
  insert CURBB into BBDATA.BBs;

  -- Get the number of registers needed from the address mapper
  BBDATA.nreg <- I(args.cgData.Proc.nRegUsed());

  -- At this point all the code has been generated, but branches are
  -- encoded in the exit data of the basic blocks.  The following
  -- optimization phase may transform the basic blocks in any fashion,
  -- including reordering.  It is allowable for the optimizer to do
  -- absolutely nothing.
# ifndef LIGEN
    call FNS.optimize(BBDATA);
# endif

  -- Process data vector size is computed from the size of the
  -- register set used by the basic blocks
  args.LIprog.size := BBDATA.nreg;

  -- Now we just string the basic blocks together in the current
  -- ordering, inserting branches as necessary to satisfy the exit
  -- specifications.
  args.LIprog.code <- interpform!code#(FNS.BBAssemble(BBDATA));

  -- See if there's a "Process Names" annotation, and if so, try to
  -- find a name for this process.  Failing that, look for a "Module
  -- Name" annotation and use its value for the main process.  Other
  -- processes get names formed from the module name.  If neither
  -- annotation exists, construct a relatively useless name.
  block declare
    pmaps: executable_printmappings;
    execId: executable_id;
    arb: polymorph;
  begin
    inspect pnamesAnnotation in args.cgData.Prog.annotations
	  [S("Process Names")]
    begin
      arb := pnamesAnnotation.thing;
      unwrap pmaps from arb { init };
      unite execId.pid from processid#(copy of args.proc.id);
      inspect pmap in pmaps[execId] begin
	args.LIprog.name := pmap.name;
      end inspect;
    end inspect;
  on (NotFound)			-- for either inspect
    block declare
      modname: charstring;
    begin
      inspect modnameAnnotation in args.cgData.Prog.annotations
	    [S("Module Name")] begin
	arb := modnameAnnotation.thing;
	unwrap modname from arb {init};
	if B(args.proc.id = args.cgData.Prog.main_program) then
	  args.LIprog.name <- modname;
	else
	  args.LIprog.name <- S(modname | S("_proglit"));
	end if;
      end inspect;
    on (NotFound)
      args.LIprog.name <- S("unnamed_process");
    end block;
  end block;

  -- Fill in the ccode fields with dummy data.
  -- Transformation will supply useful values.

  args.LIprog.path <- S("");			    -- following compile/link
  args.LIprog.text <- S("");			    -- result of transformation
  args.LIprog.object <- S("");			    -- result of compile/link
  args.LIprog.handle <- interpform!object_handle#0; -- following dynamic load
  new args.LIprog.pool;				    -- filled by C-code trans.

  return args;			-- all done... send back the results

  -- shut down any servers we started on behalf of this process
  send empty to shutdown;
  
end process
