Skip to content

Commit

Permalink
Allow more than 12b (up to 18b now) stack offsets for local initializ…
Browse files Browse the repository at this point in the history
…ation (FuelLabs#4515)

## Description
When addressing locals (on the stack) for initialization, the address
would be computed as `ADDi stack_base imm`, where `imm` is a 12 bit
integer. That limits our stack size to 4096. This patch changes the
codegen, in the case of a bigger stack offset, to use `MOVi reg imm` to
load a 18b imm into a register, and then `ADD stack_base reg` to compute
the address.

Fixes FuelLabs#4450 

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
vaivaswatha authored May 2, 2023
1 parent 78dd331 commit b3cfea4
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 15 deletions.
54 changes: 39 additions & 15 deletions sway-core/src/asm_generation/fuel/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,22 +696,46 @@ impl<'ir> FuelAsmBuilder<'ir> {
owning_span: None,
});

let var_stack_offs = var_stack_offs * 8;
assert!(var_stack_offs <= compiler_constants::TWELVE_BITS);

// Get the destination on the stack.
// Get the stack offset in bytes rather than words.
let var_stack_off_bytes = var_stack_offs * 8;
let dst_reg = self.reg_seqr.next();
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::ADDI(
dst_reg.clone(),
locals_base_reg.clone(),
VirtualImmediate12 {
value: var_stack_offs as u16,
},
)),
comment: "calc local variable address".to_owned(),
owning_span: None,
});
// Check if we can use the `ADDi` opcode.
if var_stack_off_bytes <= compiler_constants::TWELVE_BITS {
// Get the destination on the stack.
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::ADDI(
dst_reg.clone(),
locals_base_reg.clone(),
VirtualImmediate12 {
value: var_stack_off_bytes as u16,
},
)),
comment: "calc local variable address".to_owned(),
owning_span: None,
});
} else {
assert!(var_stack_off_bytes <= compiler_constants::EIGHTEEN_BITS);
// We can't, so load the immediate into a register and then add.
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::MOVI(
dst_reg.clone(),
VirtualImmediate18 {
value: var_stack_off_bytes as u32,
},
)),
comment: "stack offset of local variable into register".to_owned(),
owning_span: None,
});
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::ADD(
dst_reg.clone(),
locals_base_reg.clone(),
dst_reg.clone(),
)),
comment: "calc local variable address".to_owned(),
owning_span: None,
});
}

if var_word_size == 1 {
// Initialise by value.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[package]]
name = 'core'
source = 'path+from-root-6BF9CEE717879469'

[[package]]
name = 'script_multi_test'
source = 'member'
dependencies = ['std']

[[package]]
name = 'std'
source = 'path+from-root-6BF9CEE717879469'
dependencies = ['core']
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "script_multi_test"

[dependencies]
std = { path = "../../../../../../../sway-lib-std" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
script;

use std::u256::U256;

struct M1 {
a: U256,
b: U256,
c: U256,
d: U256,
}

struct M2 {
a: M1,
b: M1,
c: M1,
d: M1,
}

const m1: M1 = M1 { a: U256::new(), b: U256::new(), c: U256::new(), d: U256::new() };
const m2: M2 = M2 { a: m1, b: m1, c: m1, d: m1 };

const MARR : [M2; 6] =
[
m2, m2, m2, m2, m2, m2
];

fn bar() -> ([M2; 6], [M2; 6]) {
let mut a = MARR;
let mut b = MARR;
a[0].a.b = U256::max();
(a, b)
}

fn main() -> [M2; 6] {
let mut b = bar();
b.0
}

#[test]
fn test() -> [M2; 6] {
let mut b = bar();
assert(b.0[0].a.a == U256::new());
assert(b.0[0].a.b == U256::max());
b.0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
category = "unit_tests_pass"

0 comments on commit b3cfea4

Please sign in to comment.