ronantakizawa/codereview-bench huggingface dataset:
Repository: nexus-xyz/nexus-zkvm
File: nvm/src/circuit/step.rs (Rust)

Code before:
            } else {
                match &vars[i] {
                    FpVar::Constant(f) => lc + (*x * f, Variable::One),
                    FpVar::Var(av) => lc + (*x, av.variable),
                }
            }
        })
    };

    for i in 0..rcs.a.len() {
        cs.enforce_constraint(row(&rcs.a[i]), row(&rcs.b[i]), row(&rcs.c[i]))?;
    }

    Ok(output)
}

pub fn build_constraints(
    cs: CS,
    index: usize,
    z: &[FpVar<F>],
    tr: &Trace,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
    let witness_only = match cs.borrow().unwrap().mode {
        SynthesisMode::Setup => false,
        SynthesisMode::Prove { construct_matrices } => !construct_matrices,
    };

    let b: &Block = match tr.block(index) {
        Some(b) => b,
        None => return Err(SynthesisError::AssignmentMissing),
    };
    let mut z = z;
    let mut v = Vec::new();

    for w in b {
        let rcs = step(&w, witness_only);
        v = build_constraints_partial(cs.clone(), witness_only, z, &w, rcs)?;
        z = &v;
    }

    Ok(v)
}


Review comment (suggestion):
https://docs.rs/ark-relations/latest/ark_relations/r1cs/enum.ConstraintSystemRef.html#method.should_construct_matrices is more concise

Code after:
            } else {
                match &vars[i] {
                    FpVar::Constant(f) => lc + (*x * f, Variable::One),
                    FpVar::Var(av) => lc + (*x, av.variable),
                }
            }
        })
    };

    for i in 0..rcs.a.len() {
        cs.enforce_constraint(row(&rcs.a[i]), row(&rcs.b[i]), row(&rcs.c[i]))?;
    }

    Ok(output)
}

pub fn build_constraints(
    cs: CS,
    index: usize,
    z: &[FpVar<F>],
    tr: &Trace,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
    let witness_only = !cs.should_construct_matrices();

    let b: &Block = match tr.block(index) {
        Some(b) => b,
        None => return Err(SynthesisError::AssignmentMissing),
    };
    let mut z = z;
    let mut v = Vec::new();

    for w in b {
        let rcs = step(&w, witness_only);
        v = build_constraints_partial(cs.clone(), witness_only, z, &w, rcs)?;
        z = &v;
    }

    Ok(v)
}
Repository: nexus-xyz/nexus-zkvm
File: tools/tools-dev/src/command/common/run.rs (Rust)

Code before:
use clap::Args;

#[derive(Debug, Args)]
pub struct RunArgs {
    /// Print instruction trace.
    #[arg(short)]
    pub verbose: bool,

    /// Build artifacts with the release profile. Equivalent to "--profile release".
    #[arg(short, name = "r", conflicts_with = "profile")]
    pub release: bool,

    /// Build artifacts with the specified profile. "dev" is default.
    #[arg(long, default_value = "dev")]
    pub profile: String,

    /// Name of the bin target to run.
    #[arg(long)]
    pub bin: Option<String>,
}


Review comment (bug):
Why do you think `--profile=release` isn't sufficient? This is also reflected in the code as it conflicts.

`--profile` is explicit, `--release` for usual cargo is for distinction between debug and optimized builds, in our case it's more involved.

Code after:
use clap::Args;

#[derive(Debug, Args)]
pub struct RunArgs {
    /// Print instruction trace.
    #[arg(short)]
    pub verbose: bool,

    /// Build artifacts with the specified profile. "dev" is default.
    #[arg(long, default_value = "dev")]
    pub profile: String,

    /// Name of the bin target to run.
    #[arg(long)]
    pub bin: Option<String>,
}
Repository: nexus-xyz/nexus-zkvm
File: assets/scripts/smoke.sh (Shell)

Code before:
    echo "Error: Directory 'nexus-project-ci' already exists."
    exit 1
fi

set -x

cp -n Cargo.toml Cargo.toml.bkp

error_handler() {
    echo "Error occured in e2e.sh: : ${1}. Exiting."
    cd $ORIGINAL_DIR
    rm -rf $PROJECT_NAME
    mv -f Cargo.toml.bkp Cargo.toml
    exit 1
}
trap 'error_handler ${LINENO}' ERR

