[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Lightning] Reducing opcode permutations

From: Sandro Magi
Subject: Re: [Lightning] Reducing opcode permutations
Date: Wed, 26 Mar 2008 10:07:40 -0400

On Wed, Mar 26, 2008 at 2:46 AM, Paolo Bonzini <address@hidden> wrote:
>  > addr_c
>  > addr_uc
>  > addr_i
>  > addr_ui
>  > addr_l
>  > addr_ul
>  > addr_p
>  >
>  > Would all be collapsed down to simply: addr, since addr is a
>  > register-register operation
>  I don't think I have that many redundant operations in lightning; search
>  for "synonyms" in the porting manual, there are very few unnecessary
>  _c/_uc/_s/_us operations.

Sorry, tiredness and assembly-level reasoning don't go well together. :-)

I'm looking at a "Synonyms" section now, and it says this:

  For example, adding two unsigned integers is exactly the same as
  adding two signed integers (assuming a two's complement
  representation of negative numbers); yet, gnu lightning provides
  both jit_addr_i and jit_addr_ui macros.

Two points:

1. This is the type of duplication I'd like to avoid, as it adds
unnecessary bloat to the C library (and to my cramped fingers!). This
isn't a problem for Lightning because macros have no runtime footprint
for unused instructions. The "Synonyms—don't define them" section is
quite long.

2. Something doesn't seem right about the above description. For
instance, a signed 32-bit number overflows at 2^31, not 2^32, so
addc_i and addc_ui should have different semantics. Also, 64-bit
systems which define a 32-bit int, but a 64-bit long int, similarly
overflow at different values for addc. Is this the actual behaviour?

The approach I was taking was to make 'register' its own type, with
its own operations (or perhaps a 'word' type). The _c/_uc/_i/... only
have immediate forms, and the register forms which take only register
arguments are appended with _r. So to keep things portable:

typedef unsigned ireg_t; //register number

// modular addition
// a0 = a1 + i
void sadd_i(ireg_t a0, ireg_t a1, int i); //signed
void sadd_l(ireg_t a0, ireg_t a1, long i);
void uadd_ui(ireg_t a0, ireg_t a1, uint i); //unsigned
void uadd_ul(ireg_t a0, ireg_t a1, ulong i);

// modular addition
// a0 = a1 + a2
void sadd_r(ireg_t a0, ireg_t a1, ireg_t a2); //overflow at 2^(word_size-1)
void uadd_r(ireg_t a0, ireg_t a1, ireg_t a2); //overflow at 2^word_size

Signed and unsigned forms handle the different overflow boundaries.
This eliminates all register-register operations on types smaller than
a register/word size. I was wondering whether these operations
actually perform overflow checking on the smaller types though, as
that negates my whole assumption.

>  For example, I included all cases for
>  load/store operations, but adds only work at the word level.

Are you saying load always fetches a full word, then &'s the register
with a bitmask for the appropriate type?

>  _l/_ul are
>  always included for portability to 64-bit systems, _p is too and
>  sometimes provides additional support for patching forward references.

Haven't gotten that far yet, but I do maintain a distinct 'pointer'
type with only its specific immediate operations. Again,
register-register operations are removed.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]