1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
; RUN: opt %s -expand-arith-with-overflow -expand-struct-regs -S | FileCheck %s
; RUN: opt %s -expand-arith-with-overflow -expand-struct-regs -S | \
; RUN: FileCheck %s -check-prefix=CLEANUP
declare {i32, i1} @llvm.umul.with.overflow.i32(i32, i32)
declare {i64, i1} @llvm.umul.with.overflow.i64(i64, i64)
declare {i16, i1} @llvm.uadd.with.overflow.i16(i16, i16)
; CLEANUP-NOT: with.overflow
; CLEANUP-NOT: extractvalue
; CLEANUP-NOT: insertvalue
define void @umul32_by_const(i32 %x, i32* %result_val, i1* %result_overflow) {
%pair = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 256)
%val = extractvalue {i32, i1} %pair, 0
%overflow = extractvalue {i32, i1} %pair, 1
store i32 %val, i32* %result_val
store i1 %overflow, i1* %result_overflow
ret void
}
; The bound is 16777215 == 0xffffff == ((1 << 32) - 1) / 256
; CHECK: define void @umul32_by_const(
; CHECK-NEXT: %pair.arith = mul i32 %x, 256
; CHECK-NEXT: %pair.overflow = icmp ugt i32 %x, 16777215
; CHECK-NEXT: store i32 %pair.arith, i32* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
; Check that the pass can expand multiple uses of the same intrinsic.
define void @umul32_by_const2(i32 %x, i32* %result_val, i1* %result_overflow) {
%pair = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 65536)
%val = extractvalue {i32, i1} %pair, 0
; Check that the pass can expand multiple uses of %pair.
%overflow1 = extractvalue {i32, i1} %pair, 1
%overflow2 = extractvalue {i32, i1} %pair, 1
store i32 %val, i32* %result_val
store i1 %overflow1, i1* %result_overflow
store i1 %overflow2, i1* %result_overflow
ret void
}
; CHECK: define void @umul32_by_const2(
; CHECK-NEXT: %pair.arith = mul i32 %x, 65536
; CHECK-NEXT: %pair.overflow = icmp ugt i32 %x, 65535
; CHECK-NEXT: store i32 %pair.arith, i32* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
define void @umul64_by_const(i64 %x, i64* %result_val, i1* %result_overflow) {
; Multiply by 1 << 55.
%pair = call {i64, i1} @llvm.umul.with.overflow.i64(i64 36028797018963968, i64 %x)
%val = extractvalue {i64, i1} %pair, 0
%overflow = extractvalue {i64, i1} %pair, 1
store i64 %val, i64* %result_val
store i1 %overflow, i1* %result_overflow
ret void
}
; CHECK: define void @umul64_by_const(i64 %x, i64* %result_val, i1* %result_overflow) {
; CHECK-NEXT: %pair.arith = mul i64 %x, 36028797018963968
; CHECK-NEXT: %pair.overflow = icmp ugt i64 %x, 511
; CHECK-NEXT: store i64 %pair.arith, i64* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
define void @uadd16_with_const(i16 %x, i16* %result_val, i1* %result_overflow) {
%pair = call {i16, i1} @llvm.uadd.with.overflow.i16(i16 %x, i16 35)
%val = extractvalue {i16, i1} %pair, 0
%overflow = extractvalue {i16, i1} %pair, 1
store i16 %val, i16* %result_val
store i1 %overflow, i1* %result_overflow
ret void
}
; CHECK: define void @uadd16_with_const(i16 %x, i16* %result_val, i1* %result_overflow) {
; CHECK-NEXT: %pair.arith = add i16 %x, 35
; CHECK-NEXT: %pair.overflow = icmp ugt i16 %x, -36
; CHECK-NEXT: store i16 %pair.arith, i16* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
|