cargo build --release --package nexus-tools --bin cargo-nexus
./target/release/cargo-nexus nexus new $PROJECT_NAME
cp $1 $PROJECT_NAME/src/main.rs
cd $PROJECT_NAME
../target/release/cargo-nexus nexus run
../target/release/cargo-nexus nexus prove
../target/release/cargo-nexus nexus verify
cd $ORIGINAL_DIR
rm -rf $PROJECT_NAME
mv -f Cargo.toml.bkp Cargo.toml


Review comment (refactor):
DRY - could have single cleanup() method when done (whether error or success)

Code after:
    echo "Error: Directory '$PROJECT_NAME' already exists."
    exit 1
fi

set -x

cp -n Cargo.toml Cargo.toml.bkp

cleanup() {
    cd $ORIGINAL_DIR
    rm -rf $PROJECT_NAME
    if [ -f Cargo.toml.bkp ]; then
        mv -f Cargo.toml.bkp Cargo.toml
    fi
}
trap cleanup SIGINT

error_handler() {
    echo "Error occured in smoke.sh: : ${1}. Exiting."
    cleanup
    exit 1
}
trap 'error_handler ${LINENO}' ERR

cargo build --release --package nexus-tools --bin cargo-nexus
./target/release/cargo-nexus nexus new $PROJECT_NAME
cp $1 $PROJECT_NAME/src/main.rs
cd $PROJECT_NAME
../target/release/cargo-nexus nexus run
../target/release/cargo-nexus nexus prove
../target/release/cargo-nexus nexus verify
cleanup
Repository: nexus-xyz/nexus-zkvm
File: vm/src/rv32/parse.rs (Rust)

Code before:

fn lop(word: u32) -> Option<LOP> {
    let res = match funct3(word) {
        0b000 => LB,
        0b001 => LH,
        0b010 => LW,
        0b100 => LBU,
        0b101 => LHU,
        _ => return None,
    };
    Some(res)
}

fn sop(word: u32) -> Option<SOP> {
    let res = match funct3(word) {
        0b000 => SB,
        0b001 => SH,
        0b010 => SW,
        _ => return None,
    };
    Some(res)
}

// parsing of arithmetic operations pg. 18-20

fn aop(word: u32) -> Option<AOP> {
    let res = match (opcode(word), funct3(word), funct7(word)) {
        (0b0110011, 0b000, 0b0100000) => SUB,
        (0b0110011, 0b000, 0b0000000) => ADD,
        (0b0110011, 0b000, _) => return None,
        (_, 0b000, _) => ADD,
        (_, 0b001, _) => SLL,
        (_, 0b010, _) => SLT,
        (_, 0b011, _) => SLTU,
        (_, 0b100, _) => XOR,
        (_, 0b101, 0b0000000) => SRL,
        (_, 0b101, 0b0100000) => SRA,
        (_, 0b110, _) => OR,
        (_, 0b111, _) => AND,
        _ => return None,
    };
    Some(res)
}

/// extract immediate from ALU instruction
pub fn immA(word: u32) -> u32 {
    match funct3(word) {
        0b001 | 0b101 => shamt(word),
        _ => immI(word),
    }
}

Review comment (suggestion):
@yoichi-nexus It seems to me that we need to enforce `opcode(word) = 0b0110011` for all these arithmetic operations and return `None` when this is not the case. It seems to me that we also need to enforce `func7(word) = 0b0100000` for `SUB` and `SRA` and  `func7(word) = 0b0000000` for all the remaining arithmetic operations. 

Code after:

fn lop(word: u32) -> Option<LOP> {
    let res = match funct3(word) {
        0b000 => LB,
        0b001 => LH,
        0b010 => LW,
        0b100 => LBU,
        0b101 => LHU,
        _ => return None,
    };
    Some(res)
}

fn sop(word: u32) -> Option<SOP> {
    let res = match funct3(word) {
        0b000 => SB,
        0b001 => SH,
        0b010 => SW,
        _ => return None,
    };
    Some(res)
}

// parsing of arithmetic operations pg. 18-20

