Skip to content

Commit 297b144

Browse files
[InstCombine] Eliminate fptrunc/fpext if fast math flags allow it
When expressions of a floating-point type are evaluated at a higher precision (e.g. _Float16 being evaluated as float) this results in a fptrunc then fpext between each operation. With the appropriate fast math flags (nnan ninf contract) we can eliminate these cast instructions. As cast instructions don't have fast math flags it's the source and destination of the casts whose flags are checked.
1 parent ac1869a commit 297b144

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,32 @@ Instruction *InstCombinerImpl::visitFPExt(CastInst &FPExt) {
19491949
return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty);
19501950
}
19511951

1952+
// fpext (fptrunc(x)) -> x, if the fast math flags allow it
1953+
Instruction *SrcInstr;
1954+
if (match(Src, m_FPTrunc(m_Instruction(SrcInstr)))) {
1955+
// Whether this transformation is possible depends both on the flags of the
1956+
// value that is truncated, and the flags on the instructions that use the
1957+
// fpext.
1958+
FastMathFlags SrcFlags = SrcInstr->getFastMathFlags();
1959+
FastMathFlags DstFlags = FastMathFlags::getFast();
1960+
for (User *U : FPExt.users())
1961+
if (auto *UInstr = dyn_cast<Instruction>(U))
1962+
DstFlags &= UInstr->getFastMathFlags();
1963+
// Trunc can introduce inf and change the encoding of a nan, so the
1964+
// destination must have the nnan and ninf flags to indicate that we don't
1965+
// need to care about that. We are also removing a rounding step, and that
1966+
// requires both the source and destination to allow contraction.
1967+
if (DstFlags.noNaNs() && DstFlags.noInfs() && SrcFlags.allowContract() &&
1968+
DstFlags.allowContract()) {
1969+
// We do need a single cast if the source and destination types don't
1970+
// match.
1971+
if (SrcInstr->getType() != Ty)
1972+
return CastInst::CreateFPCast(SrcInstr, Ty);
1973+
else
1974+
return replaceInstUsesWith(FPExt, SrcInstr);
1975+
}
1976+
}
1977+
19521978
return commonCastTransforms(FPExt);
19531979
}
19541980

