1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -S -passes=early-cse -earlycse-debug-hash | FileCheck %s 3; RUN: opt < %s -S -passes='early-cse<memssa>' | FileCheck %s 4 5; Test use of constrained floating point intrinsics with dynamic 6; rounding mode. Dynamic rounding _must_ disable CSE since EarlyCSE 7; will CSE across function calls and we cannot know if the rounding 8; mode will be changed by any arbitrary function call. 9 10define double @multiple_fadd(double %a, double %b) #0 { 11; CHECK-LABEL: @multiple_fadd( 12; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]] 13; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 14; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 15; CHECK-NEXT: ret double [[TMP2]] 16; 17 %1 = call double @llvm.experimental.constrained.fadd.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 18 %2 = call double @llvm.experimental.constrained.fadd.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 19 %3 = call double @foo.f64(double %1, double %2) #0 20 ret double %2 21} 22 23define double @multiple_fadd_split(double %a, double %b) #0 { 24; CHECK-LABEL: @multiple_fadd_split( 25; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 26; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 27; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 28; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 29; CHECK-NEXT: ret double [[TMP2]] 30; 31 %1 = call double @llvm.experimental.constrained.fadd.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 32 call void @arbitraryfunc() #0 33 %2 = call double @llvm.experimental.constrained.fadd.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 34 %3 = call double @foo.f64(double %1, double %2) #0 35 ret double %2 36} 37 38define double @multiple_fsub(double %a, double %b) #0 { 39; CHECK-LABEL: @multiple_fsub( 40; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fsub.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 41; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fsub.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 42; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 43; CHECK-NEXT: ret double [[TMP2]] 44; 45 %1 = call double @llvm.experimental.constrained.fsub.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 46 %2 = call double @llvm.experimental.constrained.fsub.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 47 %3 = call double @foo.f64(double %1, double %2) #0 48 ret double %2 49} 50 51define double @multiple_fsub_split(double %a, double %b) #0 { 52; CHECK-LABEL: @multiple_fsub_split( 53; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fsub.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 54; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 55; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fsub.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 56; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 57; CHECK-NEXT: ret double [[TMP2]] 58; 59 %1 = call double @llvm.experimental.constrained.fsub.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 60 call void @arbitraryfunc() #0 61 %2 = call double @llvm.experimental.constrained.fsub.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 62 %3 = call double @foo.f64(double %1, double %2) #0 63 ret double %2 64} 65 66define double @multiple_fmul(double %a, double %b) #0 { 67; CHECK-LABEL: @multiple_fmul( 68; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fmul.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 69; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fmul.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 70; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 71; CHECK-NEXT: ret double [[TMP2]] 72; 73 %1 = call double @llvm.experimental.constrained.fmul.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 74 %2 = call double @llvm.experimental.constrained.fmul.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 75 %3 = call double @foo.f64(double %1, double %2) #0 76 ret double %2 77} 78 79define double @multiple_fmul_split(double %a, double %b) #0 { 80; CHECK-LABEL: @multiple_fmul_split( 81; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fmul.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 82; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 83; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fmul.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 84; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 85; CHECK-NEXT: ret double [[TMP2]] 86; 87 %1 = call double @llvm.experimental.constrained.fmul.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 88 call void @arbitraryfunc() #0 89 %2 = call double @llvm.experimental.constrained.fmul.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 90 %3 = call double @foo.f64(double %1, double %2) #0 91 ret double %2 92} 93 94define double @multiple_fdiv(double %a, double %b) #0 { 95; CHECK-LABEL: @multiple_fdiv( 96; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fdiv.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 97; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fdiv.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 98; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 99; CHECK-NEXT: ret double [[TMP2]] 100; 101 %1 = call double @llvm.experimental.constrained.fdiv.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 102 %2 = call double @llvm.experimental.constrained.fdiv.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 103 %3 = call double @foo.f64(double %1, double %2) #0 104 ret double %2 105} 106 107define double @multiple_fdiv_split(double %a, double %b) #0 { 108; CHECK-LABEL: @multiple_fdiv_split( 109; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.fdiv.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 110; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 111; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.fdiv.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 112; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 113; CHECK-NEXT: ret double [[TMP2]] 114; 115 %1 = call double @llvm.experimental.constrained.fdiv.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 116 call void @arbitraryfunc() #0 117 %2 = call double @llvm.experimental.constrained.fdiv.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 118 %3 = call double @foo.f64(double %1, double %2) #0 119 ret double %2 120} 121 122define double @multiple_frem(double %a, double %b) #0 { 123; CHECK-LABEL: @multiple_frem( 124; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.frem.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 125; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.frem.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 126; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 127; CHECK-NEXT: ret double [[TMP2]] 128; 129 %1 = call double @llvm.experimental.constrained.frem.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 130 %2 = call double @llvm.experimental.constrained.frem.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 131 %3 = call double @foo.f64(double %1, double %2) #0 132 ret double %2 133} 134 135define double @multiple_frem_split(double %a, double %b) #0 { 136; CHECK-LABEL: @multiple_frem_split( 137; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.frem.f64(double [[A:%.*]], double [[B:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 138; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 139; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.frem.f64(double [[A]], double [[B]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 140; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP2]]) #[[ATTR0]] 141; CHECK-NEXT: ret double [[TMP2]] 142; 143 %1 = call double @llvm.experimental.constrained.frem.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 144 call void @arbitraryfunc() #0 145 %2 = call double @llvm.experimental.constrained.frem.f64(double %a, double %b, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 146 %3 = call double @foo.f64(double %1, double %2) #0 147 ret double %2 148} 149 150define double @multiple_uitofp(i32 %a) #0 { 151; CHECK-LABEL: @multiple_uitofp( 152; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 153; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 [[A]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 154; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP1]]) #[[ATTR0]] 155; CHECK-NEXT: ret double [[TMP2]] 156; 157 %1 = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 158 %2 = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 159 %3 = call double @foo.f64(double %1, double %1) #0 160 ret double %2 161} 162 163define double @multiple_uitofp_split(i32 %a) #0 { 164; CHECK-LABEL: @multiple_uitofp_split( 165; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 166; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 167; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 [[A]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 168; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP1]]) #[[ATTR0]] 169; CHECK-NEXT: ret double [[TMP2]] 170; 171 %1 = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 172 call void @arbitraryfunc() #0 173 %2 = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 174 %3 = call double @foo.f64(double %1, double %1) #0 175 ret double %2 176} 177 178define double @multiple_sitofp(i32 %a) #0 { 179; CHECK-LABEL: @multiple_sitofp( 180; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 181; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 [[A]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 182; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP1]]) #[[ATTR0]] 183; CHECK-NEXT: ret double [[TMP2]] 184; 185 %1 = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 186 %2 = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 187 %3 = call double @foo.f64(double %1, double %1) #0 188 ret double %2 189} 190 191define double @multiple_sitofp_split(i32 %a) #0 { 192; CHECK-LABEL: @multiple_sitofp_split( 193; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 194; CHECK-NEXT: call void @arbitraryfunc() #[[ATTR0]] 195; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 [[A]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] 196; CHECK-NEXT: [[TMP3:%.*]] = call double @foo.f64(double [[TMP1]], double [[TMP1]]) #[[ATTR0]] 197; CHECK-NEXT: ret double [[TMP2]] 198; 199 %1 = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 200 call void @arbitraryfunc() #0 201 %2 = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 202 %3 = call double @foo.f64(double %1, double %1) #0 203 ret double %2 204} 205 206attributes #0 = { strictfp } 207 208declare void @arbitraryfunc() #0 209declare double @foo.f64(double, double) #0 210declare i32 @bar.i32(i32, i32) #0 211 212declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) 213declare double @llvm.experimental.constrained.fsub.f64(double, double, metadata, metadata) 214declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) 215declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) 216declare double @llvm.experimental.constrained.frem.f64(double, double, metadata, metadata) 217declare i32 @llvm.experimental.constrained.fptoui.i32.f64(double, metadata) 218declare double @llvm.experimental.constrained.uitofp.f64.i32(i32, metadata, metadata) 219declare i32 @llvm.experimental.constrained.fptosi.i32.f64(double, metadata) 220declare double @llvm.experimental.constrained.sitofp.f64.i32(i32, metadata, metadata) 221declare i1 @llvm.experimental.constrained.fcmp.i1.f64(double, double, metadata, metadata) 222declare i1 @llvm.experimental.constrained.fcmps.i1.f64(double, double, metadata, metadata) 223