fn aop(word: u32) -> Option<AOP> {
    assert_eq!(opcode(word), OPC_ALU);
    let res = match (funct3(word), funct7(word)) {
        (0b000, 0b0100000) => SUB,
        (0b000, 0b0000000) => ADD,
        (0b001, 0b0000000) => SLL,
        (0b010, 0b0000000) => SLT,
        (0b011, 0b0000000) => SLTU,
        (0b100, 0b0000000) => XOR,
        (0b101, 0b0000000) => SRL,
        (0b101, 0b0100000) => SRA,
        (0b110, 0b0000000) => OR,
        (0b111, 0b0000000) => AND,
        _ => return None,
    };
    Some(res)
}

fn aopi(word: u32) -> Option<AOP> {
    assert_eq!(opcode(word), OPC_ALUI);
    let res = match (funct3(word), funct7(word) /* imm[11:5] */) {
        (0b000, _ /* imm[11:5] can be any */) => ADD,
        (0b001, 0b0000000 /* SLLI requires special value in imm[11:5] */) => SLL,
        (0b010, _ /* imm[11:5] can be any */) => SLT,
        (0b011, _ /* imm[11:5] can be any */) => SLTU,
        (0b100, _ /* imm[11:5] can be any */) => XOR,
Repository: nexus-xyz/nexus-zkvm
File: vm/src/eval.rs (Rust)

Code before:
        }
    }

    /// set value of register r
    pub fn set_reg(&mut self, r: u32, val: u32) {
        if r != 0 {
            self.regs.x[r as usize] = val;
        }
    }

    /// initialize memory from slice
    pub fn init_memory(&mut self, addr: u32, bytes: &[u8]) -> Result<()> {
        // slow, but simple
        for (i, b) in bytes.iter().enumerate() {
            self.mem.store(SOP::SB, addr + (i as u32), *b as u32)?;
        }
        Ok(())
    }

    /// set the limit for the executed trace length
    pub fn set_max_trace_len(&mut self, max_trace_len: usize) {
        self.max_trace_len = Some(max_trace_len);
    }

    /// set the private input
    pub fn set_input(&mut self, input: &[u8]) {
        self.syscalls.set_input(input);
    }
}

// A simple, stable peephole optimizer for local constant propagation.
//
// Introduced for old 32-bit -> 64-bit translation, currently unused.
#[allow(dead_code)]
fn peephole(insn: &mut [Inst]) {
    for i in 0..insn.len() {
        match const_prop(&insn[i..]) {
            None => (),
            Some(v) => {
                for (j, x) in v.iter().enumerate() {
                    insn[i + j] = *x;
                }
            }
        }
    }
}

#[allow(dead_code)]
fn const_prop(insn: &[Inst]) -> Option<Vec<Inst>> {
    match insn {
        [Inst {

Review comment (suggestion):
We should just use `vm.syscalls.set_input()` instead of alias'ing it like this. In the future we may have inputs that don't pass through the `syscalls` interface and will want clear delineation of which method is being used.

Code after:
        }
    }

    /// set value of register r
    pub fn set_reg(&mut self, r: u32, val: u32) {
        if r != 0 {
            self.regs.x[r as usize] = val;
        }
    }

    /// initialize memory from slice
    pub fn init_memory(&mut self, addr: u32, bytes: &[u8]) -> Result<()> {
        // slow, but simple
        for (i, b) in bytes.iter().enumerate() {
            self.mem.store(SOP::SB, addr + (i as u32), *b as u32)?;
        }
        Ok(())
    }

    /// set the limit for the executed trace length
    pub fn set_max_trace_len(&mut self, max_trace_len: usize) {
        self.max_trace_len = Some(max_trace_len);
    }
}

// A simple, stable peephole optimizer for local constant propagation.
//
// Introduced for old 32-bit -> 64-bit translation, currently unused.
#[allow(dead_code)]
fn peephole(insn: &mut [Inst]) {
    for i in 0..insn.len() {
        match const_prop(&insn[i..]) {
            None => (),
            Some(v) => {
                for (j, x) in v.iter().enumerate() {
                    insn[i + j] = *x;
                }
            }
        }
    }
}

#[allow(dead_code)]
fn const_prop(insn: &[Inst]) -> Option<Vec<Inst>> {
    match insn {
        [Inst {
            pc: pc1,
            inst: RV32::AUIPC { rd: rd1, imm: imm1 },
            ..
        }, Inst {
            pc: pc2,
Repository: nexus-xyz/nexus-zkvm
File: vm/src/eval.rs (Rust)

Code before:
                            if *counter == 0 {
                                *clk = vm.global_clk - *clk;
                            }
                        }
                        _ => (),
                    }
                }
            }
        }
        UNIMP => {
            PC = vm.inst.pc;
        }
    }

    // Counts cycles per instruction kind.
    // In RISC-V:
    // - Memory instructions are 3 cycles
    // - Branch instructions are 2 cycles
    // - System call instruction are 4 cycles and higher
    // - ALU/ALUI/JAR/LUI/AUIPC instructions are 1 cycle
    // - Unknown instruction is 0 cycle
    let cycles = match vm.inst.inst {
        LOAD { .. } | STORE { .. } => 3,
        BR { .. } => 2,
        LUI { .. } | AUIPC { .. } | JAL { .. } | JALR { .. } | ALUI { .. } | ALU { .. } => 1,
        // Let's say ECALL is 4 cycles
        ECALL { .. } => 4,
        _ => 0,
    };

    if PC == 0 {
        PC = add32(vm.inst.pc, vm.inst.len);
    }
    vm.set_reg(RD, vm.Z);
    vm.regs.pc = PC;
    vm.trace_len += 1;
    vm.global_clk += cycles;
    Ok(())
}


