Skip to content

Commit

Permalink
Merge main into v2.6.0. (#5195)
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbens-starkware authored Mar 4, 2024
2 parents 7cb38ab + 7e94dd4 commit 5aa90bc
Show file tree
Hide file tree
Showing 114 changed files with 72,032 additions and 62,567 deletions.
84 changes: 84 additions & 0 deletions corelib/src/integer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ impl U128PartialOrd of PartialOrd<u128> {
}

pub extern type Bitwise;
/// Returns the bitwise operations (AND, XOR, OR) between `lhs` and `rhs`.
extern fn bitwise(lhs: u128, rhs: u128) -> (u128, u128, u128) implicits(Bitwise) nopanic;
impl U128BitAnd of BitAnd<u128> {
#[inline(always)]
Expand Down Expand Up @@ -2960,3 +2961,86 @@ impl I128OverflowingSub of core::num::traits::OverflowingSub<i128> {
}
}
}

// OverflowingMul implementations
impl U8OverflowingMul of core::num::traits::OverflowingMul<u8> {
fn overflowing_mul(self: u8, v: u8) -> (u8, bool) {
let wide_result = u8_wide_mul(self, v);
let MASK: u16 = BoundedInt::<u8>::max().into();
let (v_low, _, v_with_low_masked) = u16_bitwise(wide_result, MASK);
(v_low.try_into().unwrap(), v_with_low_masked != MASK)
}
}

impl U16OverflowingMul of core::num::traits::OverflowingMul<u16> {
fn overflowing_mul(self: u16, v: u16) -> (u16, bool) {
let wide_result = u16_wide_mul(self, v);
let MASK: u32 = BoundedInt::<u16>::max().into();
let (v_low, _, v_with_low_masked) = u32_bitwise(wide_result, MASK);
(v_low.try_into().unwrap(), v_with_low_masked != MASK)
}
}

impl U32OverflowingMul of core::num::traits::OverflowingMul<u32> {
fn overflowing_mul(self: u32, v: u32) -> (u32, bool) {
let wide_result = u32_wide_mul(self, v);
let MASK: u64 = BoundedInt::<u32>::max().into();
let (v_low, _, v_with_low_masked) = u64_bitwise(wide_result, MASK);
(v_low.try_into().unwrap(), v_with_low_masked != MASK)
}
}

impl U64OverflowingMul of core::num::traits::OverflowingMul<u64> {
fn overflowing_mul(self: u64, v: u64) -> (u64, bool) {
let wide_result = u64_wide_mul(self, v);
let MASK: u128 = BoundedInt::<u64>::max().into();
let (v_low, _, v_with_low_masked) = bitwise(wide_result, MASK);
(v_low.try_into().unwrap(), v_with_low_masked != MASK)
}
}

impl U128OverflowingMul of core::num::traits::OverflowingMul<u128> {
fn overflowing_mul(self: u128, v: u128) -> (u128, bool) {
u128_overflowing_mul(self, v)
}
}

impl U256OverflowingMul of core::num::traits::OverflowingMul<u256> {
fn overflowing_mul(self: u256, v: u256) -> (u256, bool) {
u256_overflow_mul(self, v)
}
}

/// WrappingAdd implementations
impl U8WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u8>;
impl U16WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u16>;
impl U32WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u32>;
impl U64WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u64>;
impl U128WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u128>;
impl U256WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<u256>;
impl I8WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<i8>;
impl I16WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<i16>;
impl I32WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<i32>;
impl I64WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<i64>;
impl I128WrappingAdd = core::num::traits::ops::wrapping::overflow_based::TWrappingAdd<i128>;

/// WrappingSub implementations
impl U8WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u8>;
impl U16WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u16>;
impl U32WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u32>;
impl U64WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u64>;
impl U128WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u128>;
impl U256WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<u256>;
impl I8WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<i8>;
impl I16WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<i16>;
impl I32WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<i32>;
impl I64WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<i64>;
impl I128WrappingSub = core::num::traits::ops::wrapping::overflow_based::TWrappingSub<i128>;

/// WrappingMul implementations
impl U8WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u8>;
impl U16WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u16>;
impl U32WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u32>;
impl U64WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u64>;
impl U128WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u128>;
impl U256WrappingMul = core::num::traits::ops::wrapping::overflow_based::TWrappingMul<u256>;
3 changes: 2 additions & 1 deletion corelib/src/num/traits.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ pub mod bit_size;
pub use bit_size::BitSize;

