Skip to content

Commit bcd1cf9

Browse files
xunilrjJoshuaBattyIGI-111
authored
match for string slices (#6202)
## Description This PR implements `match` for string slices including radix trie optimization and is a task of #5110. For example a simple `match` like ``` fn return_match_on_str_slice(param: str) -> u64 { match param { "get_a" => { 1u64 }, "get_a_b" => { 2u64 }, "get_b" => { 3u64 }, _ => { 1000u64 }, } } ``` will generate code following this logic: ``` let packed_string = "get_a_b" if str.len() == 5 if str[0..4] == "get_" at packed_string[0] if str[4..5] == "b" at packed_string[6] return branch 2 if str[4..5] == "a" at packed_string[4] return branch 0 return wildcard branch return wildcard branch if str.len() == 7 if str[0..7] == "get_a_b" at packed_string[0] return branch 1 return wildcard branch return wildcard branch ``` In logical terms, this boils down to checking the length and an `O(N)` check on the string. Albeit the bytecode will be more complex because of all the branches. Another interesting optimization is the "packed string literal" that coalesces all "match arms string slices" into just one string. In the case above, given that one of the arms contains all the necessary strings for all other comparisons, we will create just one string literal. Saving a lot of bytes in the data section. The section below describes how `rustc` deals with this desugaring. I think these choices make more sense to us for two reasons: 1 - Avoid testing common prefixes multiple times will spend less gas in general (needs more testing); 2 - packing all strings will decrease the data section size. This is the bytecode generated in this case: ``` fn return_match_on_str_slice(param: str) -> u64 { match param { "get_a" => { 1u64 }, "get_a_b" => { 2u64 }, "get_b" => { 3u64 }, _ => { 1000u64 }, } } @ /home/xunilrj/github/sway/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw:22:1 0x0000017c PSHL 0xf ;; [149, 0, 0, 15] 0x00000180 PSHH 0x80000 ;; [150, 8, 0, 0] 0x00000184 MOVE R59 $sp ;; [26, 236, 80, 0] 0x00000188 CFEI 0x90 ;; [145, 0, 0, 144] 0x0000018c MOVE $writable R58 ;; [26, 67, 160, 0] 0x00000190 MOVE R19 R62 ;; [26, 79, 224, 0] match param { "get_a" => { 1u64 }, "get_a_b" => { 2u64 }, "get_b" => { 3u64 }, _ => { 1000u64 }, } @ /home/xunilrj/github/sway/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw:23:5 0x00000194 ADDI R17 R59 0x80 ;; 0x00000198 MOVI R18 0x10 ;; 0x0000019c MCP R17 $writable R18 ;; 0x000001a0 MOVI R17 0x7 ;; 0x7 = "get_a_b".len() @ <autogenerated>:1:1 0x000001a4 LW $writable R59 0x11 ;; R59 + 0x11 = a.len() 0x000001a8 EQ $writable $writable R17 ;; a.len() == 0x7 0x000001ac JNZF $writable $zero 0x3c ;; if false jump to 2a0? 0x000001b0 MOVI R17 0x5 ;; we have two arms with length equals 0x5 0x000001b4 LW $writable R59 0x11 ;; R59 + 0x11 = a.len() 0x000001b8 EQ $writable $writable R17 ;; a.len() == 0x5 0x000001bc MOVI R17 0x3e8 ;; 0x3e8 = 1000 (wildcard return value) 0x000001c0 JNZF $writable $zero 0x1 ;; if true jump to 1c8 0x000001c4 JMPF $zero 0x35 ;; if false jump to 29c (will return R17) 0x000001c8 LW $writable R63 0x3 ;; R63 = start of data section, will load 13c 0x000001cc ADD $writable $writable $pc ;; $writable = 0x308 = packed strings 0x000001d0 ADDI R17 R59 0x20 ;; 0x000001d4 SW R59 $writable 0x4 ;; R59 + 0x4 = packed strings 0x000001d8 MOVI $writable 0x7 ;; 0x000001dc SW R59 $writable 0x5 ;; R59 + 0x5 = 0x7 0x000001e0 ADDI $writable R59 0x30 ;; 0x000001e4 MOVI R18 0x10 ;; 0x000001e8 MCP $writable R17 R18 ;; R59 + 0x30 = R59 + 0x20 0x000001ec MOVI R18 0x4 ;; 0x4 = "get_".len() 0x000001f0 LW $writable R59 0x10 ;; 0x000001f4 ADDI $writable $writable 0x0 ;; 0x000001f8 LW R17 R59 0x6 ;; R17 = a.ptr() 0x000001fc ADDI R17 R17 0x0 ;; 0x00000200 MEQ $writable $writable R17 R18 ;; a[0..4] = packed[0..4] 0x00000204 MOVI R17 0x3e8 ;; 0x3e8 = 1000 (wildcard return value) 0x00000208 JNZF $writable $zero 0x1 ;; if true jump to 210 0x0000020c JMPF $zero 0x23 ;; if false jump to 29c (will return R17) .... .data_section: 0x00000300 .bytes as hex ([]), len i0, as ascii "" 0x00000300 .word i18446744073709486084, as hex be bytes ([FF, FF, FF, FF, FF, FF, 00, 04]) 0x00000308 .bytes as hex ([67, 65, 74, 5F, 61, 5F, 62]), len i7, as ascii "get_a_b" 0x00000310 .word i500, as hex be bytes ([00, 00, 00, 00, 00, 00, 01, F4]) 0x00000318 .word i316, as hex be bytes ([00, 00, 00, 00, 00, 00, 01, 3C]) 0x00000320 .word i244, as hex be bytes ([00, 00, 00, 00, 00, 00, 00, F4]) 0x00000328 .word i176, as hex be bytes ([00, 00, 00, 00, 00, 00, 00, B0]) 0x00000330 .word i100, as hex be bytes ([00, 00, 00, 00, 00, 00, 00, 64]) ``` ## How `rustc` desugar `match` For comparison, this is the generated ASM with comments on how Rust tackles this. First, this is the function used: ``` #[inline(never)] fn f(a: &str) -> u64 { match a { "get_method" => 0, "get_tokens" => 1, "get_something_else" => 2, "get_tokens_2" => 3, "clear" => 4, "get_m" => 5, _ => 6, } } ``` This is the LLVM IR generated. There is a match on the length of each string slice arms. The valid range is (5, 18), everything outside of this is the wildcard match arm. This range will be important later. ``` efine internal fastcc noundef i64 @example::f::hdb860bcd6d383112(ptr noalias nocapture noundef nonnull readonly align 1 %a.0, i64 noundef %a.1) unnamed_addr { start: switch i64 %a.1, label %bb13 [ i64 10, label %"_ZN73_$LT$$u5b$A$u5d$$u20$as$u20$core..slice..cmp..SlicePartialEq$LT$B$GT$$GT$5equal17h510120b4d3581de7E.exit" i64 18, label %"_ZN73_$LT$$u5b$A$u5d$$u20$as$u20$core..slice..cmp..SlicePartialEq$LT$B$GT$$GT$5equal17h510120b4d3581de7E.exit30" i64 12, label %"_ZN73_$LT$$u5b$A$u5d$$u20$as$u20$core..slice..cmp..SlicePartialEq$LT$B$GT$$GT$5equal17h510120b4d3581de7E.exit35" i64 5, label %"_ZN73_$LT$$u5b$A$u5d$$u20$as$u20$core..slice..cmp..SlicePartialEq$LT$B$GT$$GT$5equal17h510120b4d3581de7E.exit40" ] ``` this is how "f" is called ``` mov rbx, qword ptr [rsp + 32] mov r14, qword ptr [rsp + 40] mov rsi, qword ptr [rsp + 48] <- length of the string slice mov rdi, r14 <- ptr to string slice call _ZN4main1f17h126a5dfd4e318ebcE ``` this is `f` body. `ja .LBB8_12` jumps into a simple return, returning EAX as 6. It is the wildcard return value. The cleverness of this is that when `RSI` is smaller than 5, it will become negative (because of `add rsi, -5`, wrapping into huge unsigned ints, and will also trigger `JA` (which stands for `Jump Above`), effectively jumping when the slice length is outside of the expected range which is (5, 18). After that, it uses a jump table based on the string length minus 5. Everywhere the string length is invalid, the jump address is `LBB8_12`., still returning `EAX` as 6. ``` _ZN4main1f17h126a5dfd4e318ebcE: .cfi_startproc mov eax, 6 add rsi, -5 cmp rsi, 13 ja .LBB8_12 lea rcx, [rip + .LJTI8_0] movsxd rdx, dword ptr [rcx + 4*rsi] add rdx, rcx jmp rdx ``` ``` .LBB8_12: ret ``` This is the jump table used: ``` .LJTI8_0: .long .LBB8_9-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_2-.LJTI8_0 <- 5th entry is length = 10 (remember we add -5 to the length) .long .LBB8_12-.LJTI8_0 .long .LBB8_8-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_12-.LJTI8_0 .long .LBB8_6-.LJTI8_0 ``` The interesting entry is entry 5, which has two strings: "get_method" and "get_tokens". Here we can see that `rust` actually compares the complete string slice twice. Even though they have an intersection. ``` .LBB8_2: movabs rcx, 7526752397670245735=6874656D5F746567="htem_teg" (inverted "get_meth") xor rcx, qword ptr [rdi] movzx edx, word ptr [rdi + 8] xor rdx, 25711=646F="do" (inverted "od") or rdx, rcx je .LBB8_3 movabs rcx, 7308057365947114855=656B6F745F746567="ekot_teg" (inverted "get_toke") xor rcx, qword ptr [rdi] movzx edx, word ptr [rdi + 8] xor rdx, 29550=736E="sn" (inverted "ns") or rdx, rcx je .LBB8_5 ``` ``` .LBB8_3: xor eax, eax <- returns 0 ret ``` ``` .LBB8_5: mov eax, 1 <- returns 1 ret ``` This is comparable to what `clang` is doing: rust-lang/rust#61961 ## Code and Bytecode This PR also implements code printing when printing bytecode. For now this is only enable for tests. It gnerates something like: ``` match param { "get_a" => { 1u64 }, "get_a_b" => { 2u64 }, "get_b" => { 3u64 }, _ => { 1000u64 }, } @ /home/xunilrj/github/sway/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_all/src/main.sw:23:5 0x00000194 ADDI R17 R59 0x80 ;; 0x00000198 MOVI R18 0x10 ;; 0x0000019c MCP R17 $writable R18 ;; 0x000001a0 MOVI R17 0x7 ;; 0x7 = "get_a_b".len() @ <autogenerated>:1:1 0x000001a4 LW $writable R59 0x11 ;; R59 + 0x11 = a.len() 0x000001a8 EQ $writable $writable R17 ;; a.len() == 0x7 ``` As we can see, not great, but helpful nonetheless. We can (should?) improve this by better "carrying" spans in all transformations and lowerings. ## Checklist - [x] I have linked to any relevant issues. - [x] 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. --------- Co-authored-by: Joshua Batty <[email protected]> Co-authored-by: IGI-111 <[email protected]>
1 parent 00a9254 commit bcd1cf9

File tree

26 files changed

+805
-73
lines changed

26 files changed

+805
-73
lines changed

forc-pkg/src/manifest/build_profile.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub struct BuildProfile {
2424
#[serde(default)]
2525
pub print_bytecode: bool,
2626
#[serde(default)]
27+
pub print_bytecode_spans: bool,
28+
#[serde(default)]
2729
pub terse: bool,
2830
#[serde(default)]
2931
pub time_phases: bool,
@@ -57,6 +59,7 @@ impl BuildProfile {
5759
print_ir: PrintIr::default(),
5860
print_asm: PrintAsm::default(),
5961
print_bytecode: false,
62+
print_bytecode_spans: false,
6063
terse: false,
6164
time_phases: false,
6265
metrics_outfile: None,
@@ -80,6 +83,7 @@ impl BuildProfile {
8083
print_ir: PrintIr::default(),
8184
print_asm: PrintAsm::default(),
8285
print_bytecode: false,
86+
print_bytecode_spans: false,
8387
terse: false,
8488
time_phases: false,
8589
metrics_outfile: None,
@@ -152,6 +156,7 @@ mod tests {
152156
print_ir: PrintIr::r#final(),
153157
print_asm: PrintAsm::all(),
154158
print_bytecode: true,
159+
print_bytecode_spans: false,
155160
terse: true,
156161
time_phases: true,
157162
metrics_outfile: Some("metrics_outfile".into()),

forc-pkg/src/pkg.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ pub struct PrintOpts {
263263
pub asm: PrintAsm,
264264
/// Print the bytecode. This is the final output of the compiler.
265265
pub bytecode: bool,
266+
/// Print the original source code together with bytecode.
267+
pub bytecode_spans: bool,
266268
/// Print the generated Sway IR (Intermediate Representation).
267269
pub ir: PrintIr,
268270
/// Output build errors and warnings in reverse order.
@@ -1557,7 +1559,10 @@ pub fn sway_build_config(
15571559
.with_print_dca_graph(build_profile.print_dca_graph.clone())
15581560
.with_print_dca_graph_url_format(build_profile.print_dca_graph_url_format.clone())
15591561
.with_print_asm(build_profile.print_asm)
1560-
.with_print_bytecode(build_profile.print_bytecode)
1562+
.with_print_bytecode(
1563+
build_profile.print_bytecode,
1564+
build_profile.print_bytecode_spans,
1565+
)
15611566
.with_print_ir(build_profile.print_ir.clone())
15621567
.with_include_tests(build_profile.include_tests)
15631568
.with_time_phases(build_profile.time_phases)
@@ -2087,6 +2092,7 @@ fn build_profile_from_opts(
20872092
profile.print_ir |= print.ir.clone();
20882093
profile.print_asm |= print.asm;
20892094
profile.print_bytecode |= print.bytecode;
2095+
profile.print_bytecode_spans |= print.bytecode_spans;
20902096
profile.terse |= pkg.terse;
20912097
profile.time_phases |= time_phases;
20922098
if profile.metrics_outfile.is_none() {

forc-plugins/forc-client/src/op/deploy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ fn build_opts_from_cmd(cmd: &cmd::Deploy) -> pkg::BuildOpts {
355355
dca_graph_url_format: cmd.print.dca_graph_url_format.clone(),
356356
asm: cmd.print.asm(),
357357
bytecode: cmd.print.bytecode,
358+
bytecode_spans: false,
358359
ir: cmd.print.ir(),
359360
reverse_order: cmd.print.reverse_order,
360361
},

forc-plugins/forc-client/src/op/run/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts {
231231
dca_graph_url_format: cmd.print.dca_graph_url_format.clone(),
232232
asm: cmd.print.asm(),
233233
bytecode: cmd.print.bytecode,
234+
bytecode_spans: false,
234235
ir: cmd.print.ir(),
235236
reverse_order: cmd.print.reverse_order,
236237
},

forc/src/cli/commands/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ fn opts_from_cmd(cmd: Command) -> forc_test::TestOpts {
242242
dca_graph_url_format: cmd.build.print.dca_graph_url_format.clone(),
243243
asm: cmd.build.print.asm(),
244244
bytecode: cmd.build.print.bytecode,
245+
bytecode_spans: false,
245246
ir: cmd.build.print.ir(),
246247
reverse_order: cmd.build.print.reverse_order,
247248
},

forc/src/ops/forc_build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts {
2626
dca_graph_url_format: cmd.build.print.dca_graph_url_format.clone(),
2727
asm: cmd.build.print.asm(),
2828
bytecode: cmd.build.print.bytecode,
29+
bytecode_spans: false,
2930
ir: cmd.build.print.ir(),
3031
reverse_order: cmd.build.print.reverse_order,
3132
},

forc/src/ops/forc_contract_id.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ fn build_opts_from_cmd(cmd: &ContractIdCommand) -> pkg::BuildOpts {
6161
dca_graph_url_format: cmd.print.dca_graph_url_format.clone(),
6262
asm: cmd.print.asm(),
6363
bytecode: cmd.print.bytecode,
64+
bytecode_spans: false,
6465
ir: cmd.print.ir(),
6566
reverse_order: cmd.print.reverse_order,
6667
},

forc/src/ops/forc_predicate_root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fn build_opts_from_cmd(cmd: PredicateRootCommand) -> pkg::BuildOpts {
3030
dca_graph_url_format: cmd.print.dca_graph_url_format.clone(),
3131
asm: cmd.print.asm(),
3232
bytecode: cmd.print.bytecode,
33+
bytecode_spans: false,
3334
ir: cmd.print.ir(),
3435
reverse_order: cmd.print.reverse_order,
3536
},

sway-core/src/asm_generation/finalized_asm.rs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::{
44
fuel::{checks, data_section::DataSection},
55
ProgramABI, ProgramKind,
66
};
7+
use crate::asm_generation::fuel::data_section::{DataId, Datum, Entry};
78
use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode};
89
use crate::decl_engine::DeclRefFunction;
910
use crate::source_map::SourceMap;
@@ -151,6 +152,13 @@ fn to_bytecode_mut(
151152
println!(";; --- START OF TARGET BYTECODE ---\n");
152153
}
153154

155+
let mut last_span = None;
156+
let mut indentation = if build_config.print_bytecode_spans {
157+
4
158+
} else {
159+
0
160+
};
161+
154162
let mut half_word_ix = 0;
155163
let mut offset_from_instr_start = 0;
156164
for op in ops.iter() {
@@ -165,7 +173,7 @@ fn to_bytecode_mut(
165173
match fuel_op {
166174
Either::Right(data) => {
167175
if build_config.print_bytecode {
168-
print!("{:#010x} ", bytecode.len());
176+
print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len());
169177
println!(
170178
" ;; {:?}",
171179
data
@@ -181,8 +189,45 @@ fn to_bytecode_mut(
181189
}
182190
Either::Left(instructions) => {
183191
for instruction in instructions {
192+
// Print original source span only once
193+
if build_config.print_bytecode_spans {
194+
last_span = match (last_span, &span) {
195+
(None, Some(span)) => {
196+
indentation = 4;
197+
let line_col = span.start_pos().line_col();
198+
println!(
199+
"{} @ {}:{}:{}",
200+
span.as_str(),
201+
span.source_id()
202+
.map(|source_id| source_engine.get_path(source_id))
203+
.map(|x| x.display().to_string())
204+
.unwrap_or("<autogenerated>".to_string()),
205+
line_col.line,
206+
line_col.col
207+
);
208+
Some(span.clone())
209+
}
210+
(Some(last), Some(span)) if last != *span => {
211+
indentation = 4;
212+
let line_col = span.start_pos().line_col();
213+
println!(
214+
"{} @ {}:{}:{}",
215+
span.as_str(),
216+
span.source_id()
217+
.map(|source_id| source_engine.get_path(source_id))
218+
.map(|x| x.display().to_string())
219+
.unwrap_or("<autogenerated>".to_string()),
220+
line_col.line,
221+
line_col.col
222+
);
223+
Some(span.clone())
224+
}
225+
(last, _) => last,
226+
};
227+
}
228+
184229
if build_config.print_bytecode {
185-
print!("{:#010x} ", bytecode.len());
230+
print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len());
186231
print_instruction(&instruction);
187232
}
188233

@@ -202,8 +247,64 @@ fn to_bytecode_mut(
202247
}
203248
}
204249
}
250+
205251
if build_config.print_bytecode {
206-
println!("{}", data_section);
252+
println!(".data_section:");
253+
254+
let offset = bytecode.len();
255+
256+
fn print_entry(indentation: usize, offset: usize, pair: &Entry) {
257+
print!("{}{:#010x} ", " ".repeat(indentation), offset);
258+
259+
match &pair.value {
260+
Datum::Byte(w) => println!(".byte i{w}, as hex {w:02X}"),
261+
Datum::Word(w) => {
262+
println!(".word i{w}, as hex be bytes ({:02X?})", w.to_be_bytes())
263+
}
264+
Datum::ByteArray(bs) => {
265+
print!(".bytes as hex ({bs:02X?}), len i{}, as ascii \"", bs.len());
266+
267+
for b in bs {
268+
print!(
269+
"{}",
270+
if *b == b' ' || b.is_ascii_graphic() {
271+
*b as char
272+
} else {
273+
'.'
274+
}
275+
);
276+
}
277+
println!("\"");
278+
}
279+
Datum::Slice(bs) => {
280+
print!(".slice as hex ({bs:02X?}), len i{}, as ascii \"", bs.len());
281+
282+
for b in bs {
283+
print!(
284+
"{}",
285+
if *b == b' ' || b.is_ascii_graphic() {
286+
*b as char
287+
} else {
288+
'.'
289+
}
290+
);
291+
}
292+
println!("\"");
293+
}
294+
Datum::Collection(els) => {
295+
println!(".collection");
296+
for e in els {
297+
print_entry(indentation + 1, offset, e);
298+
}
299+
}
300+
};
301+
}
302+
303+
for (i, entry) in data_section.value_pairs.iter().enumerate() {
304+
let entry_offset = data_section.data_id_to_offset(&DataId(i as u32));
305+
print_entry(indentation, offset + entry_offset, entry);
306+
}
307+
207308
println!(";; --- END OF TARGET BYTECODE ---\n");
208309
}
209310

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,14 @@ impl AllocatedAbstractInstructionSet {
121121
new_ops.push(AllocatedAbstractOp {
122122
opcode: Either::Left(AllocatedOpcode::PSHL(mask_l)),
123123
comment: "Save registers 16..40".into(),
124-
owning_span: None,
124+
owning_span: op.owning_span.clone(),
125125
});
126126
}
127127
if mask_h.value != 0 {
128128
new_ops.push(AllocatedAbstractOp {
129129
opcode: Either::Left(AllocatedOpcode::PSHH(mask_h)),
130130
comment: "Save registers 40..64".into(),
131-
owning_span: None,
131+
owning_span: op.owning_span.clone(),
132132
});
133133
}
134134
}
@@ -147,14 +147,14 @@ impl AllocatedAbstractInstructionSet {
147147
new_ops.push(AllocatedAbstractOp {
148148
opcode: Either::Left(AllocatedOpcode::POPH(mask_h)),
149149
comment: "Restore registers 40..64".into(),
150-
owning_span: None,
150+
owning_span: op.owning_span.clone(),
151151
});
152152
}
153153
if mask_l.value != 0 {
154154
new_ops.push(AllocatedAbstractOp {
155155
opcode: Either::Left(AllocatedOpcode::POPL(mask_l)),
156156
comment: "Restore registers 16..40".into(),
157-
owning_span: None,
157+
owning_span: op.owning_span.clone(),
158158
});
159159
}
160160
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
274274
function.get_name(self.context)
275275
);
276276

277-
self.cur_bytecode.push(match span {
278-
Some(span) => Op::jump_label_comment(start_label, span, comment),
277+
self.cur_bytecode.push(match &span {
278+
Some(span) => Op::jump_label_comment(start_label, span.clone(), comment),
279279
None => Op::unowned_jump_label_comment(start_label, comment),
280280
});
281281

@@ -285,7 +285,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
285285
self.cur_bytecode.push(Op {
286286
opcode: Either::Right(OrganizationalOp::PushAll(start_label)),
287287
comment: "save all regs".to_owned(),
288-
owning_span: None,
288+
owning_span: span.clone(),
289289
});
290290
}
291291

sway-core/src/build_config.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub struct BuildConfig {
187187
pub(crate) print_dca_graph_url_format: Option<String>,
188188
pub(crate) print_asm: PrintAsm,
189189
pub(crate) print_bytecode: bool,
190+
pub(crate) print_bytecode_spans: bool,
190191
pub(crate) print_ir: PrintIr,
191192
pub(crate) include_tests: bool,
192193
pub(crate) optimization_level: OptLevel,
@@ -234,6 +235,7 @@ impl BuildConfig {
234235
print_dca_graph_url_format: None,
235236
print_asm: PrintAsm::default(),
236237
print_bytecode: false,
238+
print_bytecode_spans: false,
237239
print_ir: PrintIr::default(),
238240
include_tests: false,
239241
time_phases: false,
@@ -264,9 +266,10 @@ impl BuildConfig {
264266
Self { print_asm, ..self }
265267
}
266268

267-
pub fn with_print_bytecode(self, a: bool) -> Self {
269+
pub fn with_print_bytecode(self, bytecode: bool, bytecode_spans: bool) -> Self {
268270
Self {
269-
print_bytecode: a,
271+
print_bytecode: bytecode,
272+
print_bytecode_spans: bytecode_spans,
270273
..self
271274
}
272275
}

sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ use super::{
183183
///
184184
/// # Details
185185
///
186-
/// This algorithm checks is a match expression is exhaustive and if its match
186+
/// This algorithm checks if a match expression is exhaustive and if its match
187187
/// arms are reachable by applying the above definitions of usefulness and
188188
/// witnesses. This algorithm sequentially creates a [WitnessReport] for every
189189
/// match arm by calling *U(P, q)*, where *P* is the [Matrix] of patterns seen

0 commit comments

Comments
 (0)