199 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 52; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD3; RUN: llc -mtriple=aarch64 -global-isel=true -global-isel-abort=2 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI4 5; CHECK-GI: warning: Instruction selection used fallback path for unused_div_fpexcept_strict6; CHECK-GI-NEXT: warning: Instruction selection used fallback path for unused_div_round_dynamic7; CHECK-GI-NEXT: warning: Instruction selection used fallback path for add_twice_fpexcept_strict8; CHECK-GI-NEXT: warning: Instruction selection used fallback path for add_twice_round_dynamic9; CHECK-GI-NEXT: warning: Instruction selection used fallback path for set_rounding10; CHECK-GI-NEXT: warning: Instruction selection used fallback path for set_rounding_fpexcept_strict11; CHECK-GI-NEXT: warning: Instruction selection used fallback path for set_rounding_round_dynamic12 13; Div whose result is unused should be removed unless we have strict exceptions14 15define void @unused_div(float %x, float %y) {16; CHECK-LABEL: unused_div:17; CHECK: // %bb.0: // %entry18; CHECK-NEXT: ret19entry:20 %add = fdiv float %x, %y21 ret void22}23 24define void @unused_div_fpexcept_strict(float %x, float %y) #0 {25; CHECK-LABEL: unused_div_fpexcept_strict:26; CHECK: // %bb.0: // %entry27; CHECK-NEXT: fdiv s0, s0, s128; CHECK-NEXT: ret29entry:30 %add = call float @llvm.experimental.constrained.fdiv.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") #031 ret void32}33 34define void @unused_div_round_dynamic(float %x, float %y) #0 {35; CHECK-LABEL: unused_div_round_dynamic:36; CHECK: // %bb.0: // %entry37; CHECK-NEXT: ret38entry:39 %add = call float @llvm.experimental.constrained.fdiv.f32(float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.ignore") #040 ret void41}42 43 44; Machine CSE should eliminate the second add unless we have strict exceptions45define float @add_twice(float %x, float %y, i32 %n) {46; CHECK-LABEL: add_twice:47; CHECK: // %bb.0: // %entry48; CHECK-NEXT: fadd s0, s0, s149; CHECK-NEXT: cmp w0, #050; CHECK-NEXT: fmul s1, s0, s051; CHECK-NEXT: fcsel s0, s0, s1, eq52; CHECK-NEXT: ret53entry:54 %add = fadd float %x, %y55 %tobool.not = icmp eq i32 %n, 056 br i1 %tobool.not, label %if.end, label %if.then57 58if.then:59 %add1 = fadd float %x, %y60 %mul = fmul float %add, %add161 br label %if.end62 63if.end:64 %a.0 = phi float [ %mul, %if.then ], [ %add, %entry ]65 ret float %a.066}67 68define float @add_twice_fpexcept_strict(float %x, float %y, i32 %n) #0 {69; CHECK-LABEL: add_twice_fpexcept_strict:70; CHECK: // %bb.0: // %entry71; CHECK-NEXT: fmov s2, s072; CHECK-NEXT: fadd s0, s0, s173; CHECK-NEXT: cbz w0, .LBB4_274; CHECK-NEXT: // %bb.1: // %if.then75; CHECK-NEXT: fadd s1, s2, s176; CHECK-NEXT: fmul s0, s0, s177; CHECK-NEXT: .LBB4_2: // %if.end78; CHECK-NEXT: ret79entry:80 %add = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") #081 %tobool.not = icmp eq i32 %n, 082 br i1 %tobool.not, label %if.end, label %if.then83 84if.then:85 %add1 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") #086 %mul = call float @llvm.experimental.constrained.fmul.f32(float %add, float %add1, metadata !"round.tonearest", metadata !"fpexcept.strict") #087 br label %if.end88 89if.end:90 %a.0 = phi float [ %mul, %if.then ], [ %add, %entry ]91 ret float %a.092}93 94define float @add_twice_round_dynamic(float %x, float %y, i32 %n) #0 {95; CHECK-LABEL: add_twice_round_dynamic:96; CHECK: // %bb.0: // %entry97; CHECK-NEXT: fadd s0, s0, s198; CHECK-NEXT: cbz w0, .LBB5_299; CHECK-NEXT: // %bb.1: // %if.then100; CHECK-NEXT: fmul s0, s0, s0101; CHECK-NEXT: .LBB5_2: // %if.end102; CHECK-NEXT: ret103entry:104 %add = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0105 %tobool.not = icmp eq i32 %n, 0106 br i1 %tobool.not, label %if.end, label %if.then107 108if.then:109 %add1 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0110 %mul = call float @llvm.experimental.constrained.fmul.f32(float %add, float %add1, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0111 br label %if.end112 113if.end:114 %a.0 = phi float [ %mul, %if.then ], [ %add, %entry ]115 ret float %a.0116}117 118 119; Two adds separated by llvm.set.rounding should be preserved when rounding is120; dynamic (as they may give different results) or when we have strict exceptions121; (the llvm.set.rounding is irrelevant, but both could trap).122 123define float @set_rounding(float %x, float %y) {124; CHECK-LABEL: set_rounding:125; CHECK: // %bb.0: // %entry126; CHECK-NEXT: mrs x8, FPCR127; CHECK-NEXT: fadd s0, s0, s1128; CHECK-NEXT: orr x8, x8, #0xc00000129; CHECK-NEXT: msr FPCR, x8130; CHECK-NEXT: mrs x8, FPCR131; CHECK-NEXT: and x8, x8, #0xffffffffff3fffff132; CHECK-NEXT: msr FPCR, x8133; CHECK-NEXT: fsub s0, s0, s0134; CHECK-NEXT: ret135entry:136 %add1 = fadd float %x, %y137 call void @llvm.set.rounding(i32 0)138 %add2 = fadd float %x, %y139 call void @llvm.set.rounding(i32 1)140 %sub = fsub float %add1, %add2141 ret float %sub142}143 144define float @set_rounding_fpexcept_strict(float %x, float %y) #0 {145; CHECK-LABEL: set_rounding_fpexcept_strict:146; CHECK: // %bb.0: // %entry147; CHECK-NEXT: fadd s2, s0, s1148; CHECK-NEXT: mrs x8, FPCR149; CHECK-NEXT: orr x8, x8, #0xc00000150; CHECK-NEXT: msr FPCR, x8151; CHECK-NEXT: fadd s0, s0, s1152; CHECK-NEXT: mrs x8, FPCR153; CHECK-NEXT: and x8, x8, #0xffffffffff3fffff154; CHECK-NEXT: msr FPCR, x8155; CHECK-NEXT: fsub s0, s2, s0156; CHECK-NEXT: ret157entry:158 %add1 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") #0159 call void @llvm.set.rounding(i32 0) #0160 %add2 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") #0161 call void @llvm.set.rounding(i32 1) #0162 %sub = call float @llvm.experimental.constrained.fsub.f32(float %add1, float %add2, metadata !"round.tonearest", metadata !"fpexcept.strict") #0163 ret float %sub164}165 166define float @set_rounding_round_dynamic(float %x, float %y) #0 {167; CHECK-LABEL: set_rounding_round_dynamic:168; CHECK: // %bb.0: // %entry169; CHECK-NEXT: mrs x8, FPCR170; CHECK-NEXT: fadd s2, s0, s1171; CHECK-NEXT: orr x8, x8, #0xc00000172; CHECK-NEXT: msr FPCR, x8173; CHECK-NEXT: fadd s0, s0, s1174; CHECK-NEXT: mrs x8, FPCR175; CHECK-NEXT: and x8, x8, #0xffffffffff3fffff176; CHECK-NEXT: msr FPCR, x8177; CHECK-NEXT: fsub s0, s2, s0178; CHECK-NEXT: ret179entry:180 %add1 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0181 call void @llvm.set.rounding(i32 0) #0182 %add2 = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0183 call void @llvm.set.rounding(i32 1) #0184 %sub = call float @llvm.experimental.constrained.fsub.f32(float %add1, float %add2, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0185 ret float %sub186}187 188declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)189declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)190declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata)191declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata)192declare i32 @llvm.get.rounding()193declare void @llvm.set.rounding(i32)194 195attributes #0 = { strictfp }196;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:197; CHECK-GI: {{.*}}198; CHECK-SD: {{.*}}199