Skip to content

Commit 65d6520

Browse files
authored
Improve array decode (#7342)
## Description Continuation of #6860. This PR implements multiple small features focusing on improving `AbiDecode` for arrays. 1 - Before this PR, the implementation of `AbiDecode` for arrays was decoding the first element and creating a "repeat array" with it. Depending on the array length, the initialisation would be five `store`s or a loop copying the first item over all slots. Now we create a "repeat array" of zeros of the required size. This will be initialised with just one `MCLI`/`MCL`. And then we transmute this into the desired array type. The final `ASM` is still far from ideal. But will improve with future optimizations. ``` pshl i15 ; save registers 16..40 pshh i524288 ; save registers 40..64 move $$locbase $sp ; save locals base register for function transmute_by_reference_7 cfei i144 ; allocate 144 bytes for locals and 0 slots for call arguments move $r0 $$arg0 ; save argument 0 (__ret_value) move $r1 $$reta ; save return address mcli $$locbase i64 ; clear memory [u8; 64], 64 bytes addi $r2 $$locbase i72 ; get offset to local __ptr [u8; 64] mcpi $r2 $$locbase i64 ; copy memory addi $r2 $$locbase i72 ; get offset to local __ptr [u8; 64] addi $r3 $$locbase i64 ; get offset to local __ptr __ptr [u8; 64] sw $$locbase $r2 i8 ; store word addi $r2 $$locbase i136 ; get offset to local __ptr __ptr u256 mcpi $r2 $r3 i8 ; copy memory lw $r2 $$locbase i17 ; load word mcpi $r0 $r2 i32 ; copy memory move $$retv $r0 ; set return value cfsi i144 ; free 144 bytes for locals and 0 slots for extra call arguments move $$reta $r1 ; restore return address poph i524288 ; restore registers 40..64 popl i15 ; restore registers 16..40 jal $zero $$reta i0 ; return from call ``` 2 - Array lengths can now be specified using `const` variables. One limitation is that these lengths must be limited to simple `const` variables, local or global, but associated `consts` are still not working. Another limitation is that we can't unify arrays lengths that use variables and literals. For example: `let _: [u64; 1] = [0u64; A]`; ```sway const GLOBAL_A: u64 = 1; #[inline(never)] fn arrays_with_const_length() { const A = 1; const B = A + 1; let _ = [0u64; A]; let _: [u64; A] = [0u64]; let _ = [0u64; GLOBAL_A]; let _ = [0u64; B]; let _: [u64; B] = [0u64, 1u64]; } ``` 3 - `const` declarations can now use `const generics` in their expressions. ```sway #[inline(never)] fn const_with_const_generics<const B: u64>() { const A: u64 = B + 1; __dbg(A); } ``` 4 - `__transmute` can now transmute references. ```sway fn transmute_by_reference() -> u256 { let mut bytes = [0u8; 32]; let v: &mut u256 = __transmute::<&mut [u8; 32], &mut u256>(&mut bytes); *v } ``` 5 - Snapshot tests now support a "filter-fn" command, which will parse the compiler output and focus on the specified fns. This will help by eliminating clutter from the snapshots. Its first argument is the project that we want to filter, and the second is a comma-separated list of all function names we want. In the example below, `{name}` is the name of the project where the `snapshot.toml` lives. ```toml cmds = [ "forc build --path {root} --ir final --asm final | filter-fn {name} transmute_by_reference_7", ] ``` ## convert_resolved_type_info One of the biggest changes was that `convert_resolved_type_info` needs access to the "context" that is being compiled, as types can include expressions. At the moment, only `const variables` and `const generics variables`. But soon enough, we will be able to write more complex expressions, and we will need full access to available symbols. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers.
1 parent c2696d6 commit 65d6520

File tree

43 files changed

+3421
-1048
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3421
-1048
lines changed

sway-core/src/asm_generation/fuel/fuel_asm_builder.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,10 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
13511351
byte_offs,
13521352
instr_reg.clone(),
13531353
Some(&base_reg),
1354-
"get offset to local",
1354+
format!(
1355+
"get offset to local {}",
1356+
local_var.get_type(self.context).as_string(self.context)
1357+
),
13551358
owning_span,
13561359
);
13571360
}

sway-core/src/decl_engine/id.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::{
22
decl_engine::*,
33
engine_threading::*,
44
language::ty::{
5-
TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl,
6-
TyTraitFn, TyTraitType, TyTypeAliasDecl,
5+
TyConstantDecl, TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait,
6+
TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType, TyTypeAliasDecl,
77
},
88
type_system::*,
99
};
@@ -240,6 +240,19 @@ impl SubstTypes for DeclId<TyTraitType> {
240240
}
241241
}
242242

