@@ -2,6 +2,7 @@ use crate::brillig::brillig_ir::artifact::Label;
22use crate :: brillig:: brillig_ir:: brillig_variable:: {
33 type_to_heap_value_type, BrilligArray , BrilligVariable , SingleAddrVariable ,
44} ;
5+
56use crate :: brillig:: brillig_ir:: registers:: Stack ;
67use crate :: brillig:: brillig_ir:: {
78 BrilligBinaryOp , BrilligContext , ReservedRegisters , BRILLIG_MEMORY_ADDRESSING_BIT_SIZE ,
@@ -1202,7 +1203,7 @@ impl<'block> BrilligBlock<'block> {
12021203 let brillig_binary_op = match binary. operator {
12031204 BinaryOp :: Div => {
12041205 if is_signed {
1205- self . convert_signed_division ( left, right, result_variable) ;
1206+ self . brillig_context . convert_signed_division ( left, right, result_variable) ;
12061207 return ;
12071208 } else if is_field {
12081209 BrilligBinaryOp :: FieldDiv
@@ -1234,7 +1235,14 @@ impl<'block> BrilligBlock<'block> {
12341235 BinaryOp :: Or => BrilligBinaryOp :: Or ,
12351236 BinaryOp :: Xor => BrilligBinaryOp :: Xor ,
12361237 BinaryOp :: Shl => BrilligBinaryOp :: Shl ,
1237- BinaryOp :: Shr => BrilligBinaryOp :: Shr ,
1238+ BinaryOp :: Shr => {
1239+ if is_signed {
1240+ self . convert_signed_shr ( left, right, result_variable) ;
1241+ return ;
1242+ } else {
1243+ BrilligBinaryOp :: Shr
1244+ }
1245+ }
12381246 } ;
12391247
12401248 self . brillig_context . binary_instruction ( left, right, result_variable, brillig_binary_op) ;
@@ -1250,98 +1258,6 @@ impl<'block> BrilligBlock<'block> {
12501258 ) ;
12511259 }
12521260
1253- /// Splits a two's complement signed integer in the sign bit and the absolute value.
1254- /// For example, -6 i8 (11111010) is split to 00000110 (6, absolute value) and 1 (is_negative).
1255- fn absolute_value (
1256- & mut self ,
1257- num : SingleAddrVariable ,
1258- absolute_value : SingleAddrVariable ,
1259- result_is_negative : SingleAddrVariable ,
1260- ) {
1261- let max_positive = self
1262- . brillig_context
1263- . make_constant_instruction ( ( ( 1_u128 << ( num. bit_size - 1 ) ) - 1 ) . into ( ) , num. bit_size ) ;
1264-
1265- // Compute if num is negative
1266- self . brillig_context . binary_instruction (
1267- max_positive,
1268- num,
1269- result_is_negative,
1270- BrilligBinaryOp :: LessThan ,
1271- ) ;
1272-
1273- // Two's complement of num
1274- let zero = self . brillig_context . make_constant_instruction ( 0_usize . into ( ) , num. bit_size ) ;
1275- let twos_complement =
1276- SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , num. bit_size ) ;
1277- self . brillig_context . binary_instruction ( zero, num, twos_complement, BrilligBinaryOp :: Sub ) ;
1278-
1279- // absolute_value = result_is_negative ? twos_complement : num
1280- self . brillig_context . codegen_branch ( result_is_negative. address , |ctx, is_negative| {
1281- if is_negative {
1282- ctx. mov_instruction ( absolute_value. address , twos_complement. address ) ;
1283- } else {
1284- ctx. mov_instruction ( absolute_value. address , num. address ) ;
1285- }
1286- } ) ;
1287-
1288- self . brillig_context . deallocate_single_addr ( zero) ;
1289- self . brillig_context . deallocate_single_addr ( max_positive) ;
1290- self . brillig_context . deallocate_single_addr ( twos_complement) ;
1291- }
1292-
1293- fn convert_signed_division (
1294- & mut self ,
1295- left : SingleAddrVariable ,
1296- right : SingleAddrVariable ,
1297- result : SingleAddrVariable ,
1298- ) {
1299- let left_is_negative = SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , 1 ) ;
1300- let left_abs_value =
1301- SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , left. bit_size ) ;
1302-
1303- let right_is_negative =
1304- SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , 1 ) ;
1305- let right_abs_value =
1306- SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , right. bit_size ) ;
1307-
1308- let result_is_negative =
1309- SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , 1 ) ;
1310-
1311- // Compute both absolute values
1312- self . absolute_value ( left, left_abs_value, left_is_negative) ;
1313- self . absolute_value ( right, right_abs_value, right_is_negative) ;
1314-
1315- // Perform the division on the absolute values
1316- self . brillig_context . binary_instruction (
1317- left_abs_value,
1318- right_abs_value,
1319- result,
1320- BrilligBinaryOp :: UnsignedDiv ,
1321- ) ;
1322-
1323- // Compute result sign
1324- self . brillig_context . binary_instruction (
1325- left_is_negative,
1326- right_is_negative,
1327- result_is_negative,
1328- BrilligBinaryOp :: Xor ,
1329- ) ;
1330-
1331- // If result has to be negative, perform two's complement
1332- self . brillig_context . codegen_if ( result_is_negative. address , |ctx| {
1333- let zero = ctx. make_constant_instruction ( 0_usize . into ( ) , result. bit_size ) ;
1334- ctx. binary_instruction ( zero, result, result, BrilligBinaryOp :: Sub ) ;
1335- ctx. deallocate_single_addr ( zero) ;
1336- } ) ;
1337-
1338- self . brillig_context . deallocate_single_addr ( left_is_negative) ;
1339- self . brillig_context . deallocate_single_addr ( left_abs_value) ;
1340- self . brillig_context . deallocate_single_addr ( right_is_negative) ;
1341- self . brillig_context . deallocate_single_addr ( right_abs_value) ;
1342- self . brillig_context . deallocate_single_addr ( result_is_negative) ;
1343- }
1344-
13451261 fn convert_signed_modulo (
13461262 & mut self ,
13471263 left : SingleAddrVariable ,
@@ -1354,7 +1270,7 @@ impl<'block> BrilligBlock<'block> {
13541270 SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , left. bit_size ) ;
13551271
13561272 // i = left / right
1357- self . convert_signed_division ( left, right, scratch_var_i) ;
1273+ self . brillig_context . convert_signed_division ( left, right, scratch_var_i) ;
13581274
13591275 // j = i * right
13601276 self . brillig_context . binary_instruction (
@@ -1401,6 +1317,56 @@ impl<'block> BrilligBlock<'block> {
14011317 self . brillig_context . deallocate_single_addr ( bias) ;
14021318 }
14031319
1320+ fn convert_signed_shr (
1321+ & mut self ,
1322+ left : SingleAddrVariable ,
1323+ right : SingleAddrVariable ,
1324+ result : SingleAddrVariable ,
1325+ ) {
1326+ // Check if left is negative
1327+ let left_is_negative = SingleAddrVariable :: new ( self . brillig_context . allocate_register ( ) , 1 ) ;
1328+ let max_positive = self
1329+ . brillig_context
1330+ . make_constant_instruction ( ( ( 1_u128 << ( left. bit_size - 1 ) ) - 1 ) . into ( ) , left. bit_size ) ;
1331+ self . brillig_context . binary_instruction (
1332+ max_positive,
1333+ left,
1334+ left_is_negative,
1335+ BrilligBinaryOp :: LessThan ,
1336+ ) ;
1337+
1338+ self . brillig_context . codegen_branch ( left_is_negative. address , |ctx, is_negative| {
1339+ if is_negative {
1340+ let one = ctx. make_constant_instruction ( 1_u128 . into ( ) , left. bit_size ) ;
1341+
1342+ // computes 2^right
1343+ let two = ctx. make_constant_instruction ( 2_u128 . into ( ) , left. bit_size ) ;
1344+ let two_pow = ctx. make_constant_instruction ( 1_u128 . into ( ) , left. bit_size ) ;
1345+ let right_u32 = SingleAddrVariable :: new ( ctx. allocate_register ( ) , 32 ) ;
1346+ ctx. cast ( right_u32, right) ;
1347+ let pow_body = |ctx : & mut BrilligContext < _ , _ > , _: SingleAddrVariable | {
1348+ ctx. binary_instruction ( two_pow, two, two_pow, BrilligBinaryOp :: Mul ) ;
1349+ } ;
1350+ ctx. codegen_for_loop ( None , right_u32. address , None , pow_body) ;
1351+
1352+ // Right shift using division on 1-complement
1353+ ctx. binary_instruction ( left, one, result, BrilligBinaryOp :: Add ) ;
1354+ ctx. convert_signed_division ( result, two_pow, result) ;
1355+ ctx. binary_instruction ( result, one, result, BrilligBinaryOp :: Sub ) ;
1356+
1357+ // Clean-up
1358+ ctx. deallocate_single_addr ( one) ;
1359+ ctx. deallocate_single_addr ( two) ;
1360+ ctx. deallocate_single_addr ( two_pow) ;
1361+ ctx. deallocate_single_addr ( right_u32) ;
1362+ } else {
1363+ ctx. binary_instruction ( left, right, result, BrilligBinaryOp :: Shr ) ;
1364+ }
1365+ } ) ;
1366+
1367+ self . brillig_context . deallocate_single_addr ( left_is_negative) ;
1368+ }
1369+
14041370 #[ allow( clippy:: too_many_arguments) ]
14051371 fn add_overflow_check (
14061372 & mut self ,
0 commit comments