[M3commit] [modula3/cm3] 496e9b: Fix compiler-generated FINALLY procedure using par...

Rodney M. Bates rodney_bates at lcwb.coop
Sun Aug 2 21:57:28 CEST 2015


AFAIK, it was not causing an observable failure in any of the the established back
ends.  But it was causing Peter trouble in translating to llvm.  Here is part of
the thread (which somehow got on to the unrelated SUBARRAY thread,.)
--------------------------------------------------------------------------------------

So far not doing anything with free_temp, declare_temp just does an alloca but does it at the end of the first basic block to avoid dominate all uses problems. ( I have since discovered that there is a flag -alloca-hoisting which does this for you). The language ref hardly mentions temps except that they are referred to as unnamed values ie %1 %2 etc whether the optimiser does anything with these I dont know. I think I'm giving the temps names like %tmp.1 etc
   The workaround I have at the moment is that if in the store, (which I think is the first place one of these temps is referenced) the var is a temp ie having NoID and is not declared in the current procedure then declare it ie alloca it. Seems to work but seems pretty kludgy.
   My first thought when I struck this problem was that I should put all temps on the static link (since there is no parameter in declare_temp to say its uplevel and hence say which could be nested proc material) but that didnt work and really it was a pretty dumb idea. I cant see why the front end couldnt just declare a new temp in the finally proc.

Commit 496e9be1dcdcf87bda8e72239fc90132591b4cf4 fixes this, for this test case.

Regards Peter

On Sun, Jul 26, 2015 at 2:26 AM, Rodney M. Bates <rodney_bates at lcwb.coop> wrote:

     More on this:

     I appears that, in the CM3 IR, "variables" declared by declare_local and one
     declared by declare_temp (and a few others, too), while declared with different
     operators, are accessible interchangeably.  In this example, the FINALLY procedure
     accesses both s and the temporary nonlocally, in the same way.  The difference
     is, the temp, unlike a local variable, has the possibility that its space in
     the activation record is freed prior to the end of the corresponding code.

     What llvm IR are you translating declare_temp and free_temp into?   Llvm might
     have different rules for temps.




     On 07/25/2015 10:25 AM, Rodney M. Bates wrote:

         I compiled this and looked at the cm3 IR for it.  At first glance, it looks like
         a bug in the front end.  The FINALLY code is translated as a nested procedure,
         inside the one containing the entire TRY..FINALLY statement.  The temp is created by
         a declare_temp in the outer procedure, freed by a free_temp in the inner one,
         and used in both, the 2 uses being unrelated.

         In m3-sys/m3middle/src/M3CG_Ops.i3, I see:
         -----------------------------------------------------------------------------
           declare_temp (s: ByteSize;  a: Alignment;  t: Type;
                        in_memory: BOOLEAN): Var;
         (* declares an anonymous local variable.  Temps are declared
             and freed between their containing procedure's begin_procedure and
             end_procedure calls.  Temps are never referenced by nested procedures. *)
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

         free_temp (v: Var);
         (* releases the space occupied by temp 'v' so that it may be reused by
             other new temporaries. *)
         -----------------------------------------------------------------------------

         And it also seems strange for the temp to be freed inside the nested procedure,
         although this does not violate what the comment says.  The fact that every
         temp has a unique variable number would take care of matching the free_temp to the
         right declare_temp, and maybe the code generators can handle freeing a nonlocal
         temp.

         Apparently, this has caused no problems with preexisting code generators.
         But it certainly looks wrong, and clearly violates the comments.

         I recall that the gcc-derived code generator and the integrated x86 code generator
         both unnest nested procedures, in opposite ways (one pulls them out in front, the
         other in back), which might have something to do with how they handle this.

         What happens in the llvm back end for a programmer-declared nested procedure
         making a nonlocal reference to a programmer-declared local variable of the
         containing procedure?  If you can handle this latter case, can you handle the
         failing one the same way?  Maybe this is what is happening in the other code
         generators, and the comment is just too strict.




         On 07/24/2015 08:13 PM, Peter McKinna wrote:

             On the subject of temporaries can I get your thoughts on the following?

             TRY
                s := s & "a";
             FINALLY
                s := s & "b";
             END;

             The front end declares a temp in the try block as part of its concat and then refers to the same temp in the finally block. The trouble is that the finally code is generated in a separate procedure and references a temp declared in the proc of the try. In llvm the first you know of the problem is a store to the temp which has not been declared.
             Just wondering whether the front end should redeclare this temp? Also is the front end generating similar temps for other runtime operations?

             Regards Peter