llvm/test/Transforms/InstCombine/fpextend.ll

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,95 @@ define bfloat @bf16_frem(bfloat %x) {
448448
%t3 = fptrunc float %t2 to bfloat
449449
ret bfloat %t3
450450
}
451+
452+
define double @fptrunc_fpextend_nofast(double %x, double %y, double %z) {
453+
; CHECK-LABEL: @fptrunc_fpextend_nofast(
454+
; CHECK-NEXT: [[ADD1:%.*]] = fadd double [[X:%.*]], [[Y:%.*]]
455+
; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc double [[ADD1]] to float
456+
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[TRUNC]] to double
457+
; CHECK-NEXT: [[ADD2:%.*]] = fadd double [[Z:%.*]], [[EXT]]
458+
; CHECK-NEXT: ret double [[ADD2]]
459+
;
460+
%add1 = fadd double %x, %y
461+
%trunc = fptrunc double %add1 to float
462+
%ext = fpext float %trunc to double
463+
%add2 = fadd double %ext, %z
464+
ret double %add2
465+
}
466+
467+
define double @fptrunc_fpextend_fast(double %x, double %y, double %z) {
468+
; CHECK-LABEL: @fptrunc_fpextend_fast(
469+
; CHECK-NEXT: [[ADD1:%.*]] = fadd contract double [[X:%.*]], [[Y:%.*]]
470+
; CHECK-NEXT: [[ADD2:%.*]] = fadd nnan ninf contract double [[ADD1]], [[Z:%.*]]
471+
; CHECK-NEXT: ret double [[ADD2]]
472+
;
473+
%add1 = fadd contract double %x, %y
474+
%trunc = fptrunc double %add1 to float
475+
%ext = fpext float %trunc to double
476+
%add2 = fadd nnan ninf contract double %ext, %z
477+
ret double %add2
478+
}
479+
480+
define float @fptrunc_fpextend_result_smaller(double %x, double %y, float %z) {
481+
; CHECK-LABEL: @fptrunc_fpextend_result_smaller(
482+
; CHECK-NEXT: [[ADD1:%.*]] = fadd contract double [[X:%.*]], [[Y:%.*]]
483+
; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ADD1]] to float
484+
; CHECK-NEXT: [[ADD2:%.*]] = fadd nnan ninf contract float [[Z:%.*]], [[EXT]]
485+
; CHECK-NEXT: ret float [[ADD2]]
486+
;
487+
%add1 = fadd contract double %x, %y
488+
%trunc = fptrunc double %add1 to half
489+
%ext = fpext half %trunc to float
490+
%add2 = fadd nnan ninf contract float %ext, %z
491+
ret float %add2
492+
}
493+
494+
define double @fptrunc_fpextend_result_larger(float %x, float %y, double %z) {
495+
; CHECK-LABEL: @fptrunc_fpextend_result_larger(
496+
; CHECK-NEXT: [[ADD1:%.*]] = fadd contract float [[X:%.*]], [[Y:%.*]]
497+
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[ADD1]] to double
498+
; CHECK-NEXT: [[ADD2:%.*]] = fadd nnan ninf contract double [[Z:%.*]], [[EXT]]
499+
; CHECK-NEXT: ret double [[ADD2]]
500+
;
501+
%add1 = fadd contract float %x, %y
502+
%trunc = fptrunc float %add1 to half
503+
%ext = fpext half %trunc to double
504+
%add2 = fadd nnan ninf contract double %ext, %z
505+
ret double %add2
506+
}
507+
508+
define double @fptrunc_fpextend_multiple_use(double %x, double %y, double %a, double %b) {
509+
; CHECK-LABEL: @fptrunc_fpextend_multiple_use(
510+
; CHECK-NEXT: [[ADD1:%.*]] = fadd contract double [[X:%.*]], [[Y:%.*]]
511+
; CHECK-NEXT: [[ADD2:%.*]] = fadd nnan ninf contract double [[ADD1]], [[A:%.*]]
512+
; CHECK-NEXT: [[ADD3:%.*]] = fadd nnan ninf contract double [[ADD1]], [[B:%.*]]
513+
; CHECK-NEXT: [[MUL:%.*]] = fmul double [[ADD2]], [[ADD3]]
514+
; CHECK-NEXT: ret double [[MUL]]
515+
;
516+
%add1 = fadd contract double %x, %y
517+
%trunc = fptrunc double %add1 to float
518+
%ext = fpext float %trunc to double
519+
%add2 = fadd nnan ninf contract double %ext, %a
520+
%add3 = fadd nnan ninf contract double %ext, %b
521+
%mul = fmul double %add2, %add3
522+
ret double %mul
523+
}
524+
525+
define double @fptrunc_fpextend_multiple_use_flag_mismatch(double %x, double %y, double %a, double %b) {
526+
; CHECK-LABEL: @fptrunc_fpextend_multiple_use_flag_mismatch(
527+
; CHECK-NEXT: [[ADD1:%.*]] = fadd contract double [[X:%.*]], [[Y:%.*]]
528+
; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc double [[ADD1]] to float
529+
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[TRUNC]] to double
530+
; CHECK-NEXT: [[ADD2:%.*]] = fadd nnan ninf contract double [[A:%.*]], [[EXT]]
531+
; CHECK-NEXT: [[ADD3:%.*]] = fadd nnan ninf double [[B:%.*]], [[EXT]]
532+
; CHECK-NEXT: [[MUL:%.*]] = fmul double [[ADD2]], [[ADD3]]
533+
; CHECK-NEXT: ret double [[MUL]]
534+
;
535+
%add1 = fadd contract double %x, %y
536+
%trunc = fptrunc double %add1 to float
537+
%ext = fpext float %trunc to double
538+
%add2 = fadd nnan ninf contract double %ext, %a
539+
%add3 = fadd nnan ninf double %ext, %b
540+
%mul = fmul double %add2, %add3
541+
ret double %mul
542+
}

0 commit comments

Comments
 (0)