Skip to content

Commit 211bcf6

Browse files
authored
[AMDGPU] Implement IR variant of isFMAFasterThanFMulAndFAdd (#121465)
1 parent 2ea34cd commit 211bcf6

File tree

3 files changed

+132
-35
lines changed

3 files changed

+132
-35
lines changed

llvm/lib/Target/AMDGPU/SIISelLowering.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5732,6 +5732,35 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
57325732
return false;
57335733
}
57345734

5735+
// Refer to comments added to the MIR variant of isFMAFasterThanFMulAndFAdd for
5736+
// specific details.
5737+
bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const Function &F,
5738+
Type *Ty) const {
5739+
switch (Ty->getScalarSizeInBits()) {
5740+
case 16: {
5741+
SIModeRegisterDefaults Mode = SIModeRegisterDefaults(F, *Subtarget);
5742+
return Subtarget->has16BitInsts() &&
5743+
Mode.FP64FP16Denormals != DenormalMode::getPreserveSign();
5744+
}
5745+
case 32: {
5746+
if (!Subtarget->hasMadMacF32Insts())
5747+
return Subtarget->hasFastFMAF32();
5748+
5749+
SIModeRegisterDefaults Mode = SIModeRegisterDefaults(F, *Subtarget);
5750+
if (Mode.FP32Denormals != DenormalMode::getPreserveSign())
5751+
return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts();
5752+
5753+
return Subtarget->hasFastFMAF32() && Subtarget->hasDLInsts();
5754+
}
5755+
case 64:
5756+
return true;
5757+
default:
5758+
break;
5759+
}
5760+
5761+
return false;
5762+
}
5763+
57355764
bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const {
57365765
if (!Ty.isScalar())
57375766
return false;
@@ -16992,6 +17021,33 @@ bool SITargetLowering::checkForPhysRegDependency(
1699217021
return false;
1699317022
}
1699417023

17024+
/// Check if it is profitable to hoist instruction in then/else to if.
17025+
bool SITargetLowering::isProfitableToHoist(Instruction *I) const {
17026+
if (!I->hasOneUse())
17027+
return true;
17028+
17029+
Instruction *User = I->user_back();
17030+
// TODO: Add more patterns that are not profitable to hoist and
17031+
// handle modifiers such as fabs and fneg
17032+
switch (I->getOpcode()) {
17033+
case Instruction::FMul: {
17034+
if (User->getOpcode() != Instruction::FSub &&
17035+
User->getOpcode() != Instruction::FAdd)
17036+
return true;
17037+
17038+
const TargetOptions &Options = getTargetMachine().Options;
17039+
17040+
return ((!I->hasAllowContract() || !User->hasAllowContract()) &&
17041+
Options.AllowFPOpFusion != FPOpFusion::Fast &&
17042+
!Options.UnsafeFPMath) ||
17043+
!isFMAFasterThanFMulAndFAdd(*I->getFunction(), User->getType());
17044+
}
17045+
default:
17046+
return true;
17047+
}
17048+
return true;
17049+
}
17050+
1699517051
void SITargetLowering::emitExpandAtomicAddrSpacePredicate(
1699617052
Instruction *AI) const {
1699717053
// Given: atomicrmw fadd ptr %addr, float %val ordering

llvm/lib/Target/AMDGPU/SIISelLowering.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ class SITargetLowering final : public AMDGPUTargetLowering {
459459
EVT VT) const override;
460460
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
461461
const LLT Ty) const override;
462+
bool isFMAFasterThanFMulAndFAdd(const Function &F, Type *Ty) const override;
462463
bool isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const override;
463464
bool isFMADLegal(const MachineInstr &MI, const LLT Ty) const override;
464465

@@ -538,6 +539,8 @@ class SITargetLowering final : public AMDGPUTargetLowering {
538539
const TargetInstrInfo *TII, unsigned &PhysReg,
539540
int &Cost) const override;
540541

542+
bool isProfitableToHoist(Instruction *I) const override;
543+
541544
bool isKnownNeverNaNForTargetNode(SDValue Op,
542545
const SelectionDAG &DAG,
543546
bool SNaN = false,

llvm/test/CodeGen/AMDGPU/prevent-fmul-hoist-ir.ll

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ define double @is_profitable_f64_contract(ptr dereferenceable(8) %ptr_x, ptr der
1111
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
1212
; GFX-NEXT: [[X:%.*]] = load double, ptr [[PTR_X]], align 8
1313
; GFX-NEXT: [[A_1:%.*]] = load double, ptr [[PTR_A]], align 8
14-
; GFX-NEXT: [[MUL:%.*]] = fmul contract double [[X]], [[A_1]]
1514
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
1615
; GFX: [[COMMON_RET:.*]]:
1716
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi double [ [[ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
1817
; GFX-NEXT: ret double [[COMMON_RET_OP]]
1918
; GFX: [[IF_THEN]]:
19+
; GFX-NEXT: [[MUL:%.*]] = fmul contract double [[X]], [[A_1]]
2020
; GFX-NEXT: [[ADD]] = fadd contract double 1.000000e+00, [[MUL]]
2121
; GFX-NEXT: br label %[[COMMON_RET]]
2222
; GFX: [[IF_ELSE]]:
23-
; GFX-NEXT: [[SUB]] = fsub contract double [[MUL]], [[Y]]
23+
; GFX-NEXT: [[MUL1:%.*]] = fmul contract double [[X]], [[A_1]]
24+
; GFX-NEXT: [[SUB]] = fsub contract double [[MUL1]], [[Y]]
2425
; GFX-NEXT: br label %[[COMMON_RET]]
2526
;
2627
entry:
@@ -93,16 +94,17 @@ define float @is_profitable_f32(ptr dereferenceable(8) %ptr_x, ptr dereferenceab
9394
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq float [[Y]], 0.000000e+00
9495
; GFX-NEXT: [[X:%.*]] = load float, ptr [[PTR_X]], align 8
9596
; GFX-NEXT: [[A_1:%.*]] = load float, ptr [[PTR_A]], align 8
96-
; GFX-NEXT: [[MUL:%.*]] = fmul contract float [[X]], [[A_1]]
9797
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
9898
; GFX: [[COMMON_RET:.*]]:
99-
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[MUL]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
99+
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[MUL:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
100100
; GFX-NEXT: ret float [[COMMON_RET_OP]]
101101
; GFX: [[IF_THEN]]:
102+
; GFX-NEXT: [[MUL]] = fmul contract float [[X]], [[A_1]]
102103
; GFX-NEXT: [[ADD:%.*]] = fadd contract float 1.000000e+00, [[MUL]]
103104
; GFX-NEXT: br label %[[COMMON_RET]]
104105
; GFX: [[IF_ELSE]]:
105-
; GFX-NEXT: [[SUB]] = fsub contract float [[MUL]], [[Y]]
106+
; GFX-NEXT: [[MUL1:%.*]] = fmul contract float [[X]], [[A_1]]
107+
; GFX-NEXT: [[SUB]] = fsub contract float [[MUL1]], [[Y]]
106108
; GFX-NEXT: br label %[[COMMON_RET]]
107109
;
108110
entry:
@@ -111,7 +113,6 @@ entry:
111113
%x = load float, ptr %ptr_x, align 8
112114
br i1 %cmp, label %if.then, label %if.else
113115

114-
115116
if.then: ; preds = %entry
116117
%a_1 = load float, ptr %ptr_a, align 8
117118
%mul = fmul contract float %x, %a_1
@@ -172,16 +173,17 @@ define half @is_profitable_f16_ieee(ptr dereferenceable(8) %ptr_x, ptr dereferen
172173
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq half [[Y]], 0xH0000
173174
; GFX-NEXT: [[X:%.*]] = load half, ptr [[PTR_X]], align 8
174175
; GFX-NEXT: [[A_1:%.*]] = load half, ptr [[PTR_A]], align 8
175-
; GFX-NEXT: [[MUL:%.*]] = fmul contract half [[X]], [[A_1]]
176176
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
177177
; GFX: [[COMMON_RET:.*]]:
178-
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi half [ [[MUL]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
178+
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi half [ [[MUL:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
179179
; GFX-NEXT: ret half [[COMMON_RET_OP]]
180180
; GFX: [[IF_THEN]]:
181+
; GFX-NEXT: [[MUL]] = fmul contract half [[X]], [[A_1]]
181182
; GFX-NEXT: [[ADD:%.*]] = fadd contract half [[Y]], [[MUL]]
182183
; GFX-NEXT: br label %[[COMMON_RET]]
183184
; GFX: [[IF_ELSE]]:
184-
; GFX-NEXT: [[SUB]] = fsub contract half [[MUL]], [[Y]]
185+
; GFX-NEXT: [[MUL1:%.*]] = fmul contract half [[X]], [[A_1]]
186+
; GFX-NEXT: [[SUB]] = fsub contract half [[MUL1]], [[Y]]
185187
; GFX-NEXT: br label %[[COMMON_RET]]
186188
;
187189
entry:
@@ -250,16 +252,17 @@ define bfloat @is_profitable_bfloat_ieee(ptr dereferenceable(8) %ptr_x, ptr dere
250252
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq bfloat [[Y]], 0xR0000
251253
; GFX-NEXT: [[X:%.*]] = load bfloat, ptr [[PTR_X]], align 8
252254
; GFX-NEXT: [[A_1:%.*]] = load bfloat, ptr [[PTR_A]], align 8
253-
; GFX-NEXT: [[MUL:%.*]] = fmul contract bfloat [[X]], [[A_1]]
254255
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
255256
; GFX: [[COMMON_RET:.*]]:
256-
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi bfloat [ [[MUL]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
257+
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi bfloat [ [[MUL:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
257258
; GFX-NEXT: ret bfloat [[COMMON_RET_OP]]
258259
; GFX: [[IF_THEN]]:
260+
; GFX-NEXT: [[MUL]] = fmul contract bfloat [[X]], [[A_1]]
259261
; GFX-NEXT: [[ADD:%.*]] = fadd contract bfloat 0xR3F80, [[MUL]]
260262
; GFX-NEXT: br label %[[COMMON_RET]]
261263
; GFX: [[IF_ELSE]]:
262-
; GFX-NEXT: [[SUB]] = fsub contract bfloat [[MUL]], [[Y]]
264+
; GFX-NEXT: [[MUL1:%.*]] = fmul contract bfloat [[X]], [[A_1]]
265+
; GFX-NEXT: [[SUB]] = fsub contract bfloat [[MUL1]], [[Y]]
263266
; GFX-NEXT: br label %[[COMMON_RET]]
264267
;
265268
entry:
@@ -330,16 +333,17 @@ define <8 x half> @is_profitable_vector(ptr dereferenceable(8) %ptr_x, ptr deref
330333
; GFX-NEXT: [[V1:%.*]] = load <8 x half>, ptr addrspace(3) @v1_ptr, align 16
331334
; GFX-NEXT: [[V2:%.*]] = load <8 x half>, ptr addrspace(3) @v2_ptr, align 16
332335
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
333-
; GFX-NEXT: [[MUL:%.*]] = fmul contract <8 x half> [[V1]], [[X]]
334336
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
335337
; GFX: [[COMMON_RET:.*]]:
336338
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi <8 x half> [ [[ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
337339
; GFX-NEXT: ret <8 x half> [[COMMON_RET_OP]]
338340
; GFX: [[IF_THEN]]:
341+
; GFX-NEXT: [[MUL:%.*]] = fmul contract <8 x half> [[V1]], [[X]]
339342
; GFX-NEXT: [[ADD]] = fadd contract <8 x half> [[V2]], [[MUL]]
340343
; GFX-NEXT: br label %[[COMMON_RET]]
341344
; GFX: [[IF_ELSE]]:
342-
; GFX-NEXT: [[SUB]] = fsub contract <8 x half> [[MUL]], [[V2]]
345+
; GFX-NEXT: [[MUL1:%.*]] = fmul contract <8 x half> [[V1]], [[X]]
346+
; GFX-NEXT: [[SUB]] = fsub contract <8 x half> [[MUL1]], [[V2]]
343347
; GFX-NEXT: br label %[[COMMON_RET]]
344348
;
345349
entry:
@@ -362,23 +366,61 @@ if.else: ; preds = %entry
362366
}
363367

364368
define double @is_profitable_f64_nocontract(ptr dereferenceable(8) %ptr_x, ptr dereferenceable(8) %ptr_y, ptr dereferenceable(8) %ptr_a) #0 {
365-
; GFX-LABEL: define double @is_profitable_f64_nocontract(
366-
; GFX-SAME: ptr dereferenceable(8) [[PTR_X:%.*]], ptr dereferenceable(8) [[PTR_Y:%.*]], ptr dereferenceable(8) [[PTR_A:%.*]]) #[[ATTR0]] {
367-
; GFX-NEXT: [[Y:%.*]] = load double, ptr [[PTR_Y]], align 8
368-
; GFX-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
369-
; GFX-NEXT: [[X:%.*]] = load double, ptr [[PTR_X]], align 8
370-
; GFX-NEXT: [[A_1:%.*]] = load double, ptr [[PTR_A]], align 8
371-
; GFX-NEXT: [[MUL:%.*]] = fmul double [[X]], [[A_1]]
372-
; GFX-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
373-
; GFX: [[COMMON_RET:.*]]:
374-
; GFX-NEXT: [[COMMON_RET_OP:%.*]] = phi double [ [[PTR_ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
375-
; GFX-NEXT: ret double [[COMMON_RET_OP]]
376-
; GFX: [[IF_THEN]]:
377-
; GFX-NEXT: [[PTR_ADD]] = fadd double 1.000000e+00, [[MUL]]
378-
; GFX-NEXT: br label %[[COMMON_RET]]
379-
; GFX: [[IF_ELSE]]:
380-
; GFX-NEXT: [[SUB]] = fsub double [[MUL]], [[Y]]
381-
; GFX-NEXT: br label %[[COMMON_RET]]
369+
; FP-CONTRACT-FAST-LABEL: define double @is_profitable_f64_nocontract(
370+
; FP-CONTRACT-FAST-SAME: ptr dereferenceable(8) [[PTR_X:%.*]], ptr dereferenceable(8) [[PTR_Y:%.*]], ptr dereferenceable(8) [[PTR_A:%.*]]) #[[ATTR0]] {
371+
; FP-CONTRACT-FAST-NEXT: [[Y:%.*]] = load double, ptr [[PTR_Y]], align 8
372+
; FP-CONTRACT-FAST-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
373+
; FP-CONTRACT-FAST-NEXT: [[X:%.*]] = load double, ptr [[PTR_X]], align 8
374+
; FP-CONTRACT-FAST-NEXT: [[A_1:%.*]] = load double, ptr [[PTR_A]], align 8
375+
; FP-CONTRACT-FAST-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
376+
; FP-CONTRACT-FAST: [[COMMON_RET:.*]]:
377+
; FP-CONTRACT-FAST-NEXT: [[COMMON_RET_OP:%.*]] = phi double [ [[PTR_ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
378+
; FP-CONTRACT-FAST-NEXT: ret double [[COMMON_RET_OP]]
379+
; FP-CONTRACT-FAST: [[IF_THEN]]:
380+
; FP-CONTRACT-FAST-NEXT: [[MUL:%.*]] = fmul double [[X]], [[A_1]]
381+
; FP-CONTRACT-FAST-NEXT: [[PTR_ADD]] = fadd double 1.000000e+00, [[MUL]]
382+
; FP-CONTRACT-FAST-NEXT: br label %[[COMMON_RET]]
383+
; FP-CONTRACT-FAST: [[IF_ELSE]]:
384+
; FP-CONTRACT-FAST-NEXT: [[MUL1:%.*]] = fmul double [[X]], [[A_1]]
385+
; FP-CONTRACT-FAST-NEXT: [[SUB]] = fsub double [[MUL1]], [[Y]]
386+
; FP-CONTRACT-FAST-NEXT: br label %[[COMMON_RET]]
387+
;
388+
; UNSAFE-FP-MATH-LABEL: define double @is_profitable_f64_nocontract(
389+
; UNSAFE-FP-MATH-SAME: ptr dereferenceable(8) [[PTR_X:%.*]], ptr dereferenceable(8) [[PTR_Y:%.*]], ptr dereferenceable(8) [[PTR_A:%.*]]) #[[ATTR0]] {
390+
; UNSAFE-FP-MATH-NEXT: [[Y:%.*]] = load double, ptr [[PTR_Y]], align 8
391+
; UNSAFE-FP-MATH-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
392+
; UNSAFE-FP-MATH-NEXT: [[X:%.*]] = load double, ptr [[PTR_X]], align 8
393+
; UNSAFE-FP-MATH-NEXT: [[A_1:%.*]] = load double, ptr [[PTR_A]], align 8
394+
; UNSAFE-FP-MATH-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
395+
; UNSAFE-FP-MATH: [[COMMON_RET:.*]]:
396+
; UNSAFE-FP-MATH-NEXT: [[COMMON_RET_OP:%.*]] = phi double [ [[PTR_ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
397+
; UNSAFE-FP-MATH-NEXT: ret double [[COMMON_RET_OP]]
398+
; UNSAFE-FP-MATH: [[IF_THEN]]:
399+
; UNSAFE-FP-MATH-NEXT: [[MUL:%.*]] = fmul double [[X]], [[A_1]]
400+
; UNSAFE-FP-MATH-NEXT: [[PTR_ADD]] = fadd double 1.000000e+00, [[MUL]]
401+
; UNSAFE-FP-MATH-NEXT: br label %[[COMMON_RET]]
402+
; UNSAFE-FP-MATH: [[IF_ELSE]]:
403+
; UNSAFE-FP-MATH-NEXT: [[MUL1:%.*]] = fmul double [[X]], [[A_1]]
404+
; UNSAFE-FP-MATH-NEXT: [[SUB]] = fsub double [[MUL1]], [[Y]]
405+
; UNSAFE-FP-MATH-NEXT: br label %[[COMMON_RET]]
406+
;
407+
; NO-UNSAFE-FP-MATH-LABEL: define double @is_profitable_f64_nocontract(
408+
; NO-UNSAFE-FP-MATH-SAME: ptr dereferenceable(8) [[PTR_X:%.*]], ptr dereferenceable(8) [[PTR_Y:%.*]], ptr dereferenceable(8) [[PTR_A:%.*]]) #[[ATTR0]] {
409+
; NO-UNSAFE-FP-MATH-NEXT: [[Y:%.*]] = load double, ptr [[PTR_Y]], align 8
410+
; NO-UNSAFE-FP-MATH-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y]], 0.000000e+00
411+
; NO-UNSAFE-FP-MATH-NEXT: [[X:%.*]] = load double, ptr [[PTR_X]], align 8
412+
; NO-UNSAFE-FP-MATH-NEXT: [[A_1:%.*]] = load double, ptr [[PTR_A]], align 8
413+
; NO-UNSAFE-FP-MATH-NEXT: [[MUL:%.*]] = fmul double [[X]], [[A_1]]
414+
; NO-UNSAFE-FP-MATH-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
415+
; NO-UNSAFE-FP-MATH: [[COMMON_RET:.*]]:
416+
; NO-UNSAFE-FP-MATH-NEXT: [[COMMON_RET_OP:%.*]] = phi double [ [[PTR_ADD:%.*]], %[[IF_THEN]] ], [ [[SUB:%.*]], %[[IF_ELSE]] ]
417+
; NO-UNSAFE-FP-MATH-NEXT: ret double [[COMMON_RET_OP]]
418+
; NO-UNSAFE-FP-MATH: [[IF_THEN]]:
419+
; NO-UNSAFE-FP-MATH-NEXT: [[PTR_ADD]] = fadd double 1.000000e+00, [[MUL]]
420+
; NO-UNSAFE-FP-MATH-NEXT: br label %[[COMMON_RET]]
421+
; NO-UNSAFE-FP-MATH: [[IF_ELSE]]:
422+
; NO-UNSAFE-FP-MATH-NEXT: [[SUB]] = fsub double [[MUL]], [[Y]]
423+
; NO-UNSAFE-FP-MATH-NEXT: br label %[[COMMON_RET]]
382424
;
383425
%y = load double, ptr %ptr_y, align 8
384426
%cmp = fcmp oeq double %y, 0.000000e+00
@@ -400,7 +442,3 @@ if.else: ; preds = %entry
400442

401443
attributes #0 = { nounwind "denormal-fp-math"="preserve-sign,preserve-sign" }
402444
attributes #1 = { nounwind "denormal-fp-math"="ieee,ieee" }
403-
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
404-
; FP-CONTRACT-FAST: {{.*}}
405-
; NO-UNSAFE-FP-MATH: {{.*}}
406-
; UNSAFE-FP-MATH: {{.*}}

0 commit comments

Comments
 (0)