Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions solx-mlir/sol_attr_stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ MlirType solxCreateFixedBytesType(MlirContext ctx, uint32_t size) {
MlirType solxCreateArrayType(MlirContext ctx, int64_t size, MlirType elementType,
uint32_t dataLocation) {
if (dataLocation > 5) abort();
if (size < -1) abort();
auto *context = unwrap(ctx);
auto location = static_cast<mlir::sol::DataLocation>(dataLocation);
std::optional<llvm::APInt> sizeOpt;
Expand Down
12 changes: 9 additions & 3 deletions solx-mlir/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ impl<'context> Context<'context> {
/// 1. `canonicalize`
/// 2. `sol-inline-modifiers`
/// 3. `convert-sol-to-yul`: Sol → Yul
/// 4. `convert-yul-to-std`: Yul → func/arith/scf/cf/LLVM
/// 4. `convert-yul-to-std`: Yul → func/arith/scf/cf/LLVM, keeping the
/// memoryguard symbolic; the EVM backend's `evm-fold-memory-guard` pass
/// folds it on each spill retry
/// 5. `canonicalize`
/// 6. `convert-scf-to-cf`
/// 7. `convert-func-to-llvm`
Expand Down Expand Up @@ -186,7 +188,9 @@ impl<'context> Context<'context> {
crate::ffi::mlirCreateConversionConvertSolToYulPass(),
));
pass_manager.add_pass(melior::pass::Pass::from_raw(
crate::ffi::mlirCreateConversionConvertYulToStandardPass(),
crate::ffi::mlirSolCreateConvertYulToStandardPass(
/* symbolic_mem_guard = */ true,
),
));
pass_manager.add_pass(melior::pass::Pass::from_raw(
crate::ffi::mlirCreateTransformsCanonicalizer(),
Expand Down Expand Up @@ -269,7 +273,9 @@ impl<'context> Context<'context> {
///
/// Parses the source, verifies it, lowers each `llvm.setimmutable` into heap stores at its
/// id's `immutables` offsets, and translates to LLVM IR.
/// Returns owned `(LLVMContextRef, LLVMModuleRef)`.
/// Returns owned `(LLVMContextRef, LLVMModuleRef)`. The translated
/// module still carries the symbolic memoryguard calls; the EVM backend
/// folds them at the start of the optimization pipeline.
///
/// # Errors
///
Expand Down
6 changes: 4 additions & 2 deletions solx-mlir/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ unsafe extern "C" {
/// Creates the `convert-sol-to-yul` pass.
pub fn mlirCreateConversionConvertSolToYulPass() -> MlirPass;

/// Creates the `convert-yul-to-std` pass.
pub fn mlirCreateConversionConvertYulToStandardPass() -> MlirPass;
/// Creates the `convert-yul-to-std` pass. `symbolic_mem_guard` lowers
/// `yul.memoryguard` to the `evm.memoryguard` intrinsic instead of a
/// constant.
pub fn mlirSolCreateConvertYulToStandardPass(symbolic_mem_guard: bool) -> MlirPass;

// ---- Standard-to-LLVM conversion passes ----

Expand Down
13 changes: 13 additions & 0 deletions solx-mlir/tests/lit/memory_guard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: solx --emit-mlir=llvm %s | FileCheck %s

// The free memory pointer's initializer stays symbolic through the pipeline;
// the EVM backend folds it to `guard + spill region size`.

// CHECK: llvm.func @__entry()
// CHECK: "llvm.intrcall"({{.*}}) <{id = {{[0-9]+}} : i32, name = "evm.memoryguard"}> : (i256) -> i256

contract C {
function f(uint256 a) public pure returns (uint256) {
return a + 1;
}
}
50 changes: 50 additions & 0 deletions tests/solidity/simple/stack_spill_heap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! { "modes": [ "Y", "E", "I" ], "cases": [ {
//! "name": "spillWithHeap",
//! "inputs": [
//! {
//! "method": "spillWithHeap",
//! "calldata": [ "7" ]
//! }
//! ],
//! "expected": [
//! "58321", "8", "9", "10", "11", "12", "13", "14"
//! ]
//! } ] }

pragma solidity >=0.4.19;

contract Test {
function g(uint256 x) internal pure returns (uint256) {
return x * 3 + 1;
}

function spillWithHeap(uint256 a) public pure returns (uint256[8] memory buf) {
uint256 v0 = a + 1;
uint256 v1 = a + 2;
uint256 v2 = v1 + v0;
uint256 v3 = v2 + v1;
uint256 v4 = v3 + v2;
uint256 v5 = v4 + v3;
uint256 v6 = v5 + v4;
uint256 v7 = v6 + v5;
uint256 v8 = v7 + v6;
uint256 v9 = v8 + v7;
uint256 v10 = v9 + v8;
uint256 v11 = v10 + v9;
uint256 v12 = v11 + v10;
uint256 v13 = v12 + v11;
uint256 v14 = v13 + v12;
uint256 v15 = v14 + v13;
uint256 v16 = v15 + v14;
uint256 v17 = v16 + v15;

for (uint256 i = 0; i < 8; i++) {
buf[i] = a + i;
}

uint256 r = g(a);
r += v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 +
v12 + v13 + v14 + v15 + v16 + v17;
buf[0] += r;
}
}
Loading