pub mod ops;
pub use ops::{OverflowingAdd, OverflowingSub};
pub use ops::overflowing::{OverflowingAdd, OverflowingSub, OverflowingMul};
pub use ops::wrapping::{WrappingAdd, WrappingSub, WrappingMul};
2 changes: 1 addition & 1 deletion corelib/src/num/traits/ops.cairo
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod overflowing;
pub use overflowing::{OverflowingAdd, OverflowingSub};
pub mod wrapping;
8 changes: 8 additions & 0 deletions corelib/src/num/traits/ops/overflowing.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,11 @@ pub trait OverflowingSub<T> {
/// If an overflow would have occurred then the wrapped value is returned.
fn overflowing_sub(self: T, v: T) -> (T, bool);
}

/// Performs multiplication with a flag for overflow.
pub trait OverflowingMul<T> {
/// Returns a tuple of the product along with a boolean indicating whether an arithmetic
/// overflow would occur.
/// If an overflow would have occurred then the wrapped value is returned.
fn overflowing_mul(self: T, v: T) -> (T, bool);
}
49 changes: 49 additions & 0 deletions corelib/src/num/traits/ops/wrapping.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/// Performs addition that wraps around on overflow.
pub trait WrappingAdd<T> {
/// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of the
/// type.
fn wrapping_add(self: T, v: T) -> T;
}

/// Performs subtraction that wraps around on overflow.
pub trait WrappingSub<T> {
/// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary of
/// the type.
fn wrapping_sub(self: T, v: T) -> T;
}

/// Performs multiplication that wraps around on overflow.
pub trait WrappingMul<T> {
/// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary
/// of the type.
fn wrapping_mul(self: T, v: T) -> T;
}

pub(crate) mod overflow_based {
pub(crate) impl TWrappingAdd<
T, +core::num::traits::OverflowingAdd<T>
> of core::num::traits::WrappingAdd<T> {
fn wrapping_add(self: T, v: T) -> T {
let (result, _) = self.overflowing_add(v);
result
}
}

pub(crate) impl TWrappingSub<
T, +core::num::traits::OverflowingSub<T>
> of core::num::traits::WrappingSub<T> {
fn wrapping_sub(self: T, v: T) -> T {
let (result, _) = self.overflowing_sub(v);
result
}
}

pub(crate) impl TWrappingMul<
T, +core::num::traits::OverflowingMul<T>
> of core::num::traits::WrappingMul<T> {
fn wrapping_mul(self: T, v: T) -> T {
let (result, _) = self.overflowing_mul(v);
result
}
}
}
128 changes: 127 additions & 1 deletion corelib/src/test/num_test.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::num::traits::BitSize;
use core::num::traits::{OverflowingAdd, OverflowingSub};
use core::num::traits::{
OverflowingAdd, OverflowingSub, OverflowingMul, WrappingAdd, WrappingSub, WrappingMul
};
use core::integer::BoundedInt;


Expand All @@ -19,6 +21,8 @@ fn test_bit_size() {
assert!(BitSize::<bytes31>::bits() == 248);
}

// Overflowing tests