243+
impl SubstTypes for DeclId<TyConstantDecl> {
244+
fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
245+
let decl_engine = ctx.engines.de();
246+
let mut decl = (*decl_engine.get(self)).clone();
247+
if decl.subst(ctx).has_changes() {
248+
decl_engine.replace(*self, decl);
249+
HasChanges::Yes
250+
} else {
251+
HasChanges::No
252+
}
253+
}
254+
}
255+
243256
impl<T> DeclId<T>
244257
where
245258
DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,

sway-core/src/ir_generation/compile.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,11 @@ pub(crate) fn compile_configurables(
364364
let decl = engines.de().get(decl_id);
365365

366366
let ty = convert_resolved_type_id(
367-
engines.te(),
368-
engines.de(),
367+
engines,
369368
context,
369+
md_mgr,
370+
module,
371+
None,
370372
decl.type_ascription.type_id(),
371373
&decl.type_ascription.span(),
372374
)
@@ -577,9 +579,6 @@ fn compile_fn(
577579
test_decl_ref: Option<DeclRefFunction>,
578580
cache: &mut CompiledFunctionCache,
579581
) -> Result<Function, Vec<CompileError>> {
580-
let type_engine = engines.te();
581-
let decl_engine = engines.de();
582-
583582
let inline = ast_fn_decl.inline();
584583
let trace = ast_fn_decl.trace();
585584
let ty::TyFunctionDecl {
@@ -615,9 +614,11 @@ fn compile_fn(
615614
.map(|param| {
616615
// Convert to an IR type.
617616
convert_resolved_type_id(
618-
type_engine,
619-
decl_engine,
617+
engines,
620618
context,
619+
md_mgr,
620+
module,
621+
None,
621622
param.type_argument.type_id(),
622623
&param.type_argument.span(),
623624
)
@@ -643,9 +644,11 @@ fn compile_fn(
643644
.map_err(|err| vec![err])?;
644645

645646
let ret_type = convert_resolved_type_id(
646-
type_engine,
647-
decl_engine,
647+
engines,
648648
context,
649+
md_mgr,
650+
module,
651+
None,
649652
return_type.type_id(),
650653
&return_type.span(),
651654
)

sway-core/src/ir_generation/const_eval.rs

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ fn create_array_from_vec(
265265
element_types: Vec<crate::TypeId>,
266266
element_vals: Vec<Constant>,
267267
) -> Option<Constant> {
268-
let te = lookup.engines.te();
269268
assert!({
270269
let unify_check = UnifyCheck::coercion(lookup.engines);
271270
element_types
@@ -274,9 +273,10 @@ fn create_array_from_vec(
274273
});
275274

276275
let arr = create_array_aggregate(
277-
te,
278-
lookup.engines.de(),
276+
lookup.engines,
279277
lookup.context,
278+
lookup.md_mgr,
279+
lookup.module,
280280
elem_type,
281281
element_types.len().try_into().unwrap(),
282282
)
@@ -357,22 +357,15 @@ fn const_eval_typed_expr(
357357

358358
res?
359359
}
360-
ty::TyExpressionVariant::ConstantExpression {
361-
decl: const_decl, ..
362-
} => {
363-
let call_path = &const_decl.call_path;
360+
ty::TyExpressionVariant::ConstantExpression { decl, .. } => {
361+
let call_path = &decl.call_path;
364362
let name = &call_path.suffix;
365-
366363
match known_consts.get(name) {
367-
// 1. Check if name/call_path is in known_consts.
368-
Some(cvs) => Some(*cvs),
369-
None => {
370-
// 2. Check if name is a global constant.
371-
(lookup.lookup)(lookup, call_path, &Some(*const_decl.clone()))
372-
.ok()
373-
.flatten()
374-
.and_then(|v| v.get_constant(lookup.context).cloned())
375-
}
364+
Some(constant) => Some(*constant),
365+
None => (lookup.lookup)(lookup, call_path, &Some(*decl.clone()))
366+
.ok()
367+
.flatten()
368+
.and_then(|v| v.get_constant(lookup.context).cloned()),
376369
}
377370
}
378371
ty::TyExpressionVariant::ConfigurableExpression { span, .. } => {
@@ -419,9 +412,10 @@ fn const_eval_typed_expr(
419412
assert!(field_vals.len() == fields.len());
420413

421414
get_struct_for_types(
422-
lookup.engines.te(),
423-
lookup.engines.de(),
415+
lookup.engines,
424416
lookup.context,
417+
lookup.md_mgr,
418+
lookup.module,
425419
&field_types,
426420
)
427421
.map_or(None, |struct_ty| {
@@ -456,9 +450,10 @@ fn const_eval_typed_expr(
456450
assert!(field_vals.len() == fields.len());
457451

458452
create_tuple_aggregate(
459-
lookup.engines.te(),
460-
lookup.engines.de(),
453+
lookup.engines,
461454
lookup.context,
455+
lookup.md_mgr,
456+
lookup.module,
462457
&field_types,
463458
)
464459
.map_or(None, |tuple_ty| {
@@ -525,9 +520,10 @@ fn const_eval_typed_expr(
525520
} => {
526521
let enum_decl = lookup.engines.de().get_enum(enum_ref);
527522
let aggregate = create_tagged_union_type(
528-
lookup.engines.te(),
529-
lookup.engines.de(),
523+
lookup.engines,
530524
lookup.context,
525+
lookup.md_mgr,
526+
lookup.module,
531527
&enum_decl.variants,
532528
);
533529

@@ -1177,9 +1173,11 @@ fn const_eval_intrinsic(
11771173
Intrinsic::SizeOfType => {
11781174
let targ = &intrinsic.type_arguments[0];
11791175
let ir_type = convert_resolved_type_id(
1180-
lookup.engines.te(),
1181-
lookup.engines.de(),
1176+
lookup.engines,
11821177
lookup.context,
1178+
lookup.md_mgr,
1179+
lookup.module,
1180+
lookup.function_compiler,
11831181
targ.type_id(),
11841182
&targ.span(),
11851183
)
@@ -1195,9 +1193,11 @@ fn const_eval_intrinsic(
11951193
let val = &intrinsic.arguments[0];
11961194
let type_id = val.return_type;
11971195
let ir_type = convert_resolved_type_id(
1198-
lookup.engines.te(),
1199-
lookup.engines.de(),
1196+
lookup.engines,
12001197
lookup.context,
1198+
lookup.md_mgr,
1199+
lookup.module,
1200+
lookup.function_compiler,
12011201
type_id,
12021202
&val.span,
12031203
)
@@ -1211,9 +1211,11 @@ fn const_eval_intrinsic(
12111211
Intrinsic::SizeOfStr => {
12121212
let targ = &intrinsic.type_arguments[0];
12131213
let ir_type = convert_resolved_type_id(
1214-
lookup.engines.te(),
1215-
lookup.engines.de(),
1214+
lookup.engines,
12161215
lookup.context,
1216+
lookup.md_mgr,
1217+
lookup.module,
1218+
lookup.function_compiler,
12171219
targ.type_id(),
12181220
&targ.span(),
12191221
)
@@ -1229,9 +1231,11 @@ fn const_eval_intrinsic(
12291231
Intrinsic::AssertIsStrArray => {
12301232
let targ = &intrinsic.type_arguments[0];
12311233
let ir_type = convert_resolved_type_id(
1232-
lookup.engines.te(),
1233-
lookup.engines.de(),
1234+
lookup.engines,
12341235
lookup.context,
1236+
lookup.md_mgr,
1237+
lookup.module,
1238+
lookup.function_compiler,
12351239
targ.type_id(),
12361240
&targ.span(),
12371241
)
@@ -1547,19 +1551,23 @@ fn const_eval_intrinsic(
15471551
Intrinsic::Transmute => {
15481552
let src_type = &intrinsic.type_arguments[0];
15491553
let src_ir_type = convert_resolved_type_id(
1550-
lookup.engines.te(),
1551-
lookup.engines.de(),
1554+
lookup.engines,
15521555
lookup.context,
1556+
lookup.md_mgr,
1557+
lookup.module,
1558+
lookup.function_compiler,
15531559
src_type.type_id(),
15541560
&src_type.span(),
15551561
)
15561562
.unwrap();
15571563

15581564
let dst_type = &intrinsic.type_arguments[1];
15591565
let dst_ir_type = convert_resolved_type_id(
1560-
lookup.engines.te(),
1561-
lookup.engines.de(),
1566+
lookup.engines,
15621567
lookup.context,
1568+
lookup.md_mgr,
1569+
lookup.module,
1570+
lookup.function_compiler,
15631571
dst_type.type_id(),
15641572
&dst_type.span(),
15651573
)

0 commit comments

Comments
 (0)