From 71939d1fa93a335c9c4d5a9f2b5bbb1f657d9006 Mon Sep 17 00:00:00 2001 From: Yi Sun Date: Thu, 2 Jan 2025 18:15:40 -0600 Subject: [PATCH] feat: remove LOADW2 and STOREW2 (#1160) * feat: remove LOADW2 and STOREW2 * chore: remove LOADW2 and STOREW2 from docs * chore: rename eDSL to native * fix: benchmaks do not trigger on extensions --- .github/workflows/benchmarks.yml | 4 +- docs/specs/ISA.md | 10 +- .../src/adapters/loadstore_native_adapter.rs | 100 +++-------- .../native/circuit/src/loadstore/core.rs | 30 +--- .../native/circuit/src/loadstore/tests.rs | 54 +----- .../native/compiler/src/asm/compiler.rs | 162 ++++++++---------- .../native/compiler/src/asm/instruction.rs | 16 -- .../native/compiler/src/conversion/mod.rs | 49 ------ extensions/native/compiler/src/lib.rs | 2 - 9 files changed, 113 insertions(+), 314 deletions(-) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index d8690f02e6..095b94628b 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -7,11 +7,11 @@ on: types: [opened, synchronize, reopened, labeled] branches: ["**"] paths: + - "benchmarks/**" - "crates/circuits/**" - - "crates/vm/**" - "crates/toolchain/**" + - "crates/vm/**" - "extensions/**" - - "benchmarks/**" - ".github/workflows/benchmark-call.yml" - ".github/workflows/benchmarks.yml" workflow_dispatch: diff --git a/docs/specs/ISA.md b/docs/specs/ISA.md index ee1ee016d5..c73ba7d311 100644 --- a/docs/specs/ISA.md +++ b/docs/specs/ISA.md @@ -4,7 +4,7 @@ ## Instruction format -Instructions are encoded as a global opcode (field element) followed by `NUM_OPERANDS = 7` operands (field elements): `opcode, a, b, c, d, e, f, g`. An instruction does not need to use all operands, and trailing unused operands should be set to zero. +Instructions are encoded as a global opcode (field element) followed by `NUM_OPERANDS = 6` operands (field elements): `opcode, a, b, c, d, e, f`. An instruction does not need to use all operands, and trailing unused operands should be set to zero. ## Program ROM @@ -431,11 +431,9 @@ In some instructions below, `W` is a generic parameter for the block size. | -------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | LOAD\ | `a,b,c,d,e` | Set `[a:W]_d = [[c]_d + b:W]_e`. Both `d, e` must be non-zero. | | STORE\ | `a,b,c,d,e` | Set `[[c]_d + b:W]_e = [a:W]_d`. Both `d, e` must be non-zero. | -| LOAD2\ | `a,b,c,d,e,f,g` | Set `[a:W]_d = [[c]_d + [f]_d * g + b:W]_e`. | -| STORE2\ | `a,b,c,d,e,f,g` | Set `[[c]_d + [f]_d * g + b:W]_e = [a:W]_d`. | -| JAL | `a,b,c,d` | Jump to address and link: set `[a]_d = (pc + DEFAULT_PC_STEP)` and `pc = pc + b`. Here `d` must be non-zero. | -| BEQ\ | `a,b,c,d,e` | If `[a:W]_d == [b:W]_e`, then set `pc = pc + c`. | -| BNE\ | `a,b,c,d,e` | If `[a:W]_d != [b:W]_e`, then set `pc = pc + c`. | +| JAL | `a,b,c,d` | Jump to address and link: set `[a]_d = (pc + DEFAULT_PC_STEP)` and `pc = pc + b`. Here `d` must be non-zero. | +| BEQ\ | `a,b,c,d,e` | If `[a:W]_d == [b:W]_e`, then set `pc = pc + c`. | +| BNE\ | `a,b,c,d,e` | If `[a:W]_d != [b:W]_e`, then set `pc = pc + c`. | | HINTSTORE\ | `_,b,c,d,e` | Set `[[c]_d + b:W]_e = next W elements from hint stream`. Both `d, e` must be non-zero. | | PUBLISH | `a,b,_,d,e` | Set the user public output at index `[a]_d` to equal `[b]_e`. Invalid if `[a]_d` is greater than or equal to the configured length of user public outputs. Only valid when continuations are disabled. | | CASTF | `a,b,_,d,e` | Cast a field element represented as `u32` into four bytes in little-endian: Set `[a:4]_d` to the unique array such that `sum_{i=0}^3 [a + i]_d * 2^{8i} = [b]_e` where `[a + i]_d < 2^8` for `i = 0..2` and `[a + 3]_d < 2^6`. This opcode constrains that `[b]_e` must be at most 30-bits. Both `d, e` must be non-zero. | diff --git a/extensions/native/circuit/src/adapters/loadstore_native_adapter.rs b/extensions/native/circuit/src/adapters/loadstore_native_adapter.rs index 37936f0cd8..944cee02df 100644 --- a/extensions/native/circuit/src/adapters/loadstore_native_adapter.rs +++ b/extensions/native/circuit/src/adapters/loadstore_native_adapter.rs @@ -31,9 +31,7 @@ pub struct NativeLoadStoreInstruction { // Absolute opcode number pub opcode: T, pub is_loadw: T, - pub is_loadw2: T, pub is_storew: T, - pub is_storew2: T, pub is_shintw: T, } @@ -43,7 +41,7 @@ impl VmAdapterInterface for NativeLoadStoreAdapterInterface { // TODO[yi]: Fix when vectorizing - type Reads = ([T; 2], T); + type Reads = (T, T); type Writes = [T; NUM_CELLS]; type ProcessedInstruction = NativeLoadStoreInstruction; } @@ -75,8 +73,7 @@ impl NativeLoadStoreAdapterChip { - pub pointer1_read: RecordId, - pub pointer2_read: Option, + pub pointer_read: RecordId, pub data_read: Option, pub write_as: F, pub write_ptr: F, @@ -86,8 +83,6 @@ pub struct NativeLoadStoreReadRecord { pub c: F, pub d: F, pub e: F, - pub f: F, - pub g: F, } #[derive(Clone, Debug)] @@ -105,8 +100,6 @@ pub struct NativeLoadStoreAdapterCols { pub c: T, pub d: T, pub e: T, - pub f: T, - pub g: T, pub data_read_as: T, pub data_read_pointer: T, @@ -114,7 +107,7 @@ pub struct NativeLoadStoreAdapterCols { pub data_write_as: T, pub data_write_pointer: T, - pub pointer_read_aux_cols: [MemoryReadOrImmediateAuxCols; 2], + pub pointer_read_aux_cols: MemoryReadOrImmediateAuxCols, pub data_read_aux_cols: MemoryReadOrImmediateAuxCols, // TODO[yi]: Fix when vectorizing // pub data_read_aux_cols: MemoryReadAuxCols, @@ -154,36 +147,19 @@ impl VmAdapterAir let is_valid = ctx.instruction.is_valid; let is_loadw = ctx.instruction.is_loadw; let is_storew = ctx.instruction.is_storew; - let is_loadw2 = ctx.instruction.is_loadw2; - let is_storew2 = ctx.instruction.is_storew2; let is_shintw = ctx.instruction.is_shintw; // first pointer read is always [c]_d self.memory_bridge .read_or_immediate( MemoryAddress::new(cols.d, cols.c), - ctx.reads.0[0].clone(), + ctx.reads.0.clone(), timestamp + timestamp_delta.clone(), - &cols.pointer_read_aux_cols[0], + &cols.pointer_read_aux_cols, ) .eval(builder, is_valid.clone()); timestamp_delta += is_valid.clone(); - // second pointer read is [f]_d if loadw2 or storew2, otherwise disabled - self.memory_bridge - .read_or_immediate( - MemoryAddress::new(cols.d, cols.f), - ctx.reads.0[1].clone(), - timestamp + timestamp_delta.clone(), - &cols.pointer_read_aux_cols[1], - ) - .eval( - builder, - is_valid.clone() - is_shintw.clone() - is_loadw.clone() - is_storew.clone(), - ); - timestamp_delta += - is_valid.clone() - is_shintw.clone() - is_loadw.clone() - is_storew.clone(); - // TODO[yi]: Remove when vectorizing // read data, disabled if SHINTW // data pointer = [c]_d + [f]_d * g + b, degree 2 @@ -191,14 +167,12 @@ impl VmAdapterAir .when(is_valid.clone() - is_shintw.clone()) .assert_eq( cols.data_read_as, - utils::select::(is_loadw.clone() + is_loadw2.clone(), cols.e, cols.d), + utils::select::(is_loadw.clone(), cols.e, cols.d), ); // TODO[yi]: Do we need to check for overflow? builder.assert_eq( (is_valid.clone() - is_shintw.clone()) * cols.data_read_pointer, - (is_storew.clone() + is_storew2.clone()) * cols.a - + (is_loadw.clone() + is_loadw2.clone()) - * (ctx.reads.0[0].clone() + cols.b + ctx.reads.0[1].clone() * cols.g), + is_storew.clone() * cols.a + is_loadw.clone() * (ctx.reads.0.clone() + cols.b), ); self.memory_bridge .read_or_immediate( @@ -213,14 +187,13 @@ impl VmAdapterAir // data write builder.when(is_valid.clone()).assert_eq( cols.data_write_as, - utils::select::(is_loadw.clone() + is_loadw2.clone(), cols.d, cols.e), + utils::select::(is_loadw.clone(), cols.d, cols.e), ); // TODO[yi]: Do we need to check for overflow? builder.assert_eq( is_valid.clone() * cols.data_write_pointer, - (is_loadw.clone() + is_loadw2.clone()) * cols.a - + (is_storew.clone() + is_storew2.clone() + is_shintw.clone()) - * (ctx.reads.0[0].clone() + cols.b + ctx.reads.0[1].clone() * cols.g), + is_loadw.clone() * cols.a + + (is_storew.clone() + is_shintw.clone()) * (ctx.reads.0.clone() + cols.b), ); self.memory_bridge .write( @@ -235,7 +208,7 @@ impl VmAdapterAir self.execution_bridge .execute_and_increment_or_set_pc( ctx.instruction.opcode, - [cols.a, cols.b, cols.c, cols.d, cols.e, cols.f, cols.g], + [cols.a, cols.b, cols.c, cols.d, cols.e], cols.from_state, timestamp_delta.clone(), (DEFAULT_PC_STEP, ctx.to_pc), @@ -273,36 +246,25 @@ impl VmAdapterChip c, d, e, - f, - g, .. } = *instruction; let local_opcode = NativeLoadStoreOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let read1_as = d; - let read1_ptr = c; - let read2_as = d; - let read2_ptr = f; - - let read1_cell = memory.read_cell(read1_as, read1_ptr); - let read2_cell = match local_opcode { - LOADW2 | STOREW2 => Some(memory.read_cell(read2_as, read2_ptr)), - _ => None, - }; + let read_as = d; + let read_ptr = c; + let read_cell = memory.read_cell(read_as, read_ptr); let (data_read_as, data_write_as) = { match local_opcode { - LOADW | LOADW2 => (e, d), - STOREW | STOREW2 | SHINTW => (d, e), + LOADW => (e, d), + STOREW | SHINTW => (d, e), } }; let (data_read_ptr, data_write_ptr) = { match local_opcode { - LOADW => (read1_cell.1 + b, a), - LOADW2 => (read1_cell.1 + b + read2_cell.unwrap().1 * g, a), - STOREW => (a, read1_cell.1 + b), - STOREW2 => (a, read1_cell.1 + b + read2_cell.unwrap().1 * g), - SHINTW => (a, read1_cell.1 + b), + LOADW => (read_cell.1 + b, a), + STOREW => (a, read_cell.1 + b), + SHINTW => (a, read_cell.1 + b), } }; @@ -312,8 +274,7 @@ impl VmAdapterChip _ => Some(memory.read::<1>(data_read_as, data_read_ptr)), }; let record = NativeLoadStoreReadRecord { - pointer1_read: read1_cell.0, - pointer2_read: read2_cell.map(|x| x.0), + pointer_read: read_cell.0, data_read: data_read.map(|x| x.0), write_as: data_write_as, write_ptr: data_write_ptr, @@ -322,17 +283,9 @@ impl VmAdapterChip c, d, e, - f, - g, }; - Ok(( - ( - [read1_cell.1, read2_cell.map_or(F::ZERO, |x| x.1)], - data_read.map_or(F::ZERO, |x| x.1[0]), - ), - record, - )) + Ok(((read_cell.1, data_read.map_or(F::ZERO, |x| x.1[0])), record)) } fn postprocess( @@ -372,8 +325,6 @@ impl VmAdapterChip cols.c = read_record.c; cols.d = read_record.d; cols.e = read_record.e; - cols.f = read_record.f; - cols.g = read_record.g; let data_read = read_record.data_read.map(|read| memory.record_by_id(read)); if let Some(data_read) = data_read { @@ -388,13 +339,8 @@ impl VmAdapterChip cols.data_write_as = write.address_space; cols.data_write_pointer = write.pointer; - cols.pointer_read_aux_cols[0] = aux_cols_factory - .make_read_or_immediate_aux_cols(memory.record_by_id(read_record.pointer1_read)); - cols.pointer_read_aux_cols[1] = read_record - .pointer2_read - .map_or_else(MemoryReadOrImmediateAuxCols::disabled, |read| { - aux_cols_factory.make_read_or_immediate_aux_cols(memory.record_by_id(read)) - }); + cols.pointer_read_aux_cols = aux_cols_factory + .make_read_or_immediate_aux_cols(memory.record_by_id(read_record.pointer_read)); cols.data_write_aux_cols = aux_cols_factory.make_write_aux_cols(write); } diff --git a/extensions/native/circuit/src/loadstore/core.rs b/extensions/native/circuit/src/loadstore/core.rs index 8015c3d075..0934015a7c 100644 --- a/extensions/native/circuit/src/loadstore/core.rs +++ b/extensions/native/circuit/src/loadstore/core.rs @@ -26,11 +26,9 @@ use super::super::adapters::loadstore_native_adapter::NativeLoadStoreInstruction pub struct NativeLoadStoreCoreCols { pub is_loadw: T, pub is_storew: T, - pub is_loadw2: T, - pub is_storew2: T, pub is_shintw: T, - pub pointer_reads: [T; 2], + pub pointer_read: T, pub data_read: T, pub data_write: [T; NUM_CELLS], } @@ -39,7 +37,7 @@ pub struct NativeLoadStoreCoreCols { pub struct NativeLoadStoreCoreRecord { pub opcode: NativeLoadStoreOpcode, - pub pointer_reads: [F; 2], + pub pointer_read: F, pub data_read: F, pub data_write: [F; NUM_CELLS], } @@ -64,7 +62,7 @@ impl VmCoreAir for NativeLoadStoreCoreAir< where AB: InteractionBuilder, I: VmAdapterInterface, - I::Reads: From<([AB::Expr; 2], AB::Expr)>, + I::Reads: From<(AB::Expr, AB::Expr)>, I::Writes: From<[AB::Expr; NUM_CELLS]>, I::ProcessedInstruction: From>, { @@ -75,13 +73,7 @@ where _from_pc: AB::Var, ) -> AdapterAirContext { let cols: &NativeLoadStoreCoreCols<_, NUM_CELLS> = (*local_core).borrow(); - let flags = [ - cols.is_loadw, - cols.is_storew, - cols.is_loadw2, - cols.is_storew2, - cols.is_shintw, - ]; + let flags = [cols.is_loadw, cols.is_storew, cols.is_shintw]; let is_valid = flags.iter().fold(AB::Expr::ZERO, |acc, &flag| { builder.assert_bool(flag); acc + flag.into() @@ -97,15 +89,13 @@ where AdapterAirContext { to_pc: None, - reads: (cols.pointer_reads.map(Into::into), cols.data_read.into()).into(), + reads: (cols.pointer_read.into(), cols.data_read.into()).into(), writes: cols.data_write.map(Into::into).into(), instruction: NativeLoadStoreInstruction { is_valid, opcode: expected_opcode, is_loadw: cols.is_loadw.into(), is_storew: cols.is_storew.into(), - is_loadw2: cols.is_loadw2.into(), - is_storew2: cols.is_storew2.into(), is_shintw: cols.is_shintw.into(), } .into(), @@ -134,7 +124,7 @@ impl NativeLoadStoreCoreChip { impl, const NUM_CELLS: usize> VmCoreChip for NativeLoadStoreCoreChip where - I::Reads: Into<([F; 2], F)>, + I::Reads: Into<(F, F)>, I::Writes: From<[F; NUM_CELLS]>, { type Record = NativeLoadStoreCoreRecord; @@ -149,7 +139,7 @@ where let Instruction { opcode, .. } = *instruction; let local_opcode = NativeLoadStoreOpcode::from_usize(opcode.local_opcode_idx(self.air.offset)); - let (pointer_reads, data_read) = reads.into(); + let (pointer_read, data_read) = reads.into(); let data_write = if local_opcode == NativeLoadStoreOpcode::SHINTW { let mut streams = self.streams.get().unwrap().lock().unwrap(); @@ -164,7 +154,7 @@ where let output = AdapterRuntimeContext::without_pc(data_write); let record = NativeLoadStoreCoreRecord { opcode: NativeLoadStoreOpcode::from_usize(opcode.local_opcode_idx(self.air.offset)), - pointer_reads, + pointer_read, data_read, data_write, }; @@ -182,11 +172,9 @@ where let cols: &mut NativeLoadStoreCoreCols<_, NUM_CELLS> = row_slice.borrow_mut(); cols.is_loadw = F::from_bool(record.opcode == NativeLoadStoreOpcode::LOADW); cols.is_storew = F::from_bool(record.opcode == NativeLoadStoreOpcode::STOREW); - cols.is_loadw2 = F::from_bool(record.opcode == NativeLoadStoreOpcode::LOADW2); - cols.is_storew2 = F::from_bool(record.opcode == NativeLoadStoreOpcode::STOREW2); cols.is_shintw = F::from_bool(record.opcode == NativeLoadStoreOpcode::SHINTW); - cols.pointer_reads = record.pointer_reads.map(Into::into); + cols.pointer_read = record.pointer_read; cols.data_read = record.data_read; cols.data_write = record.data_write.map(Into::into); } diff --git a/extensions/native/circuit/src/loadstore/tests.rs b/extensions/native/circuit/src/loadstore/tests.rs index f25c1ea622..bfed5311ef 100644 --- a/extensions/native/circuit/src/loadstore/tests.rs +++ b/extensions/native/circuit/src/loadstore/tests.rs @@ -21,14 +21,10 @@ struct TestData { c: F, d: F, e: F, - f: F, - g: F, ad_val: F, cd_val: F, - fd_val: F, data_val: F, is_load: bool, - is_extended: bool, is_hint: bool, } @@ -49,14 +45,7 @@ fn setup() -> (StdRng, VmChipTestBuilder, NativeLoadStoreChip) { } fn gen_test_data(rng: &mut StdRng, is_immediate: bool, opcode: NativeLoadStoreOpcode) -> TestData { - let is_load = matches!( - opcode, - NativeLoadStoreOpcode::LOADW | NativeLoadStoreOpcode::LOADW2 - ); - let is_extended = matches!( - opcode, - NativeLoadStoreOpcode::LOADW2 | NativeLoadStoreOpcode::STOREW2 - ); + let is_load = matches!(opcode, NativeLoadStoreOpcode::LOADW); let a = rng.gen_range(0..1 << 20); let b = rng.gen_range(0..1 << 20); @@ -67,16 +56,6 @@ fn gen_test_data(rng: &mut StdRng, is_immediate: bool, opcode: NativeLoadStoreOp F::from_canonical_u32(rng.gen_range(1..4)) }; let e = F::from_canonical_u32(rng.gen_range(1..4)); - let f = if is_extended { - rng.gen_range(0..1 << 10) - } else { - 0 - }; - let g = if is_extended { - rng.gen_range(0..1 << 10) - } else { - 0 - }; TestData { a: F::from_canonical_u32(a), @@ -84,35 +63,19 @@ fn gen_test_data(rng: &mut StdRng, is_immediate: bool, opcode: NativeLoadStoreOp c: F::from_canonical_u32(c), d, e, - f: F::from_canonical_u32(f), - g: F::from_canonical_u32(g), ad_val: F::from_canonical_u32(111), cd_val: F::from_canonical_u32(222), - fd_val: F::from_canonical_u32(333), data_val: F::from_canonical_u32(444), is_load, - is_extended, is_hint: matches!(opcode, NativeLoadStoreOpcode::SHINTW), } } fn get_data_pointer(data: &TestData) -> F { if data.d != F::ZERO { - data.cd_val - + data.b - + if data.is_extended { - data.g * data.fd_val - } else { - F::ZERO - } + data.cd_val + data.b } else { - data.c - + data.b - + if data.is_extended { - data.g * data.f - } else { - F::ZERO - } + data.c + data.b } } @@ -132,11 +95,6 @@ fn set_values( data.c.as_canonical_u32() as usize, [data.cd_val], ); - tester.write( - data.d.as_canonical_u32() as usize, - data.f.as_canonical_u32() as usize, - [data.fd_val], - ); } if data.is_load { let data_pointer = get_data_pointer(data); @@ -200,8 +158,7 @@ fn set_and_execute( chip, Instruction::from_usize( VmOpcode::with_default_offset(opcode), - [data.a, data.b, data.c, data.d, data.e, data.f, data.g] - .map(|x| x.as_canonical_u32() as usize), + [data.a, data.b, data.c, data.d, data.e].map(|x| x.as_canonical_u32() as usize), ), 0u32, ); @@ -214,13 +171,10 @@ fn rand_native_loadstore_test() { let (mut rng, mut tester, mut chip) = setup(); for _ in 0..20 { set_and_execute(&mut tester, &mut chip, &mut rng, false, STOREW); - set_and_execute(&mut tester, &mut chip, &mut rng, false, STOREW2); set_and_execute(&mut tester, &mut chip, &mut rng, false, SHINTW); set_and_execute(&mut tester, &mut chip, &mut rng, false, LOADW); - set_and_execute(&mut tester, &mut chip, &mut rng, false, LOADW2); set_and_execute(&mut tester, &mut chip, &mut rng, true, STOREW); - set_and_execute(&mut tester, &mut chip, &mut rng, true, STOREW2); set_and_execute(&mut tester, &mut chip, &mut rng, true, SHINTW); } let tester = tester.build().load(chip).finalize(); diff --git a/extensions/native/compiler/src/asm/compiler.rs b/extensions/native/compiler/src/asm/compiler.rs index e5778eda9d..e113814461 100644 --- a/extensions/native/compiler/src/asm/compiler.rs +++ b/extensions/native/compiler/src/asm/compiler.rs @@ -8,7 +8,7 @@ use super::{config::AsmConfig, AssemblyCode, BasicBlock, IndexTriple, ValueOrCon use crate::{ asm::AsmInstruction, ir::{Array, DslIr, Ext, Felt, Ptr, RVar, Usize, Var}, - prelude::{MemIndex, TracedVec}, + prelude::TracedVec, }; /// The memory location for the top of memory @@ -441,22 +441,36 @@ impl + TwoAdicField> AsmCo AsmInstruction::LoadFI(var.fp(), ptr.fp(), index, size, offset), debug_info.clone(), ), - IndexTriple::Var(index, offset, size) => self.push( - AsmInstruction::LoadF(var.fp(), ptr.fp(), index, size, offset), - debug_info.clone(), - ), + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.push( + AsmInstruction::LoadFI(var.fp(), A0, F::ZERO, F::ZERO, offset), + debug_info.clone(), + ) + } }, DslIr::LoadF(var, ptr, index) => match index.fp() { IndexTriple::Const(index, offset, size) => self.push( AsmInstruction::LoadFI(var.fp(), ptr.fp(), index, size, offset), debug_info.clone(), ), - IndexTriple::Var(index, offset, size) => self.push( - AsmInstruction::LoadF(var.fp(), ptr.fp(), index, size, offset), - debug_info.clone(), - ), + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.push( + AsmInstruction::LoadFI(var.fp(), A0, F::ZERO, F::ZERO, offset), + debug_info.clone(), + ) + } + }, + DslIr::LoadE(var, ptr, index) => match index.fp() { + IndexTriple::Const(index, offset, size) => { + self.load_ext(var, ptr.fp(), index * size + offset, debug_info) + } + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.load_ext(var, A0, offset, debug_info) + } }, - DslIr::LoadE(var, ptr, index) => self.load_ext(var, ptr.fp(), index, debug_info), DslIr::LoadHeapPtr(ptr) => self.push( AsmInstruction::AddFI(ptr.fp(), HEAP_PTR, F::ZERO), debug_info, @@ -466,22 +480,36 @@ impl + TwoAdicField> AsmCo AsmInstruction::StoreFI(var.fp(), ptr.fp(), index, size, offset), debug_info.clone(), ), - IndexTriple::Var(index, offset, size) => self.push( - AsmInstruction::StoreF(var.fp(), ptr.fp(), index, size, offset), - debug_info.clone(), - ), + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.push( + AsmInstruction::StoreFI(var.fp(), A0, F::ZERO, F::ZERO, offset), + debug_info.clone(), + ) + } }, DslIr::StoreF(var, ptr, index) => match index.fp() { IndexTriple::Const(index, offset, size) => self.push( AsmInstruction::StoreFI(var.fp(), ptr.fp(), index, size, offset), debug_info.clone(), ), - IndexTriple::Var(index, offset, size) => self.push( - AsmInstruction::StoreF(var.fp(), ptr.fp(), index, size, offset), - debug_info.clone(), - ), + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.push( + AsmInstruction::StoreFI(var.fp(), A0, F::ZERO, F::ZERO, offset), + debug_info.clone(), + ) + } + }, + DslIr::StoreE(var, ptr, index) => match index.fp() { + IndexTriple::Const(index, offset, size) => { + self.store_ext(var, ptr.fp(), index * size + offset, debug_info) + } + IndexTriple::Var(index, offset, size) => { + self.add_scaled(A0, ptr.fp(), index, size, debug_info.clone()); + self.store_ext(var, A0, offset, debug_info) + } }, - DslIr::StoreE(var, ptr, index) => self.store_ext(var, ptr.fp(), index, debug_info), DslIr::StoreHeapPtr(ptr) => self.push( AsmInstruction::AddFI(HEAP_PTR, ptr.fp(), F::ZERO), debug_info, @@ -968,81 +996,33 @@ impl + TwoAdicField> AsmCo } } - fn load_ext( - &mut self, - val: Ext, - addr: i32, - index: MemIndex, - debug_info: Option, - ) { - match index.fp() { - IndexTriple::Const(index, offset, size) => { - for i in 0..EF::D { - self.push( - AsmInstruction::LoadFI( - val.fp() + i as i32, - addr, - index, - size, - offset + F::from_canonical_usize(i), - ), - debug_info.clone(), - ) - } - } - IndexTriple::Var(index, offset, size) => { - for i in 0..EF::D { - self.push( - AsmInstruction::LoadF( - val.fp() + i as i32, - addr, - index, - size, - offset + F::from_canonical_usize(i), - ), - debug_info.clone(), - ) - } - } + fn load_ext(&mut self, val: Ext, addr: i32, offset: F, debug_info: Option) { + for i in 0..EF::D { + self.push( + AsmInstruction::LoadFI( + val.fp() + i as i32, + addr, + F::from_canonical_usize(i), + F::ONE, + offset, + ), + debug_info.clone(), + ) } } - fn store_ext( - &mut self, - val: Ext, - addr: i32, - index: MemIndex, - debug_info: Option, - ) { - match index.fp() { - IndexTriple::Const(index, offset, size) => { - for i in 0..EF::D { - self.push( - AsmInstruction::StoreFI( - val.fp() + i as i32, - addr, - index, - size, - offset + F::from_canonical_usize(i), - ), - debug_info.clone(), - ) - } - } - IndexTriple::Var(index, offset, size) => { - for i in 0..EF::D { - self.push( - AsmInstruction::StoreF( - val.fp() + i as i32, - addr, - index, - size, - offset + F::from_canonical_usize(i), - ), - debug_info.clone(), - ) - } - } + fn store_ext(&mut self, val: Ext, addr: i32, offset: F, debug_info: Option) { + for i in 0..EF::D { + self.push( + AsmInstruction::StoreFI( + val.fp() + i as i32, + addr, + F::from_canonical_usize(i), + F::ONE, + offset, + ), + debug_info.clone(), + ) } } diff --git a/extensions/native/compiler/src/asm/instruction.rs b/extensions/native/compiler/src/asm/instruction.rs index 98c8f11fc7..854b61eadc 100644 --- a/extensions/native/compiler/src/asm/instruction.rs +++ b/extensions/native/compiler/src/asm/instruction.rs @@ -10,13 +10,11 @@ pub enum AsmInstruction { /// Load word (dst, src, var_index, size, offset). /// /// Load a value from the address stored at src(fp) into dst(fp) with given index and offset. - LoadF(i32, i32, i32, F, F), LoadFI(i32, i32, F, F, F), /// Store word (val, addr, var_index, size, offset) /// /// Store a value from val(fp) into the address stored at addr(fp) with given index and offset. - StoreF(i32, i32, i32, F, F), StoreFI(i32, i32, F, F, F), /// Set dst = imm. @@ -149,13 +147,6 @@ impl> AsmInstruction { pub fn fmt(&self, labels: &BTreeMap, f: &mut fmt::Formatter) -> fmt::Result { match self { AsmInstruction::Break(_) => panic!("Unresolved break instruction"), - AsmInstruction::LoadF(dst, src, var_index, size, offset) => { - write!( - f, - "lw ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, var_index, size, offset - ) - } AsmInstruction::LoadFI(dst, src, var_index, size, offset) => { write!( f, @@ -163,13 +154,6 @@ impl> AsmInstruction { dst, src, var_index, size, offset ) } - AsmInstruction::StoreF(dst, src, var_index, size, offset) => { - write!( - f, - "sw ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, var_index, size, offset - ) - } AsmInstruction::StoreFI(dst, src, var_index, size, offset) => { write!( f, diff --git a/extensions/native/compiler/src/conversion/mod.rs b/extensions/native/compiler/src/conversion/mod.rs index e92e6c3b66..eb2a25c7a2 100644 --- a/extensions/native/compiler/src/conversion/mod.rs +++ b/extensions/native/compiler/src/conversion/mod.rs @@ -83,29 +83,6 @@ fn inst_med( } } -#[allow(clippy::too_many_arguments)] -fn inst_large( - opcode: VmOpcode, - a: F, - b: F, - c: F, - d: AS, - e: AS, - f: F, - g: F, -) -> Instruction { - Instruction { - opcode, - a, - b, - c, - d: d.to_field(), - e: e.to_field(), - f, - g, - } -} - #[derive(Clone, Copy)] #[repr(u8)] enum AS { @@ -354,19 +331,6 @@ fn convert_instruction>( ) -> Program { let instructions = match instruction { AsmInstruction::Break(_) => panic!("Unresolved break instruction"), - AsmInstruction::LoadF(dst, src, index, size, offset) => vec![ - // mem[dst] <- mem[mem[src] + mem[index] * size + offset] - inst_large( - options.opcode_with_offset(NativeLoadStoreOpcode::LOADW2), - i32_f(dst), - offset, - i32_f(src), - AS::Native, - AS::Native, - i32_f(index), - size, - ), - ], AsmInstruction::LoadFI(dst, src, index, size, offset) => vec![ // mem[dst] <- mem[mem[src] + index * size + offset] inst( @@ -378,19 +342,6 @@ fn convert_instruction>( AS::Native, ), ], - AsmInstruction::StoreF(val, addr, index, size, offset) => vec![ - // mem[mem[addr] + mem[index] * size + offset] <- mem[val] - inst_large( - options.opcode_with_offset(NativeLoadStoreOpcode::STOREW2), - i32_f(val), - offset, - i32_f(addr), - AS::Native, - AS::Native, - i32_f(index), - size, - ), - ], AsmInstruction::StoreFI(val, addr, index, size, offset) => vec![ // mem[mem[addr] + index * size + offset] <- mem[val] inst( diff --git a/extensions/native/compiler/src/lib.rs b/extensions/native/compiler/src/lib.rs index ab02f3eb26..226cc0b16e 100644 --- a/extensions/native/compiler/src/lib.rs +++ b/extensions/native/compiler/src/lib.rs @@ -32,8 +32,6 @@ pub mod prelude { pub enum NativeLoadStoreOpcode { LOADW, STOREW, - LOADW2, - STOREW2, /// Instruction to write the next hint word into memory. SHINTW, }