1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -aggressive-instcombine -S | FileCheck %s
3; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s
4target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
5
6; Aggressive Instcombine should be able to reduce width of these constant
7; expressions, without crashing.
8
9declare i32 @use32(i32)
10declare <2 x i32> @use32_vec(<2 x i32>)
11declare <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32>)
12
13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14;; These tests check cases where expression dag post-dominated by TruncInst
15;; contains instruction, which has more than one usage.
16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17
18define void @const_expression_mul() {
19; CHECK-LABEL: @const_expression_mul(
20; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @use32(i32 242)
21; CHECK-NEXT:    ret void
22;
23  %A = mul i64 11, 22
24  %T = trunc i64 %A to i32
25  call i32 @use32(i32 %T)
26  ret void
27}
28
29define void @const_expression_zext() {
30; CHECK-LABEL: @const_expression_zext(
31; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @use32(i32 33)
32; CHECK-NEXT:    ret void
33;
34  %A = zext i32 33 to i64
35  %T = trunc i64 %A to i32
36  call i32 @use32(i32 %T)
37  ret void
38}
39
40define void @const_expression_trunc() {
41; CHECK-LABEL: @const_expression_trunc(
42; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @use32(i32 44)
43; CHECK-NEXT:    ret void
44;
45  %T = trunc i64 44 to i32
46  call i32 @use32(i32 %T)
47  ret void
48}
49
50; Check that we handle constant expression trunc instruction, when it is a leaf
51; of other trunc expression pattern:
52; 1. %T1 is the constant expression trunc instruction.
53; 2. %T2->%T1 is the trunc expression pattern we want to reduce.
54define void @const_expression_trunc_leaf() {
55; CHECK-LABEL: @const_expression_trunc_leaf(
56; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @use32(i32 44)
57; CHECK-NEXT:    ret void
58;
59  %T1 = trunc i64 44 to i48
60  %T2 = trunc i48 %T1 to i32
61  call i32 @use32(i32 %T2)
62  ret void
63}
64
65; Check that we handle zext instruction, which turns into trunc instruction.
66; Notice that there are two expression patterns below:
67; 1. %T2->%T1
68; 2. %T1`->%A (where %T1` is the reduced node of %T1 into trunc instruction)
69define void @const_expression_zext_to_trunc() {
70; CHECK-LABEL: @const_expression_zext_to_trunc(
71; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @use32(i32 44)
72; CHECK-NEXT:    ret void
73;
74  %A = add i64 11, 33
75  %T1 = zext i64 %A to i128
76  %T2 = trunc i128 %T1 to i32
77  call i32 @use32(i32 %T2)
78  ret void
79}
80
81define void @const_expression_mul_vec() {
82; CHECK-LABEL: @const_expression_mul_vec(
83; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> <i32 24531, i32 24864>)
84; CHECK-NEXT:    ret void
85;
86  %A = mul <2 x i64> <i64 111, i64 112>, <i64 221, i64 222>
87  %T = trunc <2 x i64> %A to <2 x i32>
88  call <2 x i32> @use32_vec(<2 x i32> %T)
89  ret void
90}
91
92define void @const_expression_zext_vec() {
93; CHECK-LABEL: @const_expression_zext_vec(
94; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> <i32 331, i32 332>)
95; CHECK-NEXT:    ret void
96;
97  %A = zext <2 x i32> <i32 331, i32 332> to <2 x i64>
98  %T = trunc <2 x i64> %A to <2 x i32>
99  call <2 x i32> @use32_vec(<2 x i32> %T)
100  ret void
101}
102
103define void @const_expression_trunc_vec() {
104; CHECK-LABEL: @const_expression_trunc_vec(
105; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @use32_vec(<2 x i32> <i32 551, i32 552>)
106; CHECK-NEXT:    ret void
107;
108  %T = trunc <2 x i64> <i64 551, i64 552> to <2 x i32>
109  call <2 x i32> @use32_vec(<2 x i32> %T)
110  ret void
111}
112
113define void @const_expression_mul_scale_vec() {
114; CHECK-LABEL: @const_expression_mul_scale_vec(
115; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> zeroinitializer)
116; CHECK-NEXT:    ret void
117;
118  %A = mul <vscale x 2 x i64> zeroinitializer, zeroinitializer
119  %T = trunc <vscale x 2 x i64> %A to <vscale x 2 x i32>
120  call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> %T)
121  ret void
122}
123
124define void @const_expression_zext_scale_vec() {
125; CHECK-LABEL: @const_expression_zext_scale_vec(
126; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> zeroinitializer)
127; CHECK-NEXT:    ret void
128;
129  %A = zext <vscale x 2 x i32> zeroinitializer to <vscale x 2 x i64>
130  %T = trunc <vscale x 2 x i64> %A to <vscale x 2 x i32>
131  call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> %T)
132  ret void
133}
134
135define void @const_expression_trunc_scale_vec() {
136; CHECK-LABEL: @const_expression_trunc_scale_vec(
137; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> zeroinitializer)
138; CHECK-NEXT:    ret void
139;
140  %T = trunc <vscale x 2 x i64> zeroinitializer to <vscale x 2 x i32>
141  call <vscale x 2 x i32> @use32_scale_vec(<vscale x 2 x i32> %T)
142  ret void
143}
144