Arithmetic
ADD
Original EVM instruction.
LLVM IR
%addition_result = add i256 %value1, %value2
LLVM IR instruction documentation
EraVM Assembly
add r1, r2, r1
For more detail, see the EraVM specification reference
MUL
Original EVM instruction.
Differences from EVM
- The carry is written to the 2nd output register
LLVM IR
%multiplication_result = mul i256 %value1, %value2
EraVM can output the carry of the multiplication operation. In this case, the result is a tuple of two values: the multiplication result and the carry. The carry is written to the 2nd output register. The snippet below returns the carry value.
%value1_extended = zext i256 %value1 to i512
%value2_extended = zext i256 %value2 to i512
%result_extended = mul nuw i512 %value1_extended, %value2_extended
%result_shifted = lshr i512 %result_extended, 256
%result = trunc i512 %result_shifted to i256
LLVM IR instruction documentation
EraVM Assembly
mul r1, r2, r1, r2
For more detail, see the EraVM specification reference
SUB
Original EVM instruction.
LLVM IR
%subtraction_result = sub i256 %value1, %value2
LLVM IR instruction documentation
EraVM Assembly
sub r1, r2, r1
For more detail, see the EraVM specification reference
DIV
Original EVM instruction.
Differences from EVM
- The remainder is written to the 2nd output register
LLVM IR
define i256 @__div(i256 %arg1, i256 %arg2) #0 {
entry:
%is_divider_zero = icmp eq i256 %arg2, 0
br i1 %is_divider_zero, label %return, label %division
division:
%div_res = udiv i256 %arg1, %arg2
br label %return
return:
%res = phi i256 [ 0, %entry ], [ %div_res, %division ]
ret i256 %res
}
LLVM IR instruction documentation
For more detail, see the EraVM specification reference
SDIV
Original EVM instruction.
LLVM IR
define i256 @__sdiv(i256 %arg1, i256 %arg2) #0 {
entry:
%is_divider_zero = icmp eq i256 %arg2, 0
br i1 %is_divider_zero, label %return, label %division_overflow
division_overflow:
%is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968
%is_minus_one = icmp eq i256 %arg2, -1
%is_overflow = and i1 %is_divided_int_min, %is_minus_one
br i1 %is_overflow, label %return, label %division
division:
%div_res = sdiv i256 %arg1, %arg2
br label %return
return:
%res = phi i256 [ 0, %entry ], [ %arg1, %division_overflow ], [ %div_res, %division ]
ret i256 %res
}
LLVM IR instruction documentation
EraVM does not have a similar instruction.
MOD
Original EVM instruction.
Differences from EVM
- The remainder is written to the 2nd output register
LLVM IR
define i256 @__mod(i256 %arg1, i256 %arg2) #0 {
entry:
%is_divider_zero = icmp eq i256 %arg2, 0
br i1 %is_divider_zero, label %return, label %remainder
remainder:
%rem_res = urem i256 %arg1, %arg2
br label %return
return:
%res = phi i256 [ 0, %entry ], [ %rem_res, %remainder ]
ret i256 %res
}
LLVM IR instruction documentation
For more detail, see the EraVM specification reference
SMOD
Original EVM instruction.
LLVM IR
define i256 @__smod(i256 %arg1, i256 %arg2) #0 {
entry:
%is_divider_zero = icmp eq i256 %arg2, 0
br i1 %is_divider_zero, label %return, label %division_overflow
division_overflow:
%is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968
%is_minus_one = icmp eq i256 %arg2, -1
%is_overflow = and i1 %is_divided_int_min, %is_minus_one
br i1 %is_overflow, label %return, label %remainder
remainder:
%rem_res = srem i256 %arg1, %arg2
br label %return
return:
%res = phi i256 [ 0, %entry ], [ 0, %division_overflow ], [ %rem_res, %remainder ]
ret i256 %res
}
LLVM IR instruction documentation
EraVM does not have a similar instruction.
ADDMOD
Original EVM instruction.
LLVM IR
define i256 @__addmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 {
entry:
%is_zero = icmp eq i256 %modulo, 0
br i1 %is_zero, label %return, label %addmod
addmod:
%arg1m = urem i256 %arg1, %modulo
%arg2m = urem i256 %arg2, %modulo
%res = call {i256, i1} @llvm.uadd.with.overflow.i256(i256 %arg1m, i256 %arg2m)
%sum = extractvalue {i256, i1} %res, 0
%obit = extractvalue {i256, i1} %res, 1
%sum.mod = urem i256 %sum, %modulo
br i1 %obit, label %overflow, label %return
overflow:
%mod.inv = xor i256 %modulo, -1
%sum1 = add i256 %sum, %mod.inv
%sum.ovf = add i256 %sum1, 1
br label %return
return:
%value = phi i256 [0, %entry], [%sum.mod, %addmod], [%sum.ovf, %overflow]
ret i256 %value
}
EraVM does not have a similar instruction.
MULMOD
Original EVM instruction.
LLVM IR
define i256 @__mulmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 {
entry:
%cccond = icmp eq i256 %modulo, 0
br i1 %cccond, label %ccret, label %entrycont
ccret:
ret i256 0
entrycont:
%arg1m = urem i256 %arg1, %modulo
%arg2m = urem i256 %arg2, %modulo
%less_then_2_128 = icmp ult i256 %modulo, 340282366920938463463374607431768211456
br i1 %less_then_2_128, label %fast, label %slow
fast:
%prod = mul i256 %arg1m, %arg2m
%prodm = urem i256 %prod, %modulo
ret i256 %prodm
slow:
%arg1e = zext i256 %arg1m to i512
%arg2e = zext i256 %arg2m to i512
%prode = mul i512 %arg1e, %arg2e
%prodl = trunc i512 %prode to i256
%prodeh = lshr i512 %prode, 256
%prodh = trunc i512 %prodeh to i256
%res = call i256 @__ulongrem(i256 %prodl, i256 %prodh, i256 %modulo)
ret i256 %res
}
EraVM does not have a similar instruction.
EXP
Original EVM instruction.
LLVM IR
define i256 @__exp(i256 %value, i256 %exp) "noinline-oz" #0 {
entry:
%exp_is_non_zero = icmp eq i256 %exp, 0
br i1 %exp_is_non_zero, label %return, label %exponent_loop_body
return:
%exp_res = phi i256 [ 1, %entry ], [ %exp_res.1, %exponent_loop_body ]
ret i256 %exp_res
exponent_loop_body:
%exp_res.2 = phi i256 [ %exp_res.1, %exponent_loop_body ], [ 1, %entry ]
%exp_val = phi i256 [ %exp_val_halved, %exponent_loop_body ], [ %exp, %entry ]
%val_squared.1 = phi i256 [ %val_squared, %exponent_loop_body ], [ %value, %entry ]
%odd_test = and i256 %exp_val, 1
%is_exp_odd = icmp eq i256 %odd_test, 0
%exp_res.1.interm = select i1 %is_exp_odd, i256 1, i256 %val_squared.1
%exp_res.1 = mul i256 %exp_res.1.interm, %exp_res.2
%val_squared = mul i256 %val_squared.1, %val_squared.1
%exp_val_halved = lshr i256 %exp_val, 1
%exp_val_is_less_2 = icmp ult i256 %exp_val, 2
br i1 %exp_val_is_less_2, label %return, label %exponent_loop_body
}
EraVM does not have a similar instruction.
SIGNEXTEND
Original EVM instruction.
LLVM IR
define i256 @__signextend(i256 %numbyte, i256 %value) #0 {
entry:
%is_overflow = icmp uge i256 %numbyte, 31
br i1 %is_overflow, label %return, label %signextend
signextend:
%numbit_byte = mul nuw nsw i256 %numbyte, 8
%numbit = add nsw nuw i256 %numbit_byte, 7
%numbit_inv = sub i256 256, %numbit
%signmask = shl i256 1, %numbit
%valmask = lshr i256 -1, %numbit_inv
%ext1 = shl i256 -1, %numbit
%signv = and i256 %signmask, %value
%sign = icmp ne i256 %signv, 0
%valclean = and i256 %value, %valmask
%sext = select i1 %sign, i256 %ext1, i256 0
%result = or i256 %sext, %valclean
br label %return
return:
%signext_res = phi i256 [%value, %entry], [%result, %signextend]
ret i256 %signext_res
}
EraVM does not have a similar instruction.