Skip to content

Keep locals in registers instead of stack when possible #7281

@Dentosal

Description

@Dentosal

Related Component

compiler

Problem you are trying to solve

The stack is used to store local variables needlessly, which leads to unneccessary bloat with LW/SW instructions. For some reason all locals (and globals) are treated as pointers even when their address is not used.

This is best illustrated with an example. Let's take the this example (the in_language_tests)

library;

use std::{
    flags::{
        disable_panic_on_overflow,
        enable_panic_on_overflow,
    },
};

#[test]
fn flags_disable_panic_on_overflow() {
    let _ = disable_panic_on_overflow();
    let _bar = u64::max() + 1;
    enable_panic_on_overflow();
}

It currently compiles into something like

                                                                                                              
  half-word   byte   op                                          raw           notes                          
          0   0      MOVE { dst: 0x3c, src: 0x3 }                1a f0 30 00                                  
          1   4      JMPF { dynamic: 0x0, fixed: 4 }             74 00 00 04                                  
          2   8      InvalidOpcode                               00 00 00 00   data section offset lo (0)     
          3   12     InvalidOpcode                               00 00 00 88   data section offset hi (136)   
          4   16     InvalidOpcode                               00 00 00 00   configurables offset lo (0)    
          5   20     InvalidOpcode                               00 00 00 a0   configurables offset hi (160)  
          6   24     LW { dst: 0x3f, addr: 0x3c, offset: 1 }     5d ff c0 01                                  
          7   28     ADD { dst: 0x3f, lhs: 0x3f, rhs: 0x3c }     10 ff ff 00                                  
          8   32     MOVE { dst: 0x3b, src: 0x5 }                1a ec 50 00                                  
          9   36     CFEI { amount: 56 }                         91 00 00 38                                  
         10   40     SW { addr: 0x3b, value: 0xf, offset: 5 }    5f ec f0 05                                  
         11   44     LW { dst: 0x10, addr: 0x3b, offset: 5 }     5d 43 b0 05                                  
         12   48     ADDI { dst: 0x11, lhs: 0x3f, rhs: 0 }       50 47 f0 00                                  
         13   52     LW { dst: 0x11, addr: 0x11, offset: 0 }     5d 45 10 00                                  
         14   56     OR { dst: 0x10, lhs: 0x10, rhs: 0x11 }      1d 41 04 40                                  
         15   60     SW { addr: 0x3b, value: 0x10, offset: 2 }   5f ed 00 02                                  
         16   64     LW { dst: 0x10, addr: 0x3b, offset: 2 }     5d 43 b0 02                                  
         17   68     FLAG { value: 0x10 }                        48 40 00 00                                  
         18   72     LW { dst: 0x10, addr: 0x3b, offset: 5 }     5d 43 b0 05                                  
         19   76     SW { addr: 0x3b, value: 0x10, offset: 0 }   5f ed 00 00                                  
         20   80     LW { dst: 0x10, addr: 0x3f, offset: 1 }     5d 43 f0 01                                  
         21   84     SW { addr: 0x3b, value: 0x10, offset: 6 }   5f ed 00 06                                  
         22   88     SW { addr: 0x3b, value: 0x1, offset: 4 }    5f ec 10 04                                  
         23   92     LW { dst: 0x10, addr: 0x3b, offset: 6 }     5d 43 b0 06                                  
         24   96     LW { dst: 0x11, addr: 0x3b, offset: 4 }     5d 47 b0 04                                  
         25   100    ADD { dst: 0x10, lhs: 0x10, rhs: 0x11 }     10 41 04 40                                  
         26   104    SW { addr: 0x3b, value: 0x10, offset: 1 }   5f ed 00 01                                  
         27   108    ADDI { dst: 0x10, lhs: 0x3f, rhs: 16 }      50 43 f0 10                                  
         28   112    LW { dst: 0x10, addr: 0x10, offset: 0 }     5d 41 00 00                                  
         29   116    AND { dst: 0x10, lhs: 0xf, rhs: 0x10 }      11 40 f4 00                                  
         30   120    SW { addr: 0x3b, value: 0x10, offset: 3 }   5f ed 00 03                                  
         31   124    LW { dst: 0x10, addr: 0x3b, offset: 3 }     5d 43 b0 03                                  
         32   128    FLAG { value: 0x10 }                        48 40 00 00                                  
         33   132    RET { value: 0x0 }                          24 00 00 00                                  
         34   136    InvalidOpcode                               00 00 00 00                                  
         35   140    InvalidOpcode                               00 00 00 02                                  
         36   144    InvalidOpcode                               ff ff ff ff                                  
         37   148    InvalidOpcode                               ff ff ff ff                                  
         38   152    InvalidOpcode                               ff ff ff ff                                  
         39   156    InvalidOpcode                               ff ff ff fd                                                                 

Solution you'd like

The exact same logic could be achieved straightforwardly with something like this. Observe that no allocations are needed.

// let _ = disable_panic_on_overflow();
move $$tmp1 $flags // backup flags
ori $$tmp2 $flags 2 // set the relevent bit
flag $$tmp2
// let _bar = u64::max() + 1;
not $$tmp3 $zero // set $$tmp3 to u64::MAX
addi $$tmp4 $$tmp3 1 // this panics
// enable_panic_on_overflow();
not $$tmp5 $zero // set $$tmp5 to u64::MAX
xori $$tmp5 $$tmp5 2 // unset the relevant bit
and $$tmp6 $$tmp5 $flags
flag $$tmp6

Notes

Several other optimizations are possible here as well, but the unnecessary stack use seems to be so far the biggest issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    bigthis task is hard and will take a whilecompiler: irIRgen and sway-ir including optimization passescompiler: static-analysisenhancementNew feature or requesttriageThis issue was opened with a template and needs to be triaged by code owners.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions