Skip to content

Commit 78e1634

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.
1 parent db9057e commit 78e1634

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,6 +1940,31 @@ Instruction *InstCombinerImpl::visitFPExt(CastInst &FPExt) {
19401940
return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty);
19411941
}
19421942

1943+
// fpext (fptrunc(x)) -> x, if the fast math flags allow it
1944+
if (auto *Trunc = dyn_cast<FPTruncInst>(Src)) {
1945+
// Whether this transformation is possible depends on the fast math flags of
1946+
// both the fpext and fptrunc.
1947+
FastMathFlags SrcFlags = Trunc->getFastMathFlags();
1948+
FastMathFlags DstFlags = FPExt.getFastMathFlags();
1949+
// Trunc can introduce inf and change the encoding of a nan, so the
1950+
// destination must have the nnan and ninf flags to indicate that we don't
1951+
// need to care about that. We are also removing a rounding step, and that
1952+
// requires both the source and destination to allow contraction.
1953+
if (DstFlags.noNaNs() && DstFlags.noInfs() && SrcFlags.allowContract() &&
1954+
DstFlags.allowContract()) {
1955+
Value *TruncSrc = Trunc->getOperand(0);
1956+
// We do need a single cast if the source and destination types don't
1957+
// match.
1958+
if (TruncSrc->getType() != Ty) {
1959+
Instruction *Ret = CastInst::CreateFPCast(TruncSrc, Ty);
1960+
Ret->copyFastMathFlags(&FPExt);
1961+
return Ret;
1962+
} else {
1963+
return replaceInstUsesWith(FPExt, TruncSrc);
1964+
}
1965+
}
1966+
}
1967+
19431968
return commonCastTransforms(FPExt);
19441969
}
19451970

llvm/test/Transforms/InstCombine/fpextend.ll

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,76 @@ 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 double [[X:%.*]], [[Y:%.*]]
470+
; CHECK-NEXT: [[ADD2:%.*]] = fadd double [[ADD1]], [[Z:%.*]]
471+
; CHECK-NEXT: ret double [[ADD2]]
472+
;
473+
%add1 = fadd double %x, %y
474+
%trunc = fptrunc contract double %add1 to float
475+
%ext = fpext nnan ninf contract float %trunc to double
476+
%add2 = fadd 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 double [[X:%.*]], [[Y:%.*]]
483+
; CHECK-NEXT: [[EXT:%.*]] = fptrunc nnan ninf contract double [[ADD1]] to float
484+
; CHECK-NEXT: [[ADD2:%.*]] = fadd float [[Z:%.*]], [[EXT]]
485+
; CHECK-NEXT: ret float [[ADD2]]
486+
;
487+
%add1 = fadd double %x, %y
488+
%trunc = fptrunc contract double %add1 to half
489+
%ext = fpext nnan ninf contract half %trunc to float
490+
%add2 = fadd 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 float [[X:%.*]], [[Y:%.*]]
497+
; CHECK-NEXT: [[EXT:%.*]] = fpext nnan ninf contract float [[ADD1]] to double
498+
; CHECK-NEXT: [[ADD2:%.*]] = fadd double [[Z:%.*]], [[EXT]]
499+
; CHECK-NEXT: ret double [[ADD2]]
500+
;
501+
%add1 = fadd float %x, %y
502+
%trunc = fptrunc contract float %add1 to half
503+
%ext = fpext nnan ninf contract half %trunc to double
504+
%add2 = fadd 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 double [[X:%.*]], [[Y:%.*]]
511+
; CHECK-NEXT: [[ADD2:%.*]] = fadd double [[ADD1]], [[A:%.*]]
512+
; CHECK-NEXT: [[ADD3:%.*]] = fadd double [[ADD1]], [[B:%.*]]
513+
; CHECK-NEXT: [[MUL:%.*]] = fmul double [[ADD2]], [[ADD3]]
514+
; CHECK-NEXT: ret double [[MUL]]
515+
;
516+
%add1 = fadd double %x, %y
517+
%trunc = fptrunc contract double %add1 to float
518+
%ext = fpext nnan ninf contract float %trunc to double
519+
%add2 = fadd double %ext, %a
520+
%add3 = fadd double %ext, %b
521+
%mul = fmul double %add2, %add3
522+
ret double %mul
523+
}

0 commit comments

Comments
 (0)