1; RUN: opt -passes=inline %s -S | FileCheck %s 2 3 4; Ordinary function is inlined into strictfp function. 5 6define float @inlined_01(float %a) { 7entry: 8 %add = fadd float %a, %a 9 ret float %add 10} 11 12define float @host_02(float %a) #0 { 13entry: 14 %0 = call float @inlined_01(float %a) #0 15 %add = call float @llvm.experimental.constrained.fadd.f32(float %0, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 16 ret float %add 17; CHECK-LABEL: @host_02 18; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 19; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 20} 21 22 23; strictfp function is inlined into another strictfp function. 24 25define float @inlined_03(float %a) #0 { 26entry: 27 %add = call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.downward", metadata !"fpexcept.maytrap") #0 28 ret float %add 29} 30 31define float @host_04(float %a) #0 { 32entry: 33 %0 = call float @inlined_03(float %a) #0 34 %add = call float @llvm.experimental.constrained.fadd.f32(float %0, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 35 ret float %add 36; CHECK-LABEL: @host_04 37; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.downward", metadata !"fpexcept.maytrap") #0 38; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 39} 40 41 42; strictfp function is NOT inlined into ordinary function. 43 44define float @inlined_05(float %a) strictfp { 45entry: 46 %add = call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.downward", metadata !"fpexcept.maytrap") #0 47 ret float %add 48} 49 50define float @host_06(float %a) { 51entry: 52 %0 = call float @inlined_05(float %a) 53 %add = fadd float %0, 2.000000e+00 54 ret float %add 55; CHECK-LABEL: @host_06 56; CHECK: call float @inlined_05(float %a) 57; CHECK: fadd float %0, 2.000000e+00 58} 59 60 61; Calls in inlined function must get strictfp attribute. 62 63declare float @func_ext(float); 64 65define float @inlined_07(float %a) { 66entry: 67 %0 = call float @func_ext(float %a) 68 %add = fadd float %0, %a 69 70 ret float %add 71} 72 73define float @host_08(float %a) #0 { 74entry: 75 %0 = call float @inlined_07(float %a) #0 76 %add = call float @llvm.experimental.constrained.fadd.f32(float %0, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 77 ret float %add 78; CHECK-LABEL: @host_08 79; CHECK: call float @func_ext(float {{.*}}) #0 80; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 81; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 82} 83 84 85; Cloning particular instructions. 86 87; fpext has two overloaded types. 88define double @inlined_09(float %a) { 89entry: 90 %t = fpext float %a to double 91 ret double %t 92} 93 94define double @host_10(float %a) #0 { 95entry: 96 %0 = call double @inlined_09(float %a) #0 97 %add = call double @llvm.experimental.constrained.fadd.f64(double %0, double 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 98 ret double %add 99; CHECK-LABEL: @host_10 100; CHECK: call double @llvm.experimental.constrained.fpext.f64.f32(float {{.*}}, metadata !"fpexcept.ignore") #0 101; CHECK: call double @llvm.experimental.constrained.fadd.f64(double {{.*}}, double 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 102} 103 104; fcmp does not depend on rounding mode and has metadata argument. 105define i1 @inlined_11(float %a, float %b) { 106entry: 107 %t = fcmp oeq float %a, %b 108 ret i1 %t 109} 110 111define i1 @host_12(float %a, float %b) #0 { 112entry: 113 %add = call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 114 %cmp = call i1 @inlined_11(float %a, float %b) #0 115 ret i1 %cmp 116; CHECK-LABEL: @host_12 117; CHECK: call float @llvm.experimental.constrained.fadd.f32(float %a, float %b, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 118; CHECK: call i1 @llvm.experimental.constrained.fcmp.f32(float {{.*}}, metadata !"oeq", metadata !"fpexcept.ignore") #0 119} 120 121; Intrinsic 'ceil' has constrained variant. 122define float @inlined_13(float %a) { 123entry: 124 %t = call float @llvm.ceil.f32(float %a) 125 ret float %t 126} 127 128define float @host_14(float %a) #0 { 129entry: 130 %0 = call float @inlined_13(float %a) #0 131 %add = call float @llvm.experimental.constrained.fadd.f32(float %0, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 132 ret float %add 133; CHECK-LABEL: @host_14 134; CHECK: call float @llvm.experimental.constrained.ceil.f32(float %a, metadata !"fpexcept.ignore") #0 135; CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float 2.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 136} 137 138attributes #0 = { strictfp } 139 140declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) 141declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) 142declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata) 143declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata) 144declare float @llvm.experimental.constrained.ceil.f32(float, metadata) 145declare float @llvm.ceil.f32(float) 146