mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 22:41:07 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af8074cfde | |||
| bb3b6ddb41 | |||
| dfe56f9306 | |||
| 63011b6d24 | |||
| d40ef3e462 |
@@ -14,9 +14,7 @@ Supported `polkadot-sdk` rev: `2503.0.1`
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Line debug information per YUL builtin and for `if` statements.
|
- Line debug information per YUL builtin and for `if` statements.
|
||||||
- Column numbers in debug information.
|
|
||||||
- Support for the YUL optimizer details in the standard json input definition.
|
- Support for the YUL optimizer details in the standard json input definition.
|
||||||
- The `revive-explorer` compiler utility.
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- The debug info source file matches the YUL path in `--debug-output-dir`, allowing tools to display the source line.
|
- The debug info source file matches the YUL path in `--debug-output-dir`, allowing tools to display the source line.
|
||||||
|
|||||||
Generated
-10
@@ -8615,16 +8615,6 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "revive-explorer"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"clap",
|
|
||||||
"num_cpus",
|
|
||||||
"revive-yul",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revive-integration"
|
name = "revive-integration"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
|
|||||||
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
|
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
|
||||||
revive-common = { version = "0.1.0", path = "crates/common" }
|
revive-common = { version = "0.1.0", path = "crates/common" }
|
||||||
revive-differential = { version = "0.1.0", path = "crates/differential" }
|
revive-differential = { version = "0.1.0", path = "crates/differential" }
|
||||||
revive-explorer = { version = "0.1.0", path = "crates/explore" }
|
|
||||||
revive-integration = { version = "0.1.1", path = "crates/integration" }
|
revive-integration = { version = "0.1.1", path = "crates/integration" }
|
||||||
revive-linker = { version = "0.1.0", path = "crates/linker" }
|
revive-linker = { version = "0.1.0", path = "crates/linker" }
|
||||||
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
|
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
install-llvm-builder \
|
install-llvm-builder \
|
||||||
install-llvm \
|
install-llvm \
|
||||||
install-revive-runner \
|
install-revive-runner \
|
||||||
install-revive-explorer \
|
|
||||||
format \
|
format \
|
||||||
clippy \
|
clippy \
|
||||||
machete \
|
machete \
|
||||||
@@ -44,9 +43,6 @@ install-llvm: install-llvm-builder
|
|||||||
install-revive-runner:
|
install-revive-runner:
|
||||||
cargo install --locked --force --path crates/runner --no-default-features
|
cargo install --locked --force --path crates/runner --no-default-features
|
||||||
|
|
||||||
install-revive-explorer:
|
|
||||||
cargo install --locked --force --path crates/explorer --no-default-features
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
|
|
||||||
@@ -57,7 +53,7 @@ machete:
|
|||||||
cargo install cargo-machete
|
cargo install cargo-machete
|
||||||
cargo machete
|
cargo machete
|
||||||
|
|
||||||
test: format clippy machete test-cli test-workspace install-revive-runner install-revive-explorer
|
test: format clippy machete test-cli test-workspace install-revive-runner
|
||||||
|
|
||||||
test-integration: install-bin
|
test-integration: install-bin
|
||||||
cargo test --package revive-integration
|
cargo test --package revive-integration
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "revive-explorer"
|
|
||||||
version.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
authors.workspace = true
|
|
||||||
description = "Helper utility to inspect debug builds"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "revive-explorer"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
clap = { workspace = true, features = ["help", "std", "derive"] }
|
|
||||||
num_cpus = { workspace = true }
|
|
||||||
|
|
||||||
revive-yul = { workspace = true }
|
|
||||||
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# revive-explorer
|
|
||||||
|
|
||||||
The `revive-explorer` is a helper utility for exploring the compilers YUL lowering unit.
|
|
||||||
|
|
||||||
It analyzes a given shared objects from the debug dump and outputs:
|
|
||||||
- The count of each YUL statement translated.
|
|
||||||
- A per YUL statement break-down of bytecode size contributed per.
|
|
||||||
- Estimated `yul-phaser` cost parameters.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
statements count:
|
|
||||||
block 532
|
|
||||||
Caller 20
|
|
||||||
Not 73
|
|
||||||
Gas 24
|
|
||||||
Shr 2
|
|
||||||
...
|
|
||||||
Shl 259
|
|
||||||
SetImmutable 2
|
|
||||||
CodeSize 1
|
|
||||||
CallDataLoad 87
|
|
||||||
Return 56
|
|
||||||
bytes per statement:
|
|
||||||
Or 756
|
|
||||||
CodeCopy 158
|
|
||||||
Log3 620
|
|
||||||
Return 1562
|
|
||||||
MStore 36128
|
|
||||||
...
|
|
||||||
ReturnDataCopy 2854
|
|
||||||
DataOffset 28
|
|
||||||
assignment 1194
|
|
||||||
Number 540
|
|
||||||
CallValue 4258
|
|
||||||
yul-phaser parameters:
|
|
||||||
--break-cost 1
|
|
||||||
--variable-declaration-cost 3
|
|
||||||
--function-call-cost 8
|
|
||||||
--if-cost 4
|
|
||||||
--expression-statement-cost 6
|
|
||||||
--function-definition-cost 11
|
|
||||||
--switch-cost 3
|
|
||||||
--block-cost 1
|
|
||||||
--leave-cost 1
|
|
||||||
--assignment-cost 1
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
//! The `llvm-dwarfdump` utility helper library.
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static EXECUTABLE: &str = "llvm-dwarfdump";
|
|
||||||
pub static DEBUG_LINES_ARGUMENTS: [&str; 1] = ["--debug-line"];
|
|
||||||
pub static SOURCE_FILE_ARGUMENTS: [&str; 1] = ["--show-sources"];
|
|
||||||
|
|
||||||
/// Calls the `llvm-dwarfdump` tool to extract debug line information
|
|
||||||
/// from the shared object at `path`. Returns the output.
|
|
||||||
///
|
|
||||||
/// Provide `Some(dwarfdump_exectuable)` to override the default executable.
|
|
||||||
pub fn debug_lines(
|
|
||||||
shared_object: &Path,
|
|
||||||
dwarfdump_executable: &Option<PathBuf>,
|
|
||||||
) -> anyhow::Result<String> {
|
|
||||||
dwarfdump(shared_object, dwarfdump_executable, &DEBUG_LINES_ARGUMENTS)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls the `llvm-dwarfdump` tool to extract the source file name.
|
|
||||||
/// Returns the source file path.
|
|
||||||
///
|
|
||||||
/// Provide `Some(dwarfdump_exectuable)` to override the default executable.
|
|
||||||
pub fn source_file(
|
|
||||||
shared_object: &Path,
|
|
||||||
dwarfdump_executable: &Option<PathBuf>,
|
|
||||||
) -> anyhow::Result<PathBuf> {
|
|
||||||
let output = dwarfdump(shared_object, dwarfdump_executable, &SOURCE_FILE_ARGUMENTS)?;
|
|
||||||
Ok(output.trim().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The internal `llvm-dwarfdump` helper function.
|
|
||||||
fn dwarfdump(
|
|
||||||
shared_object: &Path,
|
|
||||||
dwarfdump_executable: &Option<PathBuf>,
|
|
||||||
arguments: &[&str],
|
|
||||||
) -> anyhow::Result<String> {
|
|
||||||
let executable = dwarfdump_executable
|
|
||||||
.to_owned()
|
|
||||||
.unwrap_or_else(|| PathBuf::from(EXECUTABLE));
|
|
||||||
|
|
||||||
let output = Command::new(executable)
|
|
||||||
.args(arguments)
|
|
||||||
.arg(shared_object)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.spawn()?
|
|
||||||
.wait_with_output()?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
anyhow::bail!(String::from_utf8_lossy(&output.stderr).to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
|
||||||
}
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
//! The core dwarf dump analyzer library.
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use revive_yul::lexer::token::location::Location;
|
|
||||||
|
|
||||||
use crate::location_mapper::{self, map_locations, LocationMap};
|
|
||||||
|
|
||||||
/// Unknwon code.
|
|
||||||
pub const OTHER: &str = "other";
|
|
||||||
/// Compiler internal code.
|
|
||||||
pub const INTERNAL: &str = "internal";
|
|
||||||
/// YUL block code.
|
|
||||||
pub const BLOCK: &str = "block";
|
|
||||||
/// YUL function call code.
|
|
||||||
pub const FUNCTION_CALL: &str = "function_call";
|
|
||||||
/// YUL conditional code.
|
|
||||||
pub const IF: &str = "if";
|
|
||||||
/// YUL loop code.
|
|
||||||
pub const FOR: &str = "for";
|
|
||||||
/// YUL loop continue code.
|
|
||||||
pub const CONTINUE: &str = "continue";
|
|
||||||
/// YUL loop break code.
|
|
||||||
pub const BREAK: &str = "break";
|
|
||||||
/// YUL switch code.
|
|
||||||
pub const SWITCH: &str = "switch";
|
|
||||||
/// YUL variable declaration code.
|
|
||||||
pub const DECLARATION: &str = "let";
|
|
||||||
/// YUL variable assignment code.
|
|
||||||
pub const ASSIGNMENT: &str = "assignment";
|
|
||||||
/// YUL function definition code.
|
|
||||||
pub const FUNCTION_DEFINITION: &str = "function_definition";
|
|
||||||
/// YUL function leave code.
|
|
||||||
pub const LEAVE: &str = "leave";
|
|
||||||
|
|
||||||
/// The dwarf dump analyzer.
|
|
||||||
///
|
|
||||||
/// Loads debug information from `llvm-dwarfdump` and calculates statistics
|
|
||||||
/// about the compiled YUL statements:
|
|
||||||
/// - Statements count
|
|
||||||
/// - Per-statement
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct DwarfdumpAnalyzer {
|
|
||||||
/// The YUL source file path.
|
|
||||||
source: PathBuf,
|
|
||||||
|
|
||||||
/// The YUL location to statements map.
|
|
||||||
location_map: LocationMap,
|
|
||||||
|
|
||||||
/// The `llvm-dwarfdump --debug-lines` output.
|
|
||||||
debug_lines: String,
|
|
||||||
|
|
||||||
/// The observed statements.
|
|
||||||
statements_count: HashMap<String, usize>,
|
|
||||||
/// The observed statement to instructions size.
|
|
||||||
statements_size: HashMap<String, u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DwarfdumpAnalyzer {
|
|
||||||
/// The debug info analyzer constructor.
|
|
||||||
///
|
|
||||||
/// `source` is the path to the YUL source file.
|
|
||||||
/// `debug_lines` is the `llvm-dwarfdump --debug-lines` output.
|
|
||||||
pub fn new(source: &Path, debug_lines: String) -> Self {
|
|
||||||
Self {
|
|
||||||
source: source.to_path_buf(),
|
|
||||||
debug_lines,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the analysis.
|
|
||||||
pub fn analyze(&mut self) -> anyhow::Result<()> {
|
|
||||||
self.map_locations()?;
|
|
||||||
self.analyze_statements()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Populate the maps so that we can always unwrap later.
|
|
||||||
fn map_locations(&mut self) -> anyhow::Result<()> {
|
|
||||||
self.location_map = map_locations(&self.source)?;
|
|
||||||
|
|
||||||
self.statements_count = HashMap::with_capacity(self.location_map.len());
|
|
||||||
self.statements_size = HashMap::with_capacity(self.location_map.len());
|
|
||||||
|
|
||||||
for statement in self.location_map.values() {
|
|
||||||
if !self.statements_size.contains_key(statement) {
|
|
||||||
self.statements_size.insert(statement.clone(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
*self.statements_count.entry(statement.clone()).or_insert(0) += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Analyze how much bytes of insturctions each statement contributes.
|
|
||||||
fn analyze_statements(&mut self) -> anyhow::Result<()> {
|
|
||||||
let mut previous_offset = 0;
|
|
||||||
let mut previous_location = Location::new(0, 0);
|
|
||||||
|
|
||||||
for line in self
|
|
||||||
.debug_lines
|
|
||||||
.lines()
|
|
||||||
.skip_while(|line| !line.starts_with("Address"))
|
|
||||||
.skip(2)
|
|
||||||
{
|
|
||||||
let mut parts = line.split_whitespace();
|
|
||||||
let (Some(offset), Some(line), Some(column)) =
|
|
||||||
(parts.next(), parts.next(), parts.next())
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let current_offset = u64::from_str_radix(offset.trim_start_matches("0x"), 16)?;
|
|
||||||
let mut current_location = Location::new(line.parse()?, column.parse()?);
|
|
||||||
|
|
||||||
// TODO: A bug? Needs further investigation.
|
|
||||||
if current_location.line == 0 && current_location.column != 0 {
|
|
||||||
current_location.line = previous_location.line;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(statement) = self.location_map.get(&previous_location) {
|
|
||||||
let contribution = current_offset - previous_offset;
|
|
||||||
*self.statements_size.get_mut(statement).unwrap() += contribution;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous_offset = current_offset;
|
|
||||||
previous_location = current_location;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print the per-statement count break-down.
|
|
||||||
pub fn display_statement_count(&self) {
|
|
||||||
println!("statements count:");
|
|
||||||
for (statement, count) in self.statements_count.iter() {
|
|
||||||
println!("\t{statement} {count}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print the per-statement byte size contribution break-down.
|
|
||||||
pub fn display_statement_size(&self) {
|
|
||||||
println!("bytes per statement:");
|
|
||||||
for (statement, size) in self.statements_size.iter() {
|
|
||||||
println!("\t{statement} {size}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print the estimated `yul-phaser` cost parameters.
|
|
||||||
pub fn display_phaser_costs(&self, yul_phaser_scale: u64) {
|
|
||||||
println!("yul-phaser parameters:");
|
|
||||||
for (parameter, cost) in self.phaser_costs(yul_phaser_scale) {
|
|
||||||
println!("\t{parameter} {cost}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Estimate the `yul-phaser` costs using the simplified weight function:
|
|
||||||
/// `Total size / toal count = cost`
|
|
||||||
pub fn phaser_costs(&self, yul_phaser_scale: u64) -> Vec<(String, u64)> {
|
|
||||||
let mut costs: HashMap<String, (usize, u64)> = HashMap::with_capacity(16);
|
|
||||||
for (statement, count) in self
|
|
||||||
.statements_count
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, count)| **count > 0)
|
|
||||||
{
|
|
||||||
let size = self.statements_size.get(statement).unwrap();
|
|
||||||
let cost = match statement.as_str() {
|
|
||||||
location_mapper::FOR => "--for-loop-cost",
|
|
||||||
location_mapper::OTHER => continue,
|
|
||||||
location_mapper::INTERNAL => continue,
|
|
||||||
location_mapper::BLOCK => "--block-cost",
|
|
||||||
location_mapper::FUNCTION_CALL => "--function-call-cost",
|
|
||||||
location_mapper::IF => "--if-cost",
|
|
||||||
location_mapper::CONTINUE => "--continue-cost",
|
|
||||||
location_mapper::BREAK => "--break-cost",
|
|
||||||
location_mapper::LEAVE => "--leave-cost",
|
|
||||||
location_mapper::SWITCH => "--switch-cost",
|
|
||||||
location_mapper::DECLARATION => "--variable-declaration-cost",
|
|
||||||
location_mapper::ASSIGNMENT => "--assignment-cost",
|
|
||||||
location_mapper::FUNCTION_DEFINITION => "--function-definition-cost",
|
|
||||||
_ => "--expression-statement-cost",
|
|
||||||
};
|
|
||||||
|
|
||||||
let entry = costs.entry(cost.to_string()).or_default();
|
|
||||||
entry.0 += count;
|
|
||||||
entry.1 += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
let costs = costs
|
|
||||||
.iter()
|
|
||||||
.map(|(cost, (count, size))| {
|
|
||||||
let ratio = *size / *count as u64;
|
|
||||||
(cost.to_string(), ratio.min(100))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let scaled_costs = scale_to(
|
|
||||||
costs
|
|
||||||
.iter()
|
|
||||||
.map(|(_, ratio)| *ratio)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.as_slice(),
|
|
||||||
yul_phaser_scale,
|
|
||||||
);
|
|
||||||
|
|
||||||
costs
|
|
||||||
.iter()
|
|
||||||
.zip(scaled_costs)
|
|
||||||
.map(|((cost, _), scaled_ratio)| (cost.to_string(), scaled_ratio))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a slice of u64 values, returns a Vec<u64> where each element
|
|
||||||
/// is linearly scaled into the closed interval [1, 10].
|
|
||||||
fn scale_to(data: &[u64], scale_max: u64) -> Vec<u64> {
|
|
||||||
if data.is_empty() {
|
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut min = data[0];
|
|
||||||
let mut max = data[0];
|
|
||||||
for &x in &data[1..] {
|
|
||||||
if x < min {
|
|
||||||
min = x;
|
|
||||||
}
|
|
||||||
if x > max {
|
|
||||||
max = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if max < scale_max {
|
|
||||||
return data.to_vec();
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = max - min;
|
|
||||||
data.iter()
|
|
||||||
.map(|&x| {
|
|
||||||
if range == 0 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
1 + (x - min) * scale_max / range
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
//! The revive explorer leverages debug info to get insights into emitted code.
|
|
||||||
|
|
||||||
pub mod dwarfdump;
|
|
||||||
pub mod dwarfdump_analyzer;
|
|
||||||
pub mod location_mapper;
|
|
||||||
pub mod yul_phaser;
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
//! The location mapper utility maps YUL source locations to AST statements.
|
|
||||||
//!
|
|
||||||
//! TODO: Refactor when the AST visitor is implemented.
|
|
||||||
|
|
||||||
use std::{collections::HashMap, path::Path};
|
|
||||||
|
|
||||||
use revive_yul::{
|
|
||||||
lexer::{token::location::Location, Lexer},
|
|
||||||
parser::statement::{
|
|
||||||
block::Block,
|
|
||||||
expression::{function_call::name::Name, Expression},
|
|
||||||
object::Object,
|
|
||||||
Statement,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Code attributed to an unknown location.
|
|
||||||
pub const OTHER: &str = "other";
|
|
||||||
/// Code attributed to a compiler internal location.
|
|
||||||
pub const INTERNAL: &str = "internal";
|
|
||||||
/// Code attributed to a
|
|
||||||
pub const BLOCK: &str = "block";
|
|
||||||
pub const FUNCTION_CALL: &str = "function_call";
|
|
||||||
pub const FOR: &str = "for";
|
|
||||||
pub const IF: &str = "if";
|
|
||||||
pub const CONTINUE: &str = "continue";
|
|
||||||
pub const BREAK: &str = "break";
|
|
||||||
pub const LEAVE: &str = "leave";
|
|
||||||
pub const SWITCH: &str = "switch";
|
|
||||||
pub const DECLARATION: &str = "let";
|
|
||||||
pub const ASSIGNMENT: &str = "assignment";
|
|
||||||
pub const FUNCTION_DEFINITION: &str = "function_definition";
|
|
||||||
|
|
||||||
/// The location to statements map type alias.
|
|
||||||
pub type LocationMap = HashMap<Location, String>;
|
|
||||||
|
|
||||||
/// Construct a [LocationMap] from the given YUL `source` file.
|
|
||||||
pub fn map_locations(source: &Path) -> anyhow::Result<LocationMap> {
|
|
||||||
let mut lexer = Lexer::new(std::fs::read_to_string(source)?);
|
|
||||||
let ast = Object::parse(&mut lexer, None).map_err(|error| {
|
|
||||||
anyhow::anyhow!("Contract `{}` parsing error: {:?}", source.display(), error)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut location_map = HashMap::with_capacity(1024);
|
|
||||||
crate::location_mapper::object_mapper(&mut location_map, &ast);
|
|
||||||
location_map.insert(Location::new(0, 0), OTHER.to_string());
|
|
||||||
location_map.insert(Location::new(1, 0), INTERNAL.to_string());
|
|
||||||
|
|
||||||
Ok(location_map)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map the [Block].
|
|
||||||
fn block_mapper(map: &mut LocationMap, block: &Block) {
|
|
||||||
map.insert(block.location, BLOCK.to_string());
|
|
||||||
|
|
||||||
for statement in &block.statements {
|
|
||||||
statement_mapper(map, statement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map the [Expression].
|
|
||||||
fn expression_mapper(map: &mut LocationMap, expression: &Expression) {
|
|
||||||
if let Expression::FunctionCall(call) = expression {
|
|
||||||
let id = match call.name {
|
|
||||||
Name::UserDefined(_) => FUNCTION_CALL.to_string(),
|
|
||||||
_ => format!("{:?}", call.name),
|
|
||||||
};
|
|
||||||
map.insert(expression.location(), id);
|
|
||||||
|
|
||||||
for expression in &call.arguments {
|
|
||||||
expression_mapper(map, expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map the [Statement].
|
|
||||||
fn statement_mapper(map: &mut LocationMap, statement: &Statement) {
|
|
||||||
match statement {
|
|
||||||
Statement::Object(object) => object_mapper(map, object),
|
|
||||||
|
|
||||||
Statement::Code(code) => block_mapper(map, &code.block),
|
|
||||||
|
|
||||||
Statement::Block(block) => block_mapper(map, block),
|
|
||||||
|
|
||||||
Statement::ForLoop(for_loop) => {
|
|
||||||
map.insert(for_loop.location, FOR.to_string());
|
|
||||||
|
|
||||||
expression_mapper(map, &for_loop.condition);
|
|
||||||
block_mapper(map, &for_loop.body);
|
|
||||||
block_mapper(map, &for_loop.initializer);
|
|
||||||
block_mapper(map, &for_loop.finalizer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::IfConditional(if_conditional) => {
|
|
||||||
map.insert(if_conditional.location, IF.to_string());
|
|
||||||
|
|
||||||
expression_mapper(map, &if_conditional.condition);
|
|
||||||
block_mapper(map, &if_conditional.block);
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Expression(expression) => expression_mapper(map, expression),
|
|
||||||
|
|
||||||
Statement::Continue(location) => {
|
|
||||||
map.insert(*location, CONTINUE.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Leave(location) => {
|
|
||||||
map.insert(*location, LEAVE.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Break(location) => {
|
|
||||||
map.insert(*location, BREAK.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Switch(switch) => {
|
|
||||||
map.insert(switch.expression.location(), SWITCH.to_string());
|
|
||||||
|
|
||||||
expression_mapper(map, &switch.expression);
|
|
||||||
for case in &switch.cases {
|
|
||||||
block_mapper(map, &case.block);
|
|
||||||
}
|
|
||||||
if let Some(block) = switch.default.as_ref() {
|
|
||||||
block_mapper(map, block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::Assignment(assignment) => {
|
|
||||||
map.insert(assignment.location, ASSIGNMENT.to_string());
|
|
||||||
|
|
||||||
expression_mapper(map, &assignment.initializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::VariableDeclaration(declaration) => {
|
|
||||||
map.insert(declaration.location, DECLARATION.to_string());
|
|
||||||
|
|
||||||
if let Some(expression) = declaration.expression.as_ref() {
|
|
||||||
expression_mapper(map, expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::FunctionDefinition(definition) => {
|
|
||||||
map.insert(definition.location, FUNCTION_DEFINITION.to_string());
|
|
||||||
|
|
||||||
block_mapper(map, &definition.body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map the [Object].
|
|
||||||
fn object_mapper(map: &mut LocationMap, object: &Object) {
|
|
||||||
map.insert(object.location, object.identifier.clone());
|
|
||||||
|
|
||||||
block_mapper(map, &object.code.block);
|
|
||||||
|
|
||||||
if let Some(object) = object.inner_object.as_ref() {
|
|
||||||
object_mapper(map, object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use clap::Parser;
|
|
||||||
|
|
||||||
use revive_explorer::{dwarfdump, dwarfdump_analyzer::DwarfdumpAnalyzer, yul_phaser};
|
|
||||||
|
|
||||||
/// The `revive-explorer` is a helper utility for exploring the compilers YUL lowering unit.
|
|
||||||
///
|
|
||||||
/// It analyzes a given shared objects from the debug dump and outputs:
|
|
||||||
/// - The count of each YUL statement translated.
|
|
||||||
/// - A per YUL statement break-down of bytecode size contributed per.
|
|
||||||
/// - Estimated `yul-phaser` cost parameters.
|
|
||||||
#[derive(Parser, Debug)]
|
|
||||||
#[command(version, about, long_about = None)]
|
|
||||||
struct Args {
|
|
||||||
/// Path of the dwarfdump executable.
|
|
||||||
#[arg(short, long)]
|
|
||||||
dwarfdump: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// The YUL phaser cost scale maximum value.
|
|
||||||
#[arg(short, long, default_value_t = 10)]
|
|
||||||
cost_scale: u64,
|
|
||||||
|
|
||||||
/// Run the provided yul-phaser executable using the estimated costs.
|
|
||||||
#[arg(short, long)]
|
|
||||||
yul_phaser: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Path of the shared object to analyze.
|
|
||||||
file: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
|
||||||
let args = Args::parse();
|
|
||||||
|
|
||||||
let source_file = dwarfdump::source_file(&args.file, &args.dwarfdump)?;
|
|
||||||
let debug_lines = dwarfdump::debug_lines(&args.file, &args.dwarfdump)?;
|
|
||||||
let mut analyzer = DwarfdumpAnalyzer::new(source_file.as_path(), debug_lines);
|
|
||||||
|
|
||||||
analyzer.analyze()?;
|
|
||||||
|
|
||||||
if let Some(path) = args.yul_phaser.as_ref() {
|
|
||||||
yul_phaser::run(
|
|
||||||
path,
|
|
||||||
source_file.as_path(),
|
|
||||||
analyzer.phaser_costs(args.cost_scale).as_slice(),
|
|
||||||
num_cpus::get() / 2, // TODO: should be configurable.
|
|
||||||
)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
analyzer.display_statement_count();
|
|
||||||
analyzer.display_statement_size();
|
|
||||||
analyzer.display_phaser_costs(args.cost_scale);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//! The revive explorer YUL phaser utility library.
|
|
||||||
//!
|
|
||||||
//! This can be used to invoke the `yul-phaser` utility,
|
|
||||||
//! used to find better YUL optimizer sequences.
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::{Command, Stdio},
|
|
||||||
thread,
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The `yul-phaser` sane default arguments:
|
|
||||||
/// - Less verbose output.
|
|
||||||
/// - Sufficient rounds.
|
|
||||||
/// - Sufficient random population start.
|
|
||||||
const ARGUMENTS: [&str; 6] = [
|
|
||||||
"--hide-round",
|
|
||||||
"--rounds",
|
|
||||||
"1000",
|
|
||||||
"--random-population",
|
|
||||||
"100",
|
|
||||||
"--show-only-top-chromosome",
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Run multiple YUL phaser executables in parallel.
|
|
||||||
pub fn run(
|
|
||||||
executable: &Path,
|
|
||||||
source: &Path,
|
|
||||||
costs: &[(String, u64)],
|
|
||||||
n_threads: usize,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut handles = Vec::with_capacity(n_threads);
|
|
||||||
|
|
||||||
for n in 0..n_threads {
|
|
||||||
let executable = executable.to_path_buf();
|
|
||||||
let source = source.to_path_buf();
|
|
||||||
let costs = costs.to_vec();
|
|
||||||
|
|
||||||
handles.push(thread::spawn(move || {
|
|
||||||
spawn_process(executable, source, costs, n)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for handle in handles {
|
|
||||||
let _ = handle.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `yul-phaser` process spawning helper function.
|
|
||||||
fn spawn_process(
|
|
||||||
executable: PathBuf,
|
|
||||||
source: PathBuf,
|
|
||||||
costs: Vec<(String, u64)>,
|
|
||||||
seed: usize,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let cost_parameters = costs
|
|
||||||
.iter()
|
|
||||||
.flat_map(|(parameter, cost)| vec![parameter.clone(), cost.to_string()]);
|
|
||||||
|
|
||||||
let secs = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.expect("Time went backwards")
|
|
||||||
.as_secs();
|
|
||||||
|
|
||||||
Command::new(executable)
|
|
||||||
.args(cost_parameters)
|
|
||||||
.args(ARGUMENTS)
|
|
||||||
.arg("--seed")
|
|
||||||
.arg((seed + secs as usize).to_string())
|
|
||||||
.arg(source)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.spawn()?
|
|
||||||
.wait()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"Baseline": 960,
|
"Baseline": 939,
|
||||||
"Computation": 2367,
|
"Computation": 2282,
|
||||||
"DivisionArithmetics": 9108,
|
"DivisionArithmetics": 8849,
|
||||||
"ERC20": 17655,
|
"ERC20": 18308,
|
||||||
"Events": 1680,
|
"Events": 1640,
|
||||||
"FibonacciIterative": 1536,
|
"FibonacciIterative": 1497,
|
||||||
"Flipper": 2137,
|
"Flipper": 2099,
|
||||||
"SHA1": 8299
|
"SHA1": 8243
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFun
|
|||||||
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
|
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
|
||||||
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
|
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
|
||||||
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
|
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
|
||||||
|
pub use self::polkavm::context::function::runtime::arithmetics::Addition as PolkaVMAdditionFunction;
|
||||||
pub use self::polkavm::context::function::runtime::arithmetics::Division as PolkaVMDivisionFunction;
|
pub use self::polkavm::context::function::runtime::arithmetics::Division as PolkaVMDivisionFunction;
|
||||||
pub use self::polkavm::context::function::runtime::arithmetics::Remainder as PolkaVMRemainderFunction;
|
pub use self::polkavm::context::function::runtime::arithmetics::Remainder as PolkaVMRemainderFunction;
|
||||||
pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision as PolkaVMSignedDivisionFunction;
|
pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision as PolkaVMSignedDivisionFunction;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub mod r#return;
|
|||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod yul_data;
|
pub mod yul_data;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
use inkwell::debug_info::AsDIScope;
|
use inkwell::debug_info::AsDIScope;
|
||||||
|
|
||||||
@@ -29,6 +29,10 @@ pub struct Function<'ctx> {
|
|||||||
declaration: Declaration<'ctx>,
|
declaration: Declaration<'ctx>,
|
||||||
/// The stack representation.
|
/// The stack representation.
|
||||||
stack: HashMap<String, Pointer<'ctx>>,
|
stack: HashMap<String, Pointer<'ctx>>,
|
||||||
|
/// The stack variables buffer.
|
||||||
|
stack_variables: inkwell::values::GlobalValue<'ctx>,
|
||||||
|
/// The stack variable names to slot mapping.
|
||||||
|
stack_slots: BTreeMap<String, usize>,
|
||||||
/// The return value entity.
|
/// The return value entity.
|
||||||
r#return: Return<'ctx>,
|
r#return: Return<'ctx>,
|
||||||
|
|
||||||
@@ -53,6 +57,7 @@ impl<'ctx> Function<'ctx> {
|
|||||||
name: String,
|
name: String,
|
||||||
declaration: Declaration<'ctx>,
|
declaration: Declaration<'ctx>,
|
||||||
r#return: Return<'ctx>,
|
r#return: Return<'ctx>,
|
||||||
|
stack_variables: inkwell::values::GlobalValue<'ctx>,
|
||||||
|
|
||||||
entry_block: inkwell::basic_block::BasicBlock<'ctx>,
|
entry_block: inkwell::basic_block::BasicBlock<'ctx>,
|
||||||
return_block: inkwell::basic_block::BasicBlock<'ctx>,
|
return_block: inkwell::basic_block::BasicBlock<'ctx>,
|
||||||
@@ -61,6 +66,8 @@ impl<'ctx> Function<'ctx> {
|
|||||||
name,
|
name,
|
||||||
declaration,
|
declaration,
|
||||||
stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY),
|
stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY),
|
||||||
|
stack_variables,
|
||||||
|
stack_slots: BTreeMap::new(),
|
||||||
r#return,
|
r#return,
|
||||||
|
|
||||||
entry_block,
|
entry_block,
|
||||||
@@ -279,4 +286,45 @@ impl<'ctx> Function<'ctx> {
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("The Yul data must have been initialized")
|
.expect("The Yul data must have been initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the stack variables global value.
|
||||||
|
pub fn stack_variables(&self) -> inkwell::values::GlobalValue<'ctx> {
|
||||||
|
self.stack_variables
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the slot for the given variable name.
|
||||||
|
pub fn stack_variable_slot(&mut self, name: String) -> usize {
|
||||||
|
let len = self.stack_slots.len();
|
||||||
|
*self.stack_slots.entry(name).or_insert_with(|| len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// References the stack variable `name`.
|
||||||
|
pub fn stack_variable_pointer<D: crate::PolkaVMDependency + Clone>(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
context: &mut super::Context<'ctx, D>,
|
||||||
|
) -> Pointer<'ctx> {
|
||||||
|
if let Some(pointer) = self.get_stack_pointer(&name) {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pointer_name = format!("var_{}", &name);
|
||||||
|
let slot = self.stack_variable_slot(name);
|
||||||
|
Pointer::new(
|
||||||
|
context.word_type(),
|
||||||
|
Default::default(),
|
||||||
|
unsafe {
|
||||||
|
context.builder().build_gep(
|
||||||
|
context.word_type().array_type(0),
|
||||||
|
self.stack_variables().as_pointer_value(),
|
||||||
|
&[
|
||||||
|
context.xlen_type().const_zero(),
|
||||||
|
context.xlen_type().const_int(slot as u64, false),
|
||||||
|
],
|
||||||
|
&pointer_name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,65 @@ use crate::polkavm::context::Context;
|
|||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
use crate::polkavm::WriteLLVM;
|
use crate::polkavm::WriteLLVM;
|
||||||
|
|
||||||
|
/// Implements the division operator according to the EVM specification.
|
||||||
|
pub struct Addition;
|
||||||
|
|
||||||
|
impl<D> RuntimeFunction<D> for Addition
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
const NAME: &'static str = "__revive_addition";
|
||||||
|
|
||||||
|
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
|
||||||
|
context.void_type().fn_type(
|
||||||
|
&[
|
||||||
|
context.llvm().ptr_type(Default::default()).into(),
|
||||||
|
context.llvm().ptr_type(Default::default()).into(),
|
||||||
|
context.llvm().ptr_type(Default::default()).into(),
|
||||||
|
],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_body<'ctx>(
|
||||||
|
&self,
|
||||||
|
context: &mut Context<'ctx, D>,
|
||||||
|
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
|
||||||
|
let result_pointer = Self::paramater(context, 0).into_pointer_value();
|
||||||
|
let operand_1 = Self::paramater(context, 1).into_pointer_value();
|
||||||
|
let operand_2 = Self::paramater(context, 2).into_pointer_value();
|
||||||
|
|
||||||
|
let operand_1 = context
|
||||||
|
.builder()
|
||||||
|
.build_load(context.word_type(), operand_1, "operand_1")?
|
||||||
|
.into_int_value();
|
||||||
|
let operand_2 = context
|
||||||
|
.builder()
|
||||||
|
.build_load(context.word_type(), operand_2, "operand_2")?
|
||||||
|
.into_int_value();
|
||||||
|
let result = context
|
||||||
|
.builder()
|
||||||
|
.build_int_add(operand_1, operand_2, "addition_result")?;
|
||||||
|
|
||||||
|
context.builder().build_store(result_pointer, result)?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> WriteLLVM<D> for Addition
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::declare(self, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::emit(&self, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implements the division operator according to the EVM specification.
|
/// Implements the division operator according to the EVM specification.
|
||||||
pub struct Division;
|
pub struct Division;
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ where
|
|||||||
function_type,
|
function_type,
|
||||||
0,
|
0,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.inner.declare(context)
|
self.inner.declare(context)
|
||||||
@@ -75,6 +74,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.set_basic_block(context.current_function().borrow().return_block());
|
context.set_basic_block(context.current_function().borrow().return_block());
|
||||||
|
context.set_debug_location(0, 0, None)?;
|
||||||
context.build_return(None);
|
context.build_return(None);
|
||||||
|
|
||||||
context.pop_debug_scope();
|
context.pop_debug_scope();
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ where
|
|||||||
entry_function_type,
|
entry_function_type,
|
||||||
0,
|
0,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
context.declare_global(
|
context.declare_global(
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ where
|
|||||||
function_type,
|
function_type,
|
||||||
0,
|
0,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.inner.declare(context)
|
self.inner.declare(context)
|
||||||
|
|||||||
@@ -463,7 +463,6 @@ where
|
|||||||
r#type: inkwell::types::FunctionType<'ctx>,
|
r#type: inkwell::types::FunctionType<'ctx>,
|
||||||
return_values_length: usize,
|
return_values_length: usize,
|
||||||
linkage: Option<inkwell::module::Linkage>,
|
linkage: Option<inkwell::module::Linkage>,
|
||||||
location: Option<(u32, u32)>,
|
|
||||||
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
|
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
|
||||||
let value = self.module().add_function(name, r#type, linkage);
|
let value = self.module().add_function(name, r#type, linkage);
|
||||||
|
|
||||||
@@ -479,8 +478,7 @@ where
|
|||||||
Some(scp) => scp,
|
Some(scp) => scp,
|
||||||
};
|
};
|
||||||
self.push_debug_scope(func_scope.as_debug_info_scope());
|
self.push_debug_scope(func_scope.as_debug_info_scope());
|
||||||
let (line, column) = location.unwrap_or((0, 0));
|
self.set_debug_location(0, 0, Some(func_scope.as_debug_info_scope()))?;
|
||||||
self.set_debug_location(line, column, Some(func_scope.as_debug_info_scope()))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_block = self.llvm.append_basic_block(value, "entry");
|
let entry_block = self.llvm.append_basic_block(value, "entry");
|
||||||
@@ -505,10 +503,17 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let stack_variables = format!("__vars_{name}");
|
||||||
|
self.declare_global(
|
||||||
|
&stack_variables,
|
||||||
|
self.word_type().array_type(0),
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
let function = Function::new(
|
let function = Function::new(
|
||||||
name.to_owned(),
|
name.to_owned(),
|
||||||
FunctionDeclaration::new(r#type, value),
|
FunctionDeclaration::new(r#type, value),
|
||||||
r#return,
|
r#return,
|
||||||
|
self.get_global(&stack_variables).unwrap().value,
|
||||||
entry_block,
|
entry_block,
|
||||||
return_block,
|
return_block,
|
||||||
);
|
);
|
||||||
@@ -535,11 +540,7 @@ where
|
|||||||
|
|
||||||
/// Sets the current active function. If debug-info generation is enabled,
|
/// Sets the current active function. If debug-info generation is enabled,
|
||||||
/// constructs a debug-scope and pushes in on the scope-stack.
|
/// constructs a debug-scope and pushes in on the scope-stack.
|
||||||
pub fn set_current_function(
|
pub fn set_current_function(&mut self, name: &str, line: Option<u32>) -> anyhow::Result<()> {
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
location: Option<(u32, u32)>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let function = self.functions.get(name).cloned().ok_or_else(|| {
|
let function = self.functions.get(name).cloned().ok_or_else(|| {
|
||||||
anyhow::anyhow!("Failed to activate an undeclared function `{}`", name)
|
anyhow::anyhow!("Failed to activate an undeclared function `{}`", name)
|
||||||
})?;
|
})?;
|
||||||
@@ -548,8 +549,7 @@ where
|
|||||||
if let Some(scope) = self.current_function().borrow().get_debug_scope() {
|
if let Some(scope) = self.current_function().borrow().get_debug_scope() {
|
||||||
self.push_debug_scope(scope);
|
self.push_debug_scope(scope);
|
||||||
}
|
}
|
||||||
let (line, column) = location.unwrap_or_default();
|
self.set_debug_location(line.unwrap_or_default(), 0, None)?;
|
||||||
self.set_debug_location(line, column, None)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -730,23 +730,17 @@ where
|
|||||||
r#type: T,
|
r#type: T,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Pointer<'ctx> {
|
) -> Pointer<'ctx> {
|
||||||
// TODO: Revisit. While at entry should be preferred in theory:
|
let current_block = self.basic_block();
|
||||||
// - It has negligible code size impact on real word contracts.
|
let entry_block = self.current_function().borrow().entry_block();
|
||||||
// - Sometimes has negative impact on code size.
|
|
||||||
// - Messes up debug information used to analyze code size issues.
|
|
||||||
self.build_alloca(r#type, name)
|
|
||||||
|
|
||||||
// let current_block = self.basic_block();
|
match entry_block.get_first_instruction() {
|
||||||
// let entry_block = self.current_function().borrow().entry_block();
|
Some(instruction) => self.builder().position_before(&instruction),
|
||||||
|
None => self.builder().position_at_end(entry_block),
|
||||||
|
}
|
||||||
|
|
||||||
// match entry_block.get_first_instruction() {
|
let pointer = self.build_alloca(r#type, name);
|
||||||
// Some(instruction) => self.builder().position_before(&instruction),
|
self.set_basic_block(current_block);
|
||||||
// None => self.builder().position_at_end(entry_block),
|
pointer
|
||||||
// }
|
|
||||||
|
|
||||||
// let pointer = self.build_alloca(r#type, name);
|
|
||||||
// self.set_basic_block(current_block);
|
|
||||||
// pointer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds an aligned stack allocation at the current position.
|
/// Builds an aligned stack allocation at the current position.
|
||||||
@@ -1284,6 +1278,20 @@ where
|
|||||||
where
|
where
|
||||||
T: BasicType<'ctx>,
|
T: BasicType<'ctx>,
|
||||||
{
|
{
|
||||||
|
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> =
|
||||||
|
vec![self.llvm().ptr_type(Default::default()).into(); return_values_size]
|
||||||
|
.into_iter()
|
||||||
|
.chain(
|
||||||
|
argument_types
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(T::as_basic_type_enum)
|
||||||
|
.map(inkwell::types::BasicMetadataTypeEnum::from),
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
self.void_type().fn_type(&argument_types.as_slice(), false)
|
||||||
|
|
||||||
|
/*
|
||||||
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> = argument_types
|
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> = argument_types
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1300,6 +1308,7 @@ where
|
|||||||
.structure_type(vec![self.word_type().as_basic_type_enum(); size].as_slice())
|
.structure_type(vec![self.word_type().as_basic_type_enum(); size].as_slice())
|
||||||
.fn_type(argument_types.as_slice(), false),
|
.fn_type(argument_types.as_slice(), false),
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modifies the call site value, setting the default attributes.
|
/// Modifies the call site value, setting the default attributes.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::polkavm::context::Context;
|
|||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
|
|
||||||
pub mod heap;
|
pub mod heap;
|
||||||
|
//pub mod stack;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
|
||||||
/// The LLVM pointer.
|
/// The LLVM pointer.
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//! The revive simulated EVM stack variable functions.
|
||||||
|
|
||||||
|
use inkwell::values::BasicValueEnum;
|
||||||
|
|
||||||
|
use crate::polkavm::context::runtime::RuntimeFunction;
|
||||||
|
use crate::polkavm::context::Context;
|
||||||
|
use crate::polkavm::Dependency;
|
||||||
|
use crate::polkavm::WriteLLVM;
|
||||||
|
|
||||||
|
/// Load a word size value from a heap pointer.
|
||||||
|
pub struct DeclareVariable;
|
||||||
|
|
||||||
|
impl<D> RuntimeFunction<D> for DeclareVariable
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
const NAME: &'static str = "__revive_declare_variable";
|
||||||
|
|
||||||
|
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
|
||||||
|
context
|
||||||
|
.llvm
|
||||||
|
.ptr_type(Default::default())
|
||||||
|
.fn_type(&[context.xlen_type().into()], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_body<'ctx>(
|
||||||
|
&self,
|
||||||
|
context: &mut Context<'ctx, D>,
|
||||||
|
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
|
||||||
|
let offset = Self::paramater(context, 0).into_int_value();
|
||||||
|
let length = context
|
||||||
|
.xlen_type()
|
||||||
|
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
|
||||||
|
let pointer = context.build_heap_gep(offset, length)?;
|
||||||
|
let value = context
|
||||||
|
.builder()
|
||||||
|
.build_load(context.word_type(), pointer.value, "value")?;
|
||||||
|
context
|
||||||
|
.basic_block()
|
||||||
|
.get_last_instruction()
|
||||||
|
.expect("Always exists")
|
||||||
|
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
|
||||||
|
.expect("Alignment is valid");
|
||||||
|
|
||||||
|
let swapped_value = context.build_byte_swap(value)?;
|
||||||
|
Ok(Some(swapped_value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> WriteLLVM<D> for LoadWord
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::declare(self, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::emit(&self, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store a word size value through a heap pointer.
|
||||||
|
pub struct StoreWord;
|
||||||
|
|
||||||
|
impl<D> RuntimeFunction<D> for StoreWord
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
const NAME: &'static str = "__revive_store_heap_word";
|
||||||
|
|
||||||
|
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
|
||||||
|
context.void_type().fn_type(
|
||||||
|
&[context.xlen_type().into(), context.word_type().into()],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_body<'ctx>(
|
||||||
|
&self,
|
||||||
|
context: &mut Context<'ctx, D>,
|
||||||
|
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
|
||||||
|
let offset = Self::paramater(context, 0).into_int_value();
|
||||||
|
let length = context
|
||||||
|
.xlen_type()
|
||||||
|
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
|
||||||
|
let pointer = context.build_heap_gep(offset, length)?;
|
||||||
|
|
||||||
|
let value = context.build_byte_swap(Self::paramater(context, 1))?;
|
||||||
|
|
||||||
|
context
|
||||||
|
.builder()
|
||||||
|
.build_store(pointer.value, value)?
|
||||||
|
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
|
||||||
|
.expect("Alignment is valid");
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> WriteLLVM<D> for StoreWord
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::declare(self, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||||
|
<Self as RuntimeFunction<_>>::emit(&self, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@ where
|
|||||||
Self::r#type(context),
|
Self::r#type(context),
|
||||||
0,
|
0,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut attributes = Self::ATTRIBUTES.to_vec();
|
let mut attributes = Self::ATTRIBUTES.to_vec();
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ pub fn check_attribute_null_pointer_is_invalid() {
|
|||||||
.fn_type(&[context.word_type().into()], false),
|
.fn_type(&[context.word_type().into()], false),
|
||||||
1,
|
1,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.expect("Failed to add function");
|
.expect("Failed to add function");
|
||||||
assert!(!function
|
assert!(!function
|
||||||
@@ -64,7 +63,6 @@ pub fn check_attribute_optimize_for_size_mode_3() {
|
|||||||
.fn_type(&[context.word_type().into()], false),
|
.fn_type(&[context.word_type().into()], false),
|
||||||
1,
|
1,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.expect("Failed to add function");
|
.expect("Failed to add function");
|
||||||
assert!(!function
|
assert!(!function
|
||||||
@@ -88,7 +86,6 @@ pub fn check_attribute_optimize_for_size_mode_z() {
|
|||||||
.fn_type(&[context.word_type().into()], false),
|
.fn_type(&[context.word_type().into()], false),
|
||||||
1,
|
1,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.expect("Failed to add function");
|
.expect("Failed to add function");
|
||||||
assert!(function
|
assert!(function
|
||||||
@@ -112,7 +109,6 @@ pub fn check_attribute_min_size_mode_3() {
|
|||||||
.fn_type(&[context.word_type().into()], false),
|
.fn_type(&[context.word_type().into()], false),
|
||||||
1,
|
1,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.expect("Failed to add function");
|
.expect("Failed to add function");
|
||||||
assert!(!function
|
assert!(!function
|
||||||
@@ -136,7 +132,6 @@ pub fn check_attribute_min_size_mode_z() {
|
|||||||
.fn_type(&[context.word_type().into()], false),
|
.fn_type(&[context.word_type().into()], false),
|
||||||
1,
|
1,
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.expect("Failed to add function");
|
.expect("Failed to add function");
|
||||||
assert!(function
|
assert!(function
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use inkwell::values::BasicValue;
|
|||||||
use crate::polkavm::context::runtime::RuntimeFunction;
|
use crate::polkavm::context::runtime::RuntimeFunction;
|
||||||
use crate::polkavm::context::Context;
|
use crate::polkavm::context::Context;
|
||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
|
use crate::PolkaVMAdditionFunction;
|
||||||
use crate::PolkaVMDivisionFunction;
|
use crate::PolkaVMDivisionFunction;
|
||||||
use crate::PolkaVMRemainderFunction;
|
use crate::PolkaVMRemainderFunction;
|
||||||
use crate::PolkaVMSignedDivisionFunction;
|
use crate::PolkaVMSignedDivisionFunction;
|
||||||
@@ -13,16 +14,20 @@ use crate::PolkaVMSignedRemainderFunction;
|
|||||||
/// Translates the arithmetic addition.
|
/// Translates the arithmetic addition.
|
||||||
pub fn addition<'ctx, D>(
|
pub fn addition<'ctx, D>(
|
||||||
context: &mut Context<'ctx, D>,
|
context: &mut Context<'ctx, D>,
|
||||||
operand_1: inkwell::values::IntValue<'ctx>,
|
binding: inkwell::values::PointerValue<'ctx>,
|
||||||
operand_2: inkwell::values::IntValue<'ctx>,
|
operand_1: inkwell::values::PointerValue<'ctx>,
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
operand_2: inkwell::values::PointerValue<'ctx>,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
Ok(context
|
let declaration = <PolkaVMAdditionFunction as RuntimeFunction<D>>::declaration(context);
|
||||||
.builder()
|
context.build_call(
|
||||||
.build_int_add(operand_1, operand_2, "addition_result")?
|
declaration,
|
||||||
.as_basic_value_enum())
|
&[binding.into(), operand_1.into(), operand_2.into()],
|
||||||
|
"add",
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the arithmetic subtraction.
|
/// Translates the arithmetic subtraction.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use self::file::File as FileSelection;
|
|||||||
pub struct Selection {
|
pub struct Selection {
|
||||||
/// Only the 'all' wildcard is available for robustness reasons.
|
/// Only the 'all' wildcard is available for robustness reasons.
|
||||||
#[serde(rename = "*", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "*", skip_serializing_if = "Option::is_none")]
|
||||||
pub all: Option<FileSelection>,
|
all: Option<FileSelection>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "BTreeMap::is_empty", flatten)]
|
#[serde(skip_serializing_if = "BTreeMap::is_empty", flatten)]
|
||||||
pub files: BTreeMap<String, FileSelection>,
|
pub files: BTreeMap<String, FileSelection>,
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
//! The lexical token location.
|
//! The lexical token location.
|
||||||
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::hash::Hasher;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
@@ -51,13 +48,6 @@ impl PartialEq for Location {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Location {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.line.hash(state);
|
|
||||||
self.column.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Location {
|
impl std::fmt::Display for Location {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}:{}", self.line, self.column)
|
write!(f, "{}:{}", self.line, self.column)
|
||||||
|
|||||||
@@ -115,13 +115,29 @@ impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for Assignment
|
|||||||
where
|
where
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
fn into_llvm(
|
fn into_llvm<'ctx>(
|
||||||
mut self,
|
mut self,
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
let value = match self.initializer.into_llvm(context)? {
|
let bindings: Vec<(String, revive_llvm_context::PolkaVMPointer<'ctx>)> = self
|
||||||
|
.bindings
|
||||||
|
.into_iter()
|
||||||
|
.map(|binding| {
|
||||||
|
(
|
||||||
|
binding.inner.clone(),
|
||||||
|
context
|
||||||
|
.current_function()
|
||||||
|
.borrow_mut()
|
||||||
|
.stack_variable_pointer(binding.inner, context),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.initializer.into_llvm(bindings.as_slice(), context)?;
|
||||||
|
/*
|
||||||
|
let value = match self.initializer.into_llvm(bindings.as_slice(), context)? {
|
||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@@ -149,7 +165,7 @@ where
|
|||||||
context.build_store(tuple_pointer, value)?;
|
context.build_store(tuple_pointer, value)?;
|
||||||
|
|
||||||
for (index, binding) in self.bindings.into_iter().enumerate() {
|
for (index, binding) in self.bindings.into_iter().enumerate() {
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
let field_pointer = context.build_gep(
|
let field_pointer = context.build_gep(
|
||||||
tuple_pointer,
|
tuple_pointer,
|
||||||
@@ -181,6 +197,8 @@ where
|
|||||||
context.build_store(binding_pointer, value)?;
|
context.build_store(binding_pointer, value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,10 +155,7 @@ where
|
|||||||
function.into_llvm(context)?;
|
function.into_llvm(context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.set_current_function(
|
context.set_current_function(current_function.as_str(), Some(self.location.line))?;
|
||||||
current_function.as_str(),
|
|
||||||
Some((self.location.line, self.location.column)),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(debug_info) = context.debug_info() {
|
if let Some(debug_info) = context.debug_info() {
|
||||||
let di_builder = debug_info.builder();
|
let di_builder = debug_info.builder();
|
||||||
@@ -172,16 +169,12 @@ where
|
|||||||
)
|
)
|
||||||
.as_debug_info_scope();
|
.as_debug_info_scope();
|
||||||
context.push_debug_scope(di_block_scope);
|
context.push_debug_scope(di_block_scope);
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.set_basic_block(current_block);
|
context.set_basic_block(current_block);
|
||||||
for statement in local_statements.into_iter() {
|
for statement in local_statements.into_iter() {
|
||||||
context.set_debug_location(
|
context.set_debug_location(statement.location().line, 0, None)?;
|
||||||
statement.location().line,
|
|
||||||
statement.location().column,
|
|
||||||
None,
|
|
||||||
)?;
|
|
||||||
if context.basic_block().get_terminator().is_some() {
|
if context.basic_block().get_terminator().is_some() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -191,7 +184,7 @@ where
|
|||||||
block.into_llvm(context)?;
|
block.into_llvm(context)?;
|
||||||
}
|
}
|
||||||
Statement::Expression(expression) => {
|
Statement::Expression(expression) => {
|
||||||
expression.into_llvm(context)?;
|
expression.into_llvm(&[], context)?;
|
||||||
}
|
}
|
||||||
Statement::VariableDeclaration(statement) => statement.into_llvm(context)?,
|
Statement::VariableDeclaration(statement) => statement.into_llvm(context)?,
|
||||||
Statement::Assignment(statement) => statement.into_llvm(context)?,
|
Statement::Assignment(statement) => statement.into_llvm(context)?,
|
||||||
|
|||||||
@@ -117,25 +117,37 @@ impl FunctionCall {
|
|||||||
/// Converts the function call into an LLVM value.
|
/// Converts the function call into an LLVM value.
|
||||||
pub fn into_llvm<'ctx, D>(
|
pub fn into_llvm<'ctx, D>(
|
||||||
mut self,
|
mut self,
|
||||||
|
bindings: &[(String, revive_llvm_context::PolkaVMPointer<'ctx>)],
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
||||||
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>>
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
let location = self.location;
|
let location = self.location;
|
||||||
context.set_debug_location(location.line, location.column, None)?;
|
context.set_debug_location(location.line, 0, None)?;
|
||||||
|
|
||||||
match self.name {
|
match self.name {
|
||||||
Name::UserDefined(name) => {
|
Name::UserDefined(name) => {
|
||||||
let mut values = Vec::with_capacity(self.arguments.len());
|
let mut values = Vec::with_capacity(bindings.len() + self.arguments.len());
|
||||||
for argument in self.arguments.into_iter().rev() {
|
for (n, argument) in self.arguments.into_iter().rev().enumerate() {
|
||||||
|
let id = format!("arg_{n}");
|
||||||
|
let binding_pointer = context.build_alloca(context.word_type(), &id);
|
||||||
let value = argument
|
let value = argument
|
||||||
.into_llvm(context)?
|
.into_llvm(&[(id, binding_pointer)], context)?
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.access(context)?;
|
.as_pointer(context)?
|
||||||
|
.value
|
||||||
|
.as_basic_value_enum();
|
||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
values.reverse();
|
values.reverse();
|
||||||
|
|
||||||
|
let values = bindings
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, pointer)| pointer.value.as_basic_value_enum())
|
||||||
|
.chain(values.into_iter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let function = context.get_function(name.as_str()).ok_or_else(|| {
|
let function = context.get_function(name.as_str()).ok_or_else(|| {
|
||||||
anyhow::anyhow!("{} Undeclared function `{}`", location, name)
|
anyhow::anyhow!("{} Undeclared function `{}`", location, name)
|
||||||
})?;
|
})?;
|
||||||
@@ -152,23 +164,24 @@ impl FunctionCall {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = context.build_call(
|
let _return_value = context.build_call(
|
||||||
function.borrow().declaration(),
|
function.borrow().declaration(),
|
||||||
values.as_slice(),
|
values.as_slice(),
|
||||||
format!("{name}_call").as_str(),
|
format!("{name}_call").as_str(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(return_value)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Name::Add => {
|
Name::Add => {
|
||||||
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
||||||
revive_llvm_context::polkavm_evm_arithmetic::addition(
|
revive_llvm_context::polkavm_evm_arithmetic::addition(
|
||||||
context,
|
context,
|
||||||
arguments[0].into_int_value(),
|
bindings,
|
||||||
arguments[1].into_int_value(),
|
arguments[0].into_pointer_value(),
|
||||||
)
|
arguments[1].into_pointer_value(),
|
||||||
.map(Some)
|
)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Name::Sub => {
|
Name::Sub => {
|
||||||
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
||||||
@@ -987,18 +1000,18 @@ impl FunctionCall {
|
|||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
let mut arguments = Vec::with_capacity(N);
|
let mut arguments = Vec::with_capacity(N);
|
||||||
for expression in self.arguments.drain(0..N).rev() {
|
for (index, expression) in self.arguments.drain(0..N).rev().enumerate() {
|
||||||
|
let name = format!("arg_{index}");
|
||||||
|
let pointer = context.build_alloca(context.word_type(), &name);
|
||||||
arguments.push(
|
arguments.push(
|
||||||
expression
|
expression
|
||||||
.into_llvm(context)?
|
.into_llvm(&[(name, pointer)], context)?
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.access(context)?,
|
.access(context)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
arguments.reverse();
|
arguments.reverse();
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
|
|
||||||
Ok(arguments.try_into().expect("Always successful"))
|
Ok(arguments.try_into().expect("Always successful"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,13 +1024,17 @@ impl FunctionCall {
|
|||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
let mut arguments = Vec::with_capacity(N);
|
let mut arguments = Vec::with_capacity(N);
|
||||||
for expression in self.arguments.drain(0..N).rev() {
|
for (index, expression) in self.arguments.drain(0..N).rev().enumerate() {
|
||||||
arguments.push(expression.into_llvm(context)?.expect("Always exists"));
|
let name = format!("arg_{index}");
|
||||||
|
let pointer = context.build_alloca(context.word_type(), &name);
|
||||||
|
arguments.push(
|
||||||
|
expression
|
||||||
|
.into_llvm(&[(name, pointer)], context)?
|
||||||
|
.expect("Always exists"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
arguments.reverse();
|
arguments.reverse();
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
|
|
||||||
Ok(arguments.try_into().expect("Always successful"))
|
Ok(arguments.try_into().expect("Always successful"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ impl Literal {
|
|||||||
/// Converts the literal into its LLVM.
|
/// Converts the literal into its LLVM.
|
||||||
pub fn into_llvm<'ctx, D>(
|
pub fn into_llvm<'ctx, D>(
|
||||||
self,
|
self,
|
||||||
|
binding: Option<(String, revive_llvm_context::PolkaVMPointer<'ctx>)>,
|
||||||
context: &revive_llvm_context::PolkaVMContext<'ctx, D>,
|
context: &revive_llvm_context::PolkaVMContext<'ctx, D>,
|
||||||
) -> anyhow::Result<revive_llvm_context::PolkaVMArgument<'ctx>>
|
) -> anyhow::Result<revive_llvm_context::PolkaVMArgument<'ctx>>
|
||||||
where
|
where
|
||||||
@@ -97,7 +98,17 @@ impl Literal {
|
|||||||
BooleanLiteral::True => num::BigUint::one(),
|
BooleanLiteral::True => num::BigUint::one(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
|
match binding {
|
||||||
|
Some((id, pointer)) => {
|
||||||
|
context.build_store(pointer, value)?;
|
||||||
|
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
|
||||||
|
.with_constant(constant))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
Ok(revive_llvm_context::PolkaVMArgument::value(value)
|
||||||
|
.with_constant(constant))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LexicalLiteral::Integer(inner) => {
|
LexicalLiteral::Integer(inner) => {
|
||||||
let r#type = self.yul_type.unwrap_or_default().into_llvm(context);
|
let r#type = self.yul_type.unwrap_or_default().into_llvm(context);
|
||||||
@@ -125,7 +136,17 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
.expect("Always valid");
|
.expect("Always valid");
|
||||||
|
|
||||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
|
match binding {
|
||||||
|
Some((id, pointer)) => {
|
||||||
|
context.build_store(pointer, value)?;
|
||||||
|
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
|
||||||
|
.with_constant(constant))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
Ok(revive_llvm_context::PolkaVMArgument::value(value)
|
||||||
|
.with_constant(constant))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LexicalLiteral::String(inner) => {
|
LexicalLiteral::String(inner) => {
|
||||||
let string = inner.inner;
|
let string = inner.inner;
|
||||||
@@ -216,7 +237,16 @@ impl Literal {
|
|||||||
)
|
)
|
||||||
.expect("The value is valid")
|
.expect("The value is valid")
|
||||||
.as_basic_value_enum();
|
.as_basic_value_enum();
|
||||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_original(string))
|
match binding {
|
||||||
|
Some((id, pointer)) => {
|
||||||
|
context.build_store(pointer, value)?;
|
||||||
|
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
|
||||||
|
.with_original(string))
|
||||||
|
}
|
||||||
|
None => Ok(
|
||||||
|
revive_llvm_context::PolkaVMArgument::value(value).with_original(string)
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ impl Expression {
|
|||||||
/// Converts the expression into an LLVM value.
|
/// Converts the expression into an LLVM value.
|
||||||
pub fn into_llvm<'ctx, D>(
|
pub fn into_llvm<'ctx, D>(
|
||||||
self,
|
self,
|
||||||
|
bindings: &[(String, revive_llvm_context::PolkaVMPointer<'ctx>)],
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
||||||
) -> anyhow::Result<Option<revive_llvm_context::PolkaVMArgument<'ctx>>>
|
) -> anyhow::Result<Option<revive_llvm_context::PolkaVMArgument<'ctx>>>
|
||||||
where
|
where
|
||||||
@@ -108,7 +109,13 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
Self::Literal(literal) => literal
|
Self::Literal(literal) => literal
|
||||||
.clone()
|
.clone()
|
||||||
.into_llvm(context)
|
.into_llvm(
|
||||||
|
bindings
|
||||||
|
.first()
|
||||||
|
.to_owned()
|
||||||
|
.map(|(id, binding)| (id.to_string(), *binding)),
|
||||||
|
context,
|
||||||
|
)
|
||||||
.map_err(|error| {
|
.map_err(|error| {
|
||||||
anyhow::anyhow!(
|
anyhow::anyhow!(
|
||||||
"{} Invalid literal `{}`: {}",
|
"{} Invalid literal `{}`: {}",
|
||||||
@@ -138,9 +145,10 @@ impl Expression {
|
|||||||
_ => argument,
|
_ => argument,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Self::FunctionCall(call) => Ok(call
|
Self::FunctionCall(call) => {
|
||||||
.into_llvm(context)?
|
call.into_llvm(bindings, context)?;
|
||||||
.map(revive_llvm_context::PolkaVMArgument::value)),
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,16 +72,15 @@ where
|
|||||||
let increment_block = context.append_basic_block("for_increment");
|
let increment_block = context.append_basic_block("for_increment");
|
||||||
let join_block = context.append_basic_block("for_join");
|
let join_block = context.append_basic_block("for_join");
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
context.build_unconditional_branch(condition_block);
|
context.build_unconditional_branch(condition_block);
|
||||||
context.set_basic_block(condition_block);
|
context.set_basic_block(condition_block);
|
||||||
|
let binding_pointer = context.build_alloca(context.word_type(), "if_condition");
|
||||||
let condition = self
|
let condition = self
|
||||||
.condition
|
.condition
|
||||||
.into_llvm(context)?
|
.into_llvm(&[("todo".to_string(), binding_pointer)], context)?
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.access(context)?
|
.access(context)?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
||||||
condition,
|
condition,
|
||||||
context.word_type(),
|
context.word_type(),
|
||||||
@@ -100,12 +99,10 @@ where
|
|||||||
context.set_basic_block(body_block);
|
context.set_basic_block(body_block);
|
||||||
self.body.into_llvm(context)?;
|
self.body.into_llvm(context)?;
|
||||||
context.build_unconditional_branch(increment_block);
|
context.build_unconditional_branch(increment_block);
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
|
|
||||||
context.set_basic_block(increment_block);
|
context.set_basic_block(increment_block);
|
||||||
self.finalizer.into_llvm(context)?;
|
self.finalizer.into_llvm(context)?;
|
||||||
context.build_unconditional_branch(condition_block);
|
context.build_unconditional_branch(condition_block);
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
|
|
||||||
context.pop_loop();
|
context.pop_loop();
|
||||||
context.set_basic_block(join_block);
|
context.set_basic_block(join_block);
|
||||||
|
|||||||
@@ -196,7 +196,6 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
let argument_types: Vec<_> = self
|
let argument_types: Vec<_> = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter()
|
.iter()
|
||||||
@@ -213,7 +212,6 @@ where
|
|||||||
function_type,
|
function_type,
|
||||||
self.result.len(),
|
self.result.len(),
|
||||||
Some(inkwell::module::Linkage::External),
|
Some(inkwell::module::Linkage::External),
|
||||||
Some((self.location.line, self.location.column)),
|
|
||||||
)?;
|
)?;
|
||||||
revive_llvm_context::PolkaVMFunction::set_attributes(
|
revive_llvm_context::PolkaVMFunction::set_attributes(
|
||||||
context.llvm(),
|
context.llvm(),
|
||||||
@@ -232,12 +230,81 @@ where
|
|||||||
mut self,
|
mut self,
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
context.set_current_function(
|
context.set_current_function(self.identifier.as_str(), Some(self.location.line))?;
|
||||||
self.identifier.as_str(),
|
|
||||||
Some((self.location.line, self.location.column)),
|
|
||||||
)?;
|
|
||||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||||
|
|
||||||
|
let return_types: Vec<_> = self
|
||||||
|
.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|argument| {
|
||||||
|
let yul_type = argument.r#type.to_owned().unwrap_or_default();
|
||||||
|
yul_type.into_llvm(context)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
for (index, argument) in self.result.iter().enumerate() {
|
||||||
|
let pointer = context
|
||||||
|
.current_function()
|
||||||
|
.borrow()
|
||||||
|
.get_nth_param(index)
|
||||||
|
.into_pointer_value();
|
||||||
|
let pointer = revive_llvm_context::PolkaVMPointer::new(
|
||||||
|
return_types[index],
|
||||||
|
Default::default(),
|
||||||
|
pointer,
|
||||||
|
);
|
||||||
|
context.build_store(pointer, pointer.r#type.const_zero())?;
|
||||||
|
context
|
||||||
|
.current_function()
|
||||||
|
.borrow_mut()
|
||||||
|
.insert_stack_pointer(argument.inner.clone(), pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument_types: Vec<_> = self
|
||||||
|
.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|argument| {
|
||||||
|
let yul_type = argument.r#type.to_owned().unwrap_or_default();
|
||||||
|
yul_type.into_llvm(context)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
for (index, argument) in self.arguments.iter().enumerate() {
|
||||||
|
let pointer = context
|
||||||
|
.current_function()
|
||||||
|
.borrow()
|
||||||
|
.get_nth_param(index + self.result.len())
|
||||||
|
.into_pointer_value();
|
||||||
|
let pointer = revive_llvm_context::PolkaVMPointer::new(
|
||||||
|
argument_types[index],
|
||||||
|
Default::default(),
|
||||||
|
pointer,
|
||||||
|
);
|
||||||
|
context
|
||||||
|
.current_function()
|
||||||
|
.borrow_mut()
|
||||||
|
.insert_stack_pointer(argument.inner.clone(), pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.body.into_llvm(context)?;
|
||||||
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
|
match context
|
||||||
|
.basic_block()
|
||||||
|
.get_last_instruction()
|
||||||
|
.map(|instruction| instruction.get_opcode())
|
||||||
|
{
|
||||||
|
Some(inkwell::values::InstructionOpcode::Br) => {}
|
||||||
|
Some(inkwell::values::InstructionOpcode::Switch) => {}
|
||||||
|
_ => context
|
||||||
|
.build_unconditional_branch(context.current_function().borrow().return_block()),
|
||||||
|
}
|
||||||
|
|
||||||
|
context.set_basic_block(context.current_function().borrow().return_block());
|
||||||
|
context.build_return(None);
|
||||||
|
|
||||||
|
context.pop_debug_scope();
|
||||||
|
|
||||||
|
/*
|
||||||
let r#return = context.current_function().borrow().r#return();
|
let r#return = context.current_function().borrow().r#return();
|
||||||
match r#return {
|
match r#return {
|
||||||
revive_llvm_context::PolkaVMFunctionReturn::None => {}
|
revive_llvm_context::PolkaVMFunctionReturn::None => {}
|
||||||
@@ -295,7 +362,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.body.into_llvm(context)?;
|
self.body.into_llvm(context)?;
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
match context
|
match context
|
||||||
.basic_block()
|
.basic_block()
|
||||||
@@ -324,6 +391,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.pop_debug_scope();
|
context.pop_debug_scope();
|
||||||
|
*/
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,13 +53,14 @@ where
|
|||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
||||||
|
let binding_pointer = context.build_alloca(context.word_type(), "if_condition");
|
||||||
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
let condition = self
|
let condition = self
|
||||||
.condition
|
.condition
|
||||||
.into_llvm(context)?
|
.into_llvm(&[("todo".to_string(), binding_pointer)], context)?
|
||||||
.expect("Always exists")
|
.expect("Always exists")
|
||||||
.access(context)?
|
.access(context)?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
||||||
condition,
|
condition,
|
||||||
context.word_type(),
|
context.word_type(),
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ where
|
|||||||
revive_llvm_context::PolkaVMEventLogFunction::<3>.declare(context)?;
|
revive_llvm_context::PolkaVMEventLogFunction::<3>.declare(context)?;
|
||||||
revive_llvm_context::PolkaVMEventLogFunction::<4>.declare(context)?;
|
revive_llvm_context::PolkaVMEventLogFunction::<4>.declare(context)?;
|
||||||
|
|
||||||
|
revive_llvm_context::PolkaVMAdditionFunction.declare(context)?;
|
||||||
revive_llvm_context::PolkaVMDivisionFunction.declare(context)?;
|
revive_llvm_context::PolkaVMDivisionFunction.declare(context)?;
|
||||||
revive_llvm_context::PolkaVMSignedDivisionFunction.declare(context)?;
|
revive_llvm_context::PolkaVMSignedDivisionFunction.declare(context)?;
|
||||||
revive_llvm_context::PolkaVMRemainderFunction.declare(context)?;
|
revive_llvm_context::PolkaVMRemainderFunction.declare(context)?;
|
||||||
@@ -258,6 +259,7 @@ where
|
|||||||
revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?;
|
revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?;
|
||||||
revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?;
|
revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?;
|
||||||
|
|
||||||
|
revive_llvm_context::PolkaVMAdditionFunction.into_llvm(context)?;
|
||||||
revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?;
|
revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?;
|
||||||
revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?;
|
revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?;
|
||||||
revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?;
|
revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?;
|
||||||
@@ -279,17 +281,17 @@ where
|
|||||||
context.push_debug_scope(object_scope.as_debug_info_scope());
|
context.push_debug_scope(object_scope.as_debug_info_scope());
|
||||||
}
|
}
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
if self.identifier.ends_with("_deployed") {
|
if self.identifier.ends_with("_deployed") {
|
||||||
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(self.code).into_llvm(context)?;
|
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(self.code).into_llvm(context)?;
|
||||||
} else {
|
} else {
|
||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
||||||
}
|
}
|
||||||
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
if let Some(object) = self.inner_object {
|
if let Some(object) = self.inner_object {
|
||||||
object.into_llvm(context)?;
|
object.into_llvm(context)?;
|
||||||
}
|
}
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
context.pop_debug_scope();
|
context.pop_debug_scope();
|
||||||
|
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ where
|
|||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
let scrutinee = self.expression.into_llvm(&[], context)?;
|
||||||
let scrutinee = self.expression.into_llvm(context)?;
|
|
||||||
|
|
||||||
if self.cases.is_empty() {
|
if self.cases.is_empty() {
|
||||||
if let Some(block) = self.default {
|
if let Some(block) = self.default {
|
||||||
@@ -138,13 +137,12 @@ where
|
|||||||
|
|
||||||
let mut branches = Vec::with_capacity(self.cases.len());
|
let mut branches = Vec::with_capacity(self.cases.len());
|
||||||
for (index, case) in self.cases.into_iter().enumerate() {
|
for (index, case) in self.cases.into_iter().enumerate() {
|
||||||
let constant = case.literal.into_llvm(context)?.access(context)?;
|
let constant = case.literal.into_llvm(None, context)?.access(context)?;
|
||||||
|
|
||||||
let expression_block = context
|
let expression_block = context
|
||||||
.append_basic_block(format!("switch_case_branch_{}_block", index + 1).as_str());
|
.append_basic_block(format!("switch_case_branch_{}_block", index + 1).as_str());
|
||||||
context.set_basic_block(expression_block);
|
context.set_basic_block(expression_block);
|
||||||
case.block.into_llvm(context)?;
|
case.block.into_llvm(context)?;
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
context.build_unconditional_branch(join_block);
|
context.build_unconditional_branch(join_block);
|
||||||
|
|
||||||
branches.push((constant.into_int_value(), expression_block));
|
branches.push((constant.into_int_value(), expression_block));
|
||||||
@@ -161,7 +159,6 @@ where
|
|||||||
None => join_block,
|
None => join_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
context.set_basic_block(current_block);
|
context.set_basic_block(current_block);
|
||||||
context.builder().build_switch(
|
context.builder().build_switch(
|
||||||
scrutinee
|
scrutinee
|
||||||
@@ -172,7 +169,6 @@ where
|
|||||||
branches.as_slice(),
|
branches.as_slice(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
|
||||||
context.set_basic_block(join_block);
|
context.set_basic_block(join_block);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -99,9 +99,28 @@ where
|
|||||||
mut self,
|
mut self,
|
||||||
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
let bindings: Vec<(String, revive_llvm_context::PolkaVMPointer<'ctx>)> = self
|
||||||
|
.bindings
|
||||||
|
.into_iter()
|
||||||
|
.map(|binding| {
|
||||||
|
(
|
||||||
|
binding.inner.clone(),
|
||||||
|
context
|
||||||
|
.current_function()
|
||||||
|
.borrow_mut()
|
||||||
|
.stack_variable_pointer(binding.inner, context),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Some(expression) = self.expression {
|
||||||
|
expression.into_llvm(&bindings, context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if self.bindings.len() == 1 {
|
if self.bindings.len() == 1 {
|
||||||
let identifier = self.bindings.remove(0);
|
let identifier = self.bindings.remove(0);
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
let identifier_type = identifier.r#type.clone().unwrap_or_default();
|
let identifier_type = identifier.r#type.clone().unwrap_or_default();
|
||||||
let r#type = identifier_type.into_llvm(context);
|
let r#type = identifier_type.into_llvm(context);
|
||||||
let pointer = context.build_alloca(r#type, identifier.inner.as_str());
|
let pointer = context.build_alloca(r#type, identifier.inner.as_str());
|
||||||
@@ -133,7 +152,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (index, binding) in self.bindings.iter().enumerate() {
|
for (index, binding) in self.bindings.iter().enumerate() {
|
||||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
context.set_debug_location(self.location.line, 0, None)?;
|
||||||
|
|
||||||
let yul_type = binding
|
let yul_type = binding
|
||||||
.r#type
|
.r#type
|
||||||
@@ -213,6 +232,7 @@ where
|
|||||||
})?;
|
})?;
|
||||||
context.build_store(pointer, value)?;
|
context.build_store(pointer, value)?;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,10 +70,11 @@ impl Type {
|
|||||||
D: revive_llvm_context::PolkaVMDependency + Clone,
|
D: revive_llvm_context::PolkaVMDependency + Clone,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN),
|
//Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN),
|
||||||
Self::Int(bitlength) => context.integer_type(bitlength),
|
//Self::Int(bitlength) => context.integer_type(bitlength),
|
||||||
Self::UInt(bitlength) => context.integer_type(bitlength),
|
Self::UInt(bitlength) => context.integer_type(bitlength),
|
||||||
Self::Custom(_) => context.word_type(),
|
//Self::Custom(_) => context.word_type(),
|
||||||
|
_ => panic!("oh no"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+4
-16
@@ -743,30 +743,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/plugin-kit": {
|
"node_modules/@eslint/plugin-kit": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
|
||||||
"integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==",
|
"integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/core": "^0.15.1",
|
"@eslint/core": "^0.14.0",
|
||||||
"levn": "^0.4.1"
|
"levn": "^0.4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
|
|
||||||
"version": "0.15.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
|
|
||||||
"integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/json-schema": "^7.0.15"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@eth-optimism/contracts": {
|
"node_modules/@eth-optimism/contracts": {
|
||||||
"version": "0.5.40",
|
"version": "0.5.40",
|
||||||
"resolved": "https://registry.npmjs.org/@eth-optimism/contracts/-/contracts-0.5.40.tgz",
|
"resolved": "https://registry.npmjs.org/@eth-optimism/contracts/-/contracts-0.5.40.tgz",
|
||||||
|
|||||||
Reference in New Issue
Block a user