Review comment (suggestion):
I suggest it should be rigorous instead of "Let's say". Optionally, we can skip counting cycles for `profile` syscall to eliminate the issue with build types.

Code after:
            vm.write_proof = Some(vm.mem.store(sop, addr, Y)?);
        }
        ALUI { aop, rd, rs1, imm } => {
            RD = rd;
            let X = vm.get_reg(rs1);
            vm.Z = alu_op(aop, X, imm);
        }
        ALU { aop, rd, rs1, rs2 } => {
            let X = vm.get_reg(rs1);
            let Y = vm.get_reg(rs2);
            RD = rd;
            vm.Z = alu_op(aop, X, Y);
        }
        FENCE => {}
        EBREAK { .. } => {}
        ECALL { rd } => {
            RD = rd;
            vm.Z = vm.syscalls.syscall(vm.regs.pc, vm.regs.x, &vm.mem)?;
            // Profile cycles
            if vm.regs.x[18] == SyscallCode::ProfileCycles as u32 {
                handle_profile_cycles(vm)?;
            }
        }
        UNIMP => {
            PC = vm.inst.pc;
        }
    }

    // Counts cycles per instruction kind.
    // In RISC-V:
    // - Memory instructions are 3 cycles
    // - Branch instructions are 2 cycles
    // - ALU/ALUI/JAR/LUI/AUIPC instructions are 1 cycle
    // - System call instruction are 4 cycles
    // - Unknown instruction is 0 cycle
    let cycles = match vm.inst.inst {
        LOAD { .. } | STORE { .. } => 3,
        BR { .. } => 2,
        LUI { .. } | AUIPC { .. } | JAL { .. } | JALR { .. } | ALUI { .. } | ALU { .. } => 1,
        ECALL { .. } => 4,
        EBREAK { .. } => 4,
        _ => 0,
    };

    if PC == 0 {
        PC = add32(vm.inst.pc, vm.inst.len);
    }
    vm.set_reg(RD, vm.Z);
    vm.regs.pc = PC;
    vm.trace_len += 1;
    vm.cycle_count += cycles;
Repository: nexus-xyz/nexus-zkvm
File: cli/src/command/run.rs (Rust)

Code before:

    /// Name of the bin target to run.
    #[arg(long)]
    pub bin: Option<String>,

    /// Build artifacts with the specific features. "cycles" is default.
    #[arg(long, default_value = "cycles")]
    pub features: String,
}

pub fn handle_command(args: RunArgs) -> anyhow::Result<()> {
    let RunArgs { verbose, profile, bin, features } = args;

    run_vm(bin, verbose, &profile, &features)
}