#[test]
fn tests_overflowing_add_unsigned_integers() {
assert_eq!(1_u8.overflowing_add(2), (3, false));
Expand Down Expand Up @@ -109,3 +113,125 @@ fn test_overflowing_sub_negative_signed_integers() {
assert!((-3_i128).overflowing_sub(-2) == (-1, false));
assert!(BoundedInt::<i128>::max().overflowing_sub(-1) == (BoundedInt::<i128>::min(), true));
}

#[test]
fn test_overflowing_mul_unsigned_integers() {
assert_eq!(2_u8.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u8>::max().overflowing_mul(2), (BoundedInt::<u8>::max() - 1, true));
assert_eq!(2_u16.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u16>::max().overflowing_mul(2), (BoundedInt::<u16>::max() - 1, true));
assert_eq!(2_u32.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u32>::max().overflowing_mul(2), (BoundedInt::<u32>::max() - 1, true));
assert_eq!(2_u64.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u64>::max().overflowing_mul(2), (BoundedInt::<u64>::max() - 1, true));
assert_eq!(2_u128.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u128>::max().overflowing_mul(2), (BoundedInt::<u128>::max() - 1, true));
assert_eq!(2_u256.overflowing_mul(3), (6, false));
assert_eq!(BoundedInt::<u256>::max().overflowing_mul(2), (BoundedInt::<u256>::max() - 1, true));
}

// Wrapping tests

#[test]
fn tests_wrapping_add_unsigned_integers() {
assert_eq!(1_u8.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u8>::max().wrapping_add(1), 0);
assert_eq!(1_u16.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u16>::max().wrapping_add(1), 0);
assert_eq!(1_u32.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u32>::max().wrapping_add(1), 0);
assert_eq!(1_u64.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u64>::max().wrapping_add(1), 0);
assert_eq!(1_u128.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u128>::max().wrapping_add(1), 0);
assert_eq!(1_u256.wrapping_add(2), 3);
assert_eq!(BoundedInt::<u256>::max().wrapping_add(1), 0);
}

#[test]
fn test_wrapping_add_positive_signed_integers() {
assert!(1_i8.wrapping_add(2) == 3);
assert!(BoundedInt::<i8>::max().wrapping_add(1) == -0x80);
assert!(1_i16.wrapping_add(2) == 3);
assert!(BoundedInt::<i16>::max().wrapping_add(1) == -0x8000);
assert!(1_i32.wrapping_add(2) == 3);
assert!(BoundedInt::<i32>::max().wrapping_add(1) == -0x80000000);
assert!(1_i64.wrapping_add(2) == 3);
assert!(BoundedInt::<i64>::max().wrapping_add(1) == -0x8000000000000000);
assert!(1_i128.wrapping_add(2) == 3);
assert!(BoundedInt::<i128>::max().wrapping_add(1) == -0x80000000000000000000000000000000);
}

#[test]
fn test_wrapping_add_negative_signed_integers() {
assert!((-1_i8).wrapping_add(-2) == -3);
assert!(BoundedInt::<i8>::min().wrapping_add(-1) == 0x7f);
assert!((-1_i16).wrapping_add(-2) == -3);
assert!(BoundedInt::<i16>::min().wrapping_add(-1) == 0x7fff);
assert!((-1_i32).wrapping_add(-2) == -3);
assert!(BoundedInt::<i32>::min().wrapping_add(-1) == 0x7fffffff);
assert!((-1_i64).wrapping_add(-2) == -3);
assert!(BoundedInt::<i64>::min().wrapping_add(-1) == 0x7fffffffffffffff);
assert!((-1_i128).wrapping_add(-2) == -3);
assert!(BoundedInt::<i128>::min().wrapping_add(-1) == 0x7fffffffffffffffffffffffffffffff);
}

#[test]
fn test_wrapping_sub_unsigned_integers() {
assert_eq!(3_u8.wrapping_sub(2), 1);
assert_eq!(0_u8.wrapping_sub(1), BoundedInt::<u8>::max());
assert_eq!(3_u16.wrapping_sub(2), 1);
assert_eq!(0_u16.wrapping_sub(1), BoundedInt::<u16>::max());
assert_eq!(3_u32.wrapping_sub(2), 1);
assert_eq!(0_u32.wrapping_sub(1), BoundedInt::<u32>::max());
assert_eq!(3_u64.wrapping_sub(2), 1);
assert_eq!(0_u64.wrapping_sub(1), BoundedInt::<u64>::max());
assert_eq!(3_u128.wrapping_sub(2), 1);
assert_eq!(0_u128.wrapping_sub(1), BoundedInt::<u128>::max());
assert_eq!(3_u256.wrapping_sub(2), 1);
assert_eq!(0_u256.wrapping_sub(1), BoundedInt::<u256>::max());
}

#[test]
fn test_wrapping_sub_positive_signed_integers() {
assert!(3_i8.wrapping_sub(2) == 1);
assert!(BoundedInt::<i8>::min().wrapping_sub(1) == BoundedInt::<i8>::max());
assert!(3_i16.wrapping_sub(2) == 1);
assert!(BoundedInt::<i16>::min().wrapping_sub(1) == BoundedInt::<i16>::max());
assert!(3_i32.wrapping_sub(2) == 1);
assert!(BoundedInt::<i32>::min().wrapping_sub(1) == BoundedInt::<i32>::max());
assert!(3_i64.wrapping_sub(2) == 1);
assert!(BoundedInt::<i64>::min().wrapping_sub(1) == BoundedInt::<i64>::max());
assert!(3_i128.wrapping_sub(2) == 1);
assert!(BoundedInt::<i128>::min().wrapping_sub(1) == BoundedInt::<i128>::max());
}

#[test]
fn test_wrapping_sub_negative_signed_integers() {
assert!((-3_i8).wrapping_sub(-2) == -1);
assert!(BoundedInt::<i8>::max().wrapping_sub(-1) == BoundedInt::<i8>::min());
assert!((-3_i16).wrapping_sub(-2) == -1);
assert!(BoundedInt::<i16>::max().wrapping_sub(-1) == BoundedInt::<i16>::min());
assert!((-3_i32).wrapping_sub(-2) == -1);
assert!(BoundedInt::<i32>::max().wrapping_sub(-1) == BoundedInt::<i32>::min());
assert!((-3_i64).wrapping_sub(-2) == -1);
assert!(BoundedInt::<i64>::max().wrapping_sub(-1) == BoundedInt::<i64>::min());
assert!((-3_i128).wrapping_sub(-2) == -1);
assert!(BoundedInt::<i128>::max().wrapping_sub(-1) == BoundedInt::<i128>::min());
}

#[test]
fn test_wrapping_mul_unsigned_integers() {
assert_eq!(2_u8.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u8>::max().wrapping_mul(2), BoundedInt::<u8>::max() - 1);
assert_eq!(2_u16.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u16>::max().wrapping_mul(2), BoundedInt::<u16>::max() - 1);
assert_eq!(2_u32.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u32>::max().wrapping_mul(2), BoundedInt::<u32>::max() - 1);
assert_eq!(2_u64.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u64>::max().wrapping_mul(2), BoundedInt::<u64>::max() - 1);
assert_eq!(2_u128.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u128>::max().wrapping_mul(2), BoundedInt::<u128>::max() - 1);
assert_eq!(2_u256.wrapping_mul(3), 6);
assert_eq!(BoundedInt::<u256>::max().wrapping_mul(2), BoundedInt::<u256>::max() - 1);
}
7 changes: 6 additions & 1 deletion crates/bin/cairo-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ fn main() -> anyhow::Result<()> {
// Check if args.path is a file or a directory.
check_compiler_path(args.single_file, &args.path)?;

let db = &mut RootDatabase::builder().detect_corelib().build()?;
let mut db_builder = RootDatabase::builder();
db_builder.detect_corelib();
if args.available_gas.is_none() {
db_builder.skip_auto_withdraw_gas();
}
let db = &mut db_builder.build()?;

let main_crate_ids = setup_project(db, Path::new(&args.path))?;

Expand Down
2 changes: 2 additions & 0 deletions crates/bin/get-lowering/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use cairo_lang_lowering::db::LoweringGroup;
use cairo_lang_lowering::destructs::add_destructs;
use cairo_lang_lowering::fmt::LoweredFormatter;
use cairo_lang_lowering::ids::ConcreteFunctionWithBodyId;
use cairo_lang_lowering::optimizations::scrub_units::scrub_units;
use cairo_lang_lowering::panic::lower_panics;
use cairo_lang_lowering::FlatLowered;
use cairo_lang_semantic::items::functions::{
Expand Down Expand Up @@ -107,6 +108,7 @@ impl fmt::Debug for PhasesFormatter<'_> {
*lowered = lower_panics(db, function_id, lowered).unwrap();
});
apply_stage("after_add_destructs", &|lowered| add_destructs(db, function_id, lowered));
apply_stage("scrub_units", &|lowered| scrub_units(db, lowered));

for phase in db.lookup_intern_strategy(strategy).0 {
let name = format!("{phase:?}").to_case(convert_case::Case::Snake);
Expand Down
15 changes: 15 additions & 0 deletions crates/cairo-lang-compiler/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use cairo_lang_filesystem::db::{
CORELIB_CRATE_NAME,
};
use cairo_lang_filesystem::detect::detect_corelib;
use cairo_lang_filesystem::flag::Flag;
use cairo_lang_filesystem::ids::FlagId;
use cairo_lang_lowering::db::{init_lowering_group, LoweringDatabase, LoweringGroup};
use cairo_lang_parser::db::ParserDatabase;
use cairo_lang_project::ProjectConfig;
Expand Down Expand Up @@ -79,6 +81,7 @@ impl Default for RootDatabase {
pub struct RootDatabaseBuilder {
plugin_suite: PluginSuite,
detect_corelib: bool,
auto_withdraw_gas: bool,
project_config: Option<Box<ProjectConfig>>,
cfg_set: Option<CfgSet>,
}
Expand All @@ -88,6 +91,7 @@ impl RootDatabaseBuilder {
Self {
plugin_suite: get_default_plugin_suite(),
detect_corelib: false,
auto_withdraw_gas: true,
project_config: None,
cfg_set: None,
}
Expand Down Expand Up @@ -118,6 +122,11 @@ impl RootDatabaseBuilder {
self
}

pub fn skip_auto_withdraw_gas(&mut self) -> &mut Self {
self.auto_withdraw_gas = false;
self
}

pub fn build(&mut self) -> Result<RootDatabase> {
// NOTE: Order of operations matters here!
// Errors if something is not OK are very subtle, mostly this results in missing
Expand All @@ -139,6 +148,12 @@ impl RootDatabaseBuilder {
init_dev_corelib(&mut db, path)
}

let add_withdraw_gas_flag_id = FlagId::new(db.upcast(), "add_withdraw_gas");
db.set_flag(
add_withdraw_gas_flag_id,
Some(Arc::new(Flag::AddWithdrawGas(self.auto_withdraw_gas))),
);

if let Some(config) = &self.project_config {
update_crate_roots_from_project_config(&mut db, config.as_ref());
if let Some(corelib) = &config.corelib {
Expand Down
Loading

0 comments on commit 5aa90bc

Please sign in to comment.