@@ -1318,28 +1318,80 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
13181318 fn checked_binop (
13191319 & mut self ,
13201320 oop : OverflowOp ,
1321- _ty : Ty < ' _ > ,
1321+ ty : Ty < ' _ > ,
13221322 lhs : Self :: Value ,
13231323 rhs : Self :: Value ,
13241324 ) -> ( Self :: Value , Self :: Value ) {
1325- // NOTE(eddyb) this needs to be `undef`, not `false`/`true`, because
1326- // we don't want the user's boolean constants to keep the zombie alive.
1327- let bool = SpirvType :: Bool . def ( self . span ( ) , self ) ;
1328- let overflowed = self . undef ( bool) ;
1329- let result = match oop {
1330- OverflowOp :: Add => ( self . add ( lhs, rhs) , overflowed) ,
1331- OverflowOp :: Sub => ( self . sub ( lhs, rhs) , overflowed) ,
1332- OverflowOp :: Mul => ( self . mul ( lhs, rhs) , overflowed) ,
1325+ // adopted partially from https://github.com/ziglang/zig/blob/master/src/codegen/spirv.zig
1326+ let is_add = match oop {
1327+ OverflowOp :: Add => true ,
1328+ OverflowOp :: Sub => false ,
1329+ OverflowOp :: Mul => {
1330+ // NOTE(eddyb) this needs to be `undef`, not `false`/`true`, because
1331+ // we don't want the user's boolean constants to keep the zombie alive.
1332+ let bool = SpirvType :: Bool . def ( self . span ( ) , self ) ;
1333+ let overflowed = self . undef ( bool) ;
1334+
1335+ let result = ( self . mul ( lhs, rhs) , overflowed) ;
1336+ self . zombie ( result. 1 . def ( self ) , "checked mul is not supported yet" ) ;
1337+ return result;
1338+ }
13331339 } ;
1334- self . zombie (
1335- result. 1 . def ( self ) ,
1336- match oop {
1337- OverflowOp :: Add => "checked add is not supported yet" ,
1338- OverflowOp :: Sub => "checked sub is not supported yet" ,
1339- OverflowOp :: Mul => "checked mul is not supported yet" ,
1340- } ,
1341- ) ;
1342- result
1340+ let signed = match ty. kind ( ) {
1341+ ty:: Int ( _) => true ,
1342+ ty:: Uint ( _) => false ,
1343+ other => self . fatal ( format ! (
1344+ "Unexpected {} type: {other:#?}" ,
1345+ match oop {
1346+ OverflowOp :: Add => "checked add" ,
1347+ OverflowOp :: Sub => "checked sub" ,
1348+ OverflowOp :: Mul => "checked mul" ,
1349+ }
1350+ ) ) ,
1351+ } ;
1352+
1353+ let result = if is_add {
1354+ self . add ( lhs, rhs)
1355+ } else {
1356+ self . sub ( lhs, rhs)
1357+ } ;
1358+
1359+ let overflowed = if signed {
1360+ // when adding, overflow could happen if
1361+ // - rhs is positive and result < lhs; or
1362+ // - rhs is negative and result > lhs
1363+ // this is equivalent to (rhs < 0) == (result > lhs)
1364+ //
1365+ // when subtracting, overflow happens if
1366+ // - rhs is positive and result > lhs; or
1367+ // - rhs is negative and result < lhs
1368+ // this is equivalent to (rhs < 0) == (result < lhs)
1369+ let rhs_lt_zero = self . icmp ( IntPredicate :: IntSLT , rhs, self . constant_int ( rhs. ty , 0 ) ) ;
1370+ let result_gt_lhs = self . icmp (
1371+ if is_add {
1372+ IntPredicate :: IntSGT
1373+ } else {
1374+ IntPredicate :: IntSLT
1375+ } ,
1376+ result,
1377+ lhs,
1378+ ) ;
1379+ self . icmp ( IntPredicate :: IntEQ , rhs_lt_zero, result_gt_lhs)
1380+ } else {
1381+ // for unsigned addition, overflow occured if the result is less than any of the operands.
1382+ // for subtraction, overflow occured if the result is greater.
1383+ self . icmp (
1384+ if is_add {
1385+ IntPredicate :: IntULT
1386+ } else {
1387+ IntPredicate :: IntUGT
1388+ } ,
1389+ result,
1390+ lhs,
1391+ )
1392+ } ;
1393+
1394+ ( result, overflowed)
13431395 }
13441396
13451397 // rustc has the concept of an immediate vs. memory type - bools are compiled to LLVM bools as
@@ -2766,8 +2818,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
27662818 kind : SpirvValueKind :: Def ( b_id) ,
27672819 ..
27682820 } ,
2769- _, // `&'static panic::Location<'static>`
2770- ] = args[ ..]
2821+ // NOTE(fee1-dead): the standard `panic` takes in a `Location` due to `track_caller`.
2822+ // but for `panic_nounwind` it does not, therefore we only look at the first two arguments.
2823+ ] = args[ ..2 ]
27712824 {
27722825 if let Some ( const_msg) = const_str_as_utf8 ( & [ a_id, b_id] ) {
27732826 decoded_format_args. const_pieces = Some ( [ const_msg] . into_iter ( ) . collect ( ) ) ;
0 commit comments