Skip to content

Commit

Permalink
[CodeGen] use saturating FP casts when compiling with "no-strict-floa…
Browse files Browse the repository at this point in the history
…t-cast-overflow"

We got an unintended consequence of the optimizer getting smarter when
compiling in a non-standard mode, and there's no good way to inhibit
those optimizations at a later stage. The test is based on an example
linked from D92270.

We allow the "no-strict-float-cast-overflow" exception to normal C
cast rules to preserve legacy code that does not expect overflowing
casts from FP to int to produce UB. See D46236 for details.

Differential Revision: https://reviews.llvm.org/D115804
  • Loading branch information
rotateright committed Dec 16, 2021
1 parent 9a35844 commit 8c7f2a4
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 3 deletions.
13 changes: 12 additions & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Expand Up @@ -1240,7 +1240,18 @@ Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType,

if (isa<llvm::IntegerType>(DstElementTy)) {
assert(SrcElementTy->isFloatingPointTy() && "Unknown real conversion");
if (DstElementType->isSignedIntegerOrEnumerationType())
bool IsSigned = DstElementType->isSignedIntegerOrEnumerationType();

// If we can't recognize overflow as undefined behavior, assume that
// overflow saturates. This protects against normal optimizations if we are
// compiling with non-standard FP semantics.
if (!CGF.CGM.getCodeGenOpts().StrictFloatCastOverflow) {
llvm::Intrinsic::ID IID =
IsSigned ? llvm::Intrinsic::fptosi_sat : llvm::Intrinsic::fptoui_sat;
return Builder.CreateCall(CGF.CGM.getIntrinsic(IID, {DstTy, SrcTy}), Src);
}

if (IsSigned)
return Builder.CreateFPToSI(Src, DstTy, "conv");
return Builder.CreateFPToUI(Src, DstTy, "conv");
}
Expand Down
12 changes: 10 additions & 2 deletions clang/test/CodeGen/no-junk-ftrunc.c
@@ -1,14 +1,22 @@
// RUN: %clang_cc1 -S -fno-strict-float-cast-overflow %s -emit-llvm -o - | FileCheck %s --check-prefix=NOSTRICT

// When compiling with non-standard semantics, use intrinsics to inhibit the optimizer.

// NOSTRICT-LABEL: main
// NOSTRICT: call i32 @llvm.fptosi.sat.i32.f64
// NOSTRICT: call i32 @llvm.fptoui.sat.i32.f64
// NOSTRICT: attributes #0 = {{.*}}"strict-float-cast-overflow"="false"{{.*}}

// The workaround attribute is not applied by default.

// RUN: %clang_cc1 -S %s -emit-llvm -o - | FileCheck %s --check-prefix=STRICT
// STRICT-LABEL: main
// STRICT: = fptosi
// STRICT: = fptoui
// STRICT-NOT: strict-float-cast-overflow


int main() {
return 0;
double d = 1e20;
return (int)d != 1e20 && (unsigned)d != 1e20;
}

0 comments on commit 8c7f2a4

Please sign in to comment.