--------------------------------------------------------------------------------------

It really was strange IR.  I doubt this change would cause any new problems, and
could fix others.  Here is the test case:

MODULE TryTemp EXPORTS Main

; PROCEDURE P ( )

   = VAR s : TEXT := "z"

   ; BEGIN
       TRY
         s := s & "a"
       FINALLY
         s := s & "b"
       END
     END P

; BEGIN
     P ( )
   END TryTemp
.

I'm not sure where to put it.  m3-sys/tests seems to have some kind of organization
and infrastructure, which I have never understand.  I don't have any automated
results check for this one.  I do have before and after output from m3cgc.




On 08/01/2015 09:20 PM, Jay K wrote:
> Rodney, Do you have a test case that was broken before and fixed afterward?
>
> If possible, though not required, check something into m3-sys/m3tests?
>
> I don't mean to imply the code was correct before. I don't know, at all.
>
> Thank you,
>   - Jay
>
>
>
> Date: Sat, 1 Aug 2015 17:36:54 -0700
> From: rodney.m.bates at acm.org
> To: m3commit at elegosoft.com
> Subject: [M3commit] [modula3/cm3] 496e9b: Fix compiler-generated FINALLY procedure using par...
>
>    Branch: refs/heads/master
>    Home:https://github.com/modula3/cm3
>    Commit: 496e9be1dcdcf87bda8e72239fc90132591b4cf4
>        https://github.com/modula3/cm3/commit/496e9be1dcdcf87bda8e72239fc90132591b4cf4
>    Author: Rodney Bates <rodney.m.bates at acm.org>
>    Date:   2015-08-01 (Sat, 01 Aug 2015)
>
>    Changed paths:
>      M m3-sys/m3front/src/misc/CG.m3
>
>    Log Message:
>    -----------
>    Fix compiler-generated FINALLY procedure using parent procedure's temporary.
>
>   Changes to be committed:
>
> 	modified:   m3-sys/m3front/src/misc/CG.m3
>
> CG was not stacking global variables used for keeping track of temporaries
> when entering nested procedures.  In the case of a compiler-generated
> nested procedure for the finally part of a TRY--FINALLY block, this
> meant the finally code could use a temporary allocated by the parent,
> though not in use at the time.  This violated the comment in M3CG_Ops.i3:
>
>      declare_temp (s: ByteSize;  a: Alignment;  t: Type;
>              in_memory: BOOLEAN): Var;
>      (* declares an anonymous local variable.  Temps are declared
>         and freed between their containing procedure's begin_procedure and
>         end_procedure calls.  Temps are never referenced by nested procedures. *)
>
> In cases of nested procedures explicitly declared in source code, this
> didn't matter because they are located ahead of any of the parent
> procedure's executable code, when it has no allocated temps, and they
> free their own temps at their end, restoring the previous state.
>
>
>
>
> _______________________________________________ M3commit mailing list M3commit at elegosoft.com https://mail.elegosoft.com/cgi-bin/mailman/listinfo/m3commit
>
>
> _______________________________________________
> M3commit mailing list
> M3commit at elegosoft.com
> https://mail.elegosoft.com/cgi-bin/mailman/listinfo/m3commit
>

-- 
Rodney Bates
rodney.m.bates at acm.org



More information about the M3commit mailing list