[CodeGen] use saturating FP casts when compiling with "no-strict-float-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
This commit is contained in:
Sanjay Patel
2021-12-16 08:37:44 -05:00
parent 9a35844990
commit 8c7f2a4f87
2 changed files with 23 additions and 4 deletions

View File

@@ -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");
}

View File

@@ -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;
}
int main() {
double d = 1e20;
return (int)d != 1e20 && (unsigned)d != 1e20;
}