[M3devel] cardinal vs. word, divide?

Rodney M. Bates rodney_bates at lcwb.coop
Tue Nov 23 17:52:37 CET 2010



Jay K wrote:
> So, here are two maybe interesting cases.
> At least to jog my brain and help make sense of the system.
> 
> 
> DIV vs. Word.Divide of CARDINAL.
> u is for unsigned, or word
> C is for Cardinal.
>  Cardinal is [0..LAST(INTEGER)].
> 
> 
> <*NOWARN*>PROCEDURE 
> uDivide_param_C_C(a:CARDINAL;b:CARDINAL):Word.T=BEGIN RETURN 
> Word.Divide(a,b);END uDivide_param_C_C;
> 
> <*NOWARN*>PROCEDURE 
> Divide_param_C_C(a:CARDINAL;b:CARDINAL):CARDINAL=BEGIN RETURN a DIV 
> b;END Divide_param_C_C;
> 
> 
> (5579) begin_procedure procedure:0x178:Divide__Divide_param_C_C 
> Divide__Divide_param_C_C
> (5580) load var:0x2E5:a offset:0 src_t:word_64 dst_t:int_64
> (5581) load var:0x2E6:b offset:0 src_t:word_64 dst_t:int_64
> (5582) div type:int_64
> (5583) check_lo type:int_64 0 code:1
> (5584) exit_proc type:word_64
> (5585) end_procedure procedure:0x178:Divide__Divide_param_C_C
> 
> 
> (5571) begin_procedure procedure:0x177:Divide__uDivide_param_C_C 
> Divide__uDivide_param_C_C
> (5572) load var:0x2E2:a offset:0 src_t:word_64 dst_t:int_64
> (5573) load var:0x2E3:b offset:0 src_t:word_64 dst_t:int_64
> (5574) div type:word_64
> (5575) exit_proc type:int_64
> (5576) end_procedure procedure:0x177:Divide__uDivide_param_C_C
> 
> 
> Thoughts?
> 
> 
> Is it right for the load to convert from word to int?
>  (I'll see about removing the address_token for unsigned/signed-only 
> conversions, if it is there.)
>  
>  
> I can see how makes sense.
> CARDINAL is just a subrange of INTEGER. So it is INTEGER.
> 
> 
> If/when we are clever, we can represent the subranges in the types
> in the backend, and the optimizer should notice, and these
> would generate identical code, if they don't already.
> 
> 
> But the return types of the divides vary as well.
> There do exist unsigned types at this level.
> 
> 
> Does that imply that
> a,b:CARDINAL
> 
> Word.Or(a, 0) DIV Word.Or(b, 0)
> is different than
> a DIV b?
> 
> 
> I guess so. Different code at least.

Same result value, for all a,b.  The code should only differ if the
compiler does not optimize away the noop Word.Or operations.

At the language semantics level, applying a builtin operator
like DIV or Word.Or to a subrange (CARDINAL) is like passing
the subrange value to a procedure that takes an INTEGER formal parameter
of VALUE mode.  The actual must be 'assignable' to the formal, which
is the case in all these examples, without runtime checks.  There could
be a representation change generated by the compiler (this is _not_
an implied type conversion), though that doesn't happen here, since surely
CARDINAL will always be represented the same as INTEGER.

If a were, say, [-128..127] or smaller, the compiler might well have
represented/stored it in a (signed) byte, and would then have to do a
representation conversion by expanding and sign-extending into a
full word before applying the operator to it.

> Given that cardinal is "half range", the results should always match.
> That is, really, other than added/missing range checks, CARDINAL
> will always act the same as INTEGER.
> So then the unsigned types..don't mean anything?
> 

I'd say yes, except when attached to the div operator.

Most languages have different types for signed and unsigned.  Then the
same operator, applied to the different types does different things.
These are (language-defined) overloaded operators.

In the case of signed vs. unsigned, Modula-3 turns it around.  There
is only one type INTEGER=Word.T.  Instead, there are different operators
for the signed/unsigned operations: DIV vs. Word.Divide.  They just
apply different interpretations to the same bits.

 From these examples and some brief looks at M3x83.m3, it looks like the
M3 backend system is designed to reflect the more common source language
system of different types, with the front end having propagated a copy of
the operand type to the operator too.

I don't know how the gcc tree system works, but I'd bet it too uses different
types.  The way that I would match the Modula-3 semantics to the gcc system would
be to keep everything in a signed type, except when an unsigned operator
comes along.  Then convert to unsigned, apply the unsigned operator, and
convert back to signed.

The conversions used would have to be LOOPHOLE-like in just reinterpreting
the bits without changing them.  No sign-check going to unsigned and no
sign-extension coming back.  So the only reason to need conversions at all
is if gcc matches types of operands to types of operators and chokes on
mismatch.

I can see why the div operator needs separate types word_64 or int_64 attached
to distinguish which operation is to be done.  I can't see why the operand
types need such a distinction at all, why the type is changed in the load,
or why the source and destination types are what they are.  The distinction
might not actually mean much on the operands.


> 
>  - Jay
> 
> 
> 
> 



More information about the M3devel mailing list