fn run_vm(bin: Option<String>, verbose: bool, profile: &str, features: &str) -> anyhow::Result<()> {
    // build artifact
    cargo(
        None,
        [
            "build",
            "--target=riscv32i-unknown-none-elf",
            "--profile",
            profile,
            "--features",
            features,
        ],
    )?;

    let path = path_to_artifact(bin, profile)?;

    run_vm_with_elf_file(&path, verbose)
}

pub fn run_vm_with_elf_file(path: &Path, verbose: bool) -> anyhow::Result<()> {
    let opts = nexus_core::nvm::VMOpts {
        k: 1,
        machine: None,
        file: Some(path.into()),
    };

    nexus_core::nvm::run_vm::<nexus_core::nvm::memory::Paged>(&opts, true, verbose)
        .map_err(Into::into)
}


Review comment (suggestion):
We should pass this through an allowlist of a features, since there are others used internally in the `runtime` that shouldn't be exposed to the user to configure.

Code after:
    #[arg(long, default_value = "dev")]
    pub profile: String,

    /// Name of the bin target to run.
    #[arg(long)]
    pub bin: Option<String>,

    /// Build artifacts with the specific features. "cycles" is default.
    #[arg(
        long,
        default_value = "cycles",
        value_name = "FEATURES",
        use_value_delimiter = true
    )]
    pub features: Vec<String>,
}

pub fn handle_command(args: RunArgs) -> anyhow::Result<()> {
    let RunArgs { verbose, profile, bin, features } = args;

    run_vm(bin, verbose, &profile, features)
}

