| ; 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 |
| } |