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