fn run_vm(
    bin: Option<String>,
    verbose: bool,
    profile: &str,
    features: Vec<String>,
) -> anyhow::Result<()> {
    let allowed_features: HashSet<_> = ALLOWED_FEATURES.iter().cloned().collect();

    // Build cargo arguments
    let mut cargo_args = vec![
        "build",
        "--target=riscv32i-unknown-none-elf",
        "--profile",
        profile,
    ];

    // Filter and add valid features
    let valid_features: Vec<&&str> = features
        .iter()
        .filter_map(|f| allowed_features.get(f.as_str()))
        .collect();

    if !valid_features.is_empty() {
        cargo_args.push("--features");
        for feature in valid_features {
            cargo_args.push(feature);
            cargo_args.push(",");
        }
Repository: nexus-xyz/nexus-zkvm
File: vm/src/syscalls.rs (Rust)

Code before:
//! Implementation of system calls

use std::collections::VecDeque;
use std::io::Write;

use crate::{
    error::{NexusVMError::UnknownECall, Result},
    memory::Memory,
};

/// Holds information related to syscall implementation.
#[derive(Default)]
pub struct Syscalls {
    to_stdout: bool,
    log_buffer: Vec<Vec<u8>>,
    input: VecDeque<u8>,
    output: Vec<u8>,
    label: Vec<Vec<u8>>,
}

pub enum SyscallCode {
    WriteLog = 1,
    ReadFromPrivateInput = 2,
    WriteToOutput = 3,
    ProfileCycles = 4,
}

impl SyscallCode {
    fn try_from(pc: u32, syscode: u32) -> Result<Self> {
        match syscode {
            1 => Ok(SyscallCode::WriteLog),
            2 => Ok(SyscallCode::ReadFromPrivateInput),
            3 => Ok(SyscallCode::WriteToOutput),
            4 => Ok(SyscallCode::ProfileCycles),
            _ => Err(UnknownECall(pc, syscode)),
        }
    }
}
impl Syscalls {
    pub fn enable_stdout(&mut self) {
        self.to_stdout = true;
    }

    pub fn disable_stdout(&mut self) {
        self.to_stdout = false;
    }

    pub fn set_input(&mut self, slice: &[u8]) {
        self.input = slice.to_owned().into();
    }

Review comment (suggestion):
If you change this to `5` as noted you should also put a comment here explaining the skip of `4`.

Code after:
//! Implementation of system calls

use std::collections::VecDeque;
use std::io::Write;

use crate::{
    error::{NexusVMError::UnknownECall, Result},
    memory::Memory,
};

/// Holds information related to syscall implementation.
#[derive(Default)]
pub struct Syscalls {
    to_stdout: bool,
    log_buffer: Vec<Vec<u8>>,
    input: VecDeque<u8>,
    output: Vec<u8>,
    label: Vec<Vec<u8>>,
}

pub enum SyscallCode {
    WriteLog = 1,
    ReadFromPrivateInput = 2,
    WriteToOutput = 3,
    ProfileCycles = 5,
}

impl SyscallCode {
    fn try_from(pc: u32, syscode: u32) -> Result<Self> {
        match syscode {
            1 => Ok(SyscallCode::WriteLog),
            2 => Ok(SyscallCode::ReadFromPrivateInput),
            3 => Ok(SyscallCode::WriteToOutput),
            5 => Ok(SyscallCode::ProfileCycles),
            _ => Err(UnknownECall(pc, syscode)),
        }
    }
}
impl Syscalls {
    pub fn enable_stdout(&mut self) {
        self.to_stdout = true;
    }

    pub fn disable_stdout(&mut self) {
        self.to_stdout = false;
    }

    pub fn set_input(&mut self, slice: &[u8]) {
        self.input = slice.to_owned().into();
    }
Repository: nexus-xyz/nexus-zkvm
File: runtime/assemble.sh (Shell)

Code before:
#!/bin/sh

set -e

rm -f bin/*.a

for ext in i imc
do
    riscv64-elf-gcc -c -mabi=ilp32 -march=rv32${ext} -mcmodel=medlow asm.S -o bin/nexus-rt.o
    riscv64-elf-ar crs bin/riscv32${ext}-unknown-none-elf.a bin/nexus-rt.o
done

rm bin/nexus-rt.o


Review comment (suggestion):
I would prefer we either don't change these, or try to detect the OS and swap between them for Linux/MacOS.

Code after:
#!/bin/sh
set -e

# Detect the operating system
if [ "$(uname)" = "Darwin" ]; then
    # macOS
    GCC_PREFIX="riscv64-elf-"
else
    # Assume Linux
    GCC_PREFIX="riscv-none-elf-"
fi

rm -f bin/***.a
for ext in i imc
do
    ${GCC_PREFIX}gcc -c -mabi=ilp32 -march=rv32${ext} -mcmodel=medlow asm.S -o bin/nexus-rt.o
    ${GCC_PREFIX}ar crs bin/riscv32${ext}-unknown-none-elf.a bin/nexus-rt.o
done
rm bin/nexus-rt.o
Repository: nexus-xyz/nexus-zkvm
File: runtime/src/alloc.rs (Rust)

Code before:
// Copyright 2023 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const MAX_MEMORY: usize = 0x400000;

#[allow(clippy::missing_safety_doc)]
#[no_mangle]
pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
    #[cfg(target_arch = "riscv32")]
    extern "C" {
        // https://lld.llvm.org/ELF/linker_script.html#sections-command
        static _end: u8;
    }

    // Pointer to next heap address to use, or 0 if the heap has not yet been
    // initialized.
    static mut HEAP_POS: usize = 0;

    // SAFETY: Single threaded, so nothing else can touch this while we're working.
    let mut heap_pos = unsafe { HEAP_POS };

    #[cfg(target_arch = "riscv32")]
    if heap_pos == 0 {
        heap_pos = unsafe { (&_end) as *const u8 as usize };
    }

    let offset = heap_pos & (align - 1);
    if offset != 0 {
        heap_pos += align - offset;

Review comment (suggestion):
This value cannot be hardcoded in, as we allow the user to set it larger dynamically through a macro or the SDK.

Code after:
// Copyright 2023 RISC Zero, Inc.
// Copyright 2024 Nexus Laboratories, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Minimum gap between heap and stack
const MEMORY_GAP: usize = 0x1000;

#[allow(clippy::missing_safety_doc)]
#[no_mangle]
pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
    extern "C" {
        // https://lld.llvm.org/ELF/linker_script.html#sections-command
        static _end: u8;
    }

    // Pointer to next heap address to use, or 0 if the heap has not yet been
    // initialized.
    static mut HEAP_POS: usize = 0;

    // SAFETY: Single threaded, so nothing else can touch this while we're working.
    let mut heap_pos = HEAP_POS;

    if heap_pos == 0 {
        heap_pos = &_end as *const u8 as usize;
    }

    let offset = heap_pos & (align - 1);
    if offset != 0 {
        heap_pos = heap_pos