; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -passes=correlated-propagation < %s | FileCheck %s declare void @llvm.trap() declare {i8, i1} @llvm.uadd.with.overflow(i8, i8) declare {i8, i1} @llvm.sadd.with.overflow(i8, i8) declare {i8, i1} @llvm.usub.with.overflow(i8, i8) declare {i8, i1} @llvm.ssub.with.overflow(i8, i8) declare {i8, i1} @llvm.umul.with.overflow(i8, i8) declare {i8, i1} @llvm.smul.with.overflow(i8, i8) define i1 @uadd_ov_false(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @uadd_ov_false( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], -102 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp ugt i8 %x, 154 store i1 %c1, i1* %pc %c2 = icmp ugt i8 %x, 155 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @uadd_ov_true(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @uadd_ov_true( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], -100 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp ugt i8 %x, 156 store i1 %c1, i1* %pc %c2 = icmp ugt i8 %x, 155 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @sadd_ov_false(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @sadd_ov_false( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 26 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp sgt i8 %x, 26 store i1 %c1, i1* %pc %c2 = icmp sgt i8 %x, 27 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @sadd_ov_true(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @sadd_ov_true( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], 28 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp sgt i8 %x, 28 store i1 %c1, i1* %pc %c2 = icmp sgt i8 %x, 27 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @usub_ov_false(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @usub_ov_false( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[X]], 101 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp ult i8 %x, 101 store i1 %c1, i1* %pc %c2 = icmp ult i8 %x, 100 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @usub_ov_true(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @usub_ov_true( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[X]], 99 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp ult i8 %x, 99 store i1 %c1, i1* %pc %c2 = icmp ult i8 %x, 100 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @ssub_ov_false(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @ssub_ov_false( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -27 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp slt i8 %x, -27 store i1 %c1, i1* %pc %c2 = icmp slt i8 %x, -28 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @ssub_ov_true(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @ssub_ov_true( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[X]], -29 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp slt i8 %x, -29 store i1 %c1, i1* %pc %c2 = icmp slt i8 %x, -28 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @umul_ov_false(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @umul_ov_false( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], 24 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp ugt i8 %x, 24 store i1 %c1, i1* %pc %c2 = icmp ugt i8 %x, 25 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @umul_ov_true(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @umul_ov_true( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[X]], 26 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp ugt i8 %x, 26 store i1 %c1, i1* %pc %c2 = icmp ugt i8 %x, 25 ret i1 %c2 trap: call void @llvm.trap() unreachable } ; Signed mul is constrained from both sides. define i1 @smul_ov_false_bound1(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @smul_ov_false_bound1( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -11 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp slt i8 %x, -11 store i1 %c1, i1* %pc %c2 = icmp slt i8 %x, -12 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @smul_ov_false_bound2(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @smul_ov_false_bound2( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 11 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %c1 = icmp sgt i8 %x, 11 store i1 %c1, i1* %pc %c2 = icmp sgt i8 %x, 12 ret i1 %c2 trap: call void @llvm.trap() unreachable } ; Can't use slt/sgt to test for a hole in the range, check equality instead. define i1 @smul_ov_true_bound1(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @smul_ov_true_bound1( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], -13 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp eq i8 %x, -13 store i1 %c1, i1* %pc %c2 = icmp eq i8 %x, -12 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @smul_ov_true_bound2(i8 %x, i8* %px, i1* %pc) { ; CHECK-LABEL: @smul_ov_true_bound2( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: store i8 [[VAL]], i8* [[PX:%.*]], align 1 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: ; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], 13 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 false ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %val = extractvalue {i8, i1} %val_ov, 0 store i8 %val, i8* %px %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %overflow, label %trap overflow: %c1 = icmp eq i8 %x, 13 store i1 %c1, i1* %pc %c2 = icmp eq i8 %x, 12 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @uadd_val(i8 %x, i1* %pc) { ; CHECK-LABEL: @uadd_val( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp ugt i8 [[VAL]], 100 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp ugt i8 %val, 100 store i1 %c1, i1* %pc %c2 = icmp uge i8 %val, 100 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @sadd_val(i8 %x, i1* %pc) { ; CHECK-LABEL: @sadd_val( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[VAL]], -28 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp sgt i8 %val, -28 store i1 %c1, i1* %pc %c2 = icmp sge i8 %val, -28 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @usub_val(i8 %x, i1* %pc) { ; CHECK-LABEL: @usub_val( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[VAL]], -101 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp ult i8 %val, 155 store i1 %c1, i1* %pc %c2 = icmp ule i8 %val, 155 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @ssub_val(i8 %x, i1* %pc) { ; CHECK-LABEL: @ssub_val( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[VAL]], 27 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp slt i8 %val, 27 store i1 %c1, i1* %pc %c2 = icmp sle i8 %val, 27 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @umul_val(i8 %x, i1* %pc) { ; CHECK-LABEL: @umul_val( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp ult i8 [[VAL]], -6 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp ult i8 %val, 250 store i1 %c1, i1* %pc %c2 = icmp ule i8 %val, 250 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @smul_val_bound1(i8 %x, i1* %pc) { ; CHECK-LABEL: @smul_val_bound1( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[VAL]], 120 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp slt i8 %val, 120 store i1 %c1, i1* %pc %c2 = icmp sle i8 %val, 120 ret i1 %c2 trap: call void @llvm.trap() unreachable } define i1 @smul_val_bound2(i8 %x, i1* %pc) { ; CHECK-LABEL: @smul_val_bound2( ; CHECK-NEXT: [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]] ; CHECK: no_overflow: ; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0 ; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[VAL]], -120 ; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10) %ov = extractvalue {i8, i1} %val_ov, 1 br i1 %ov, label %trap, label %no_overflow no_overflow: %val = extractvalue {i8, i1} %val_ov, 0 %c1 = icmp sgt i8 %val, -120 store i1 %c1, i1* %pc %c2 = icmp sge i8 %val, -120 ret i1 %c2 trap: call void @llvm.trap() unreachable }