|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | #include "InstCombineInternal.h"
|
| 14 | +#include "llvm/ADT/APFloat.h" |
14 | 15 | #include "llvm/ADT/APSInt.h"
|
15 | 16 | #include "llvm/ADT/SetVector.h"
|
16 | 17 | #include "llvm/ADT/Statistic.h"
|
|
21 | 22 | #include "llvm/Analysis/Utils/Local.h"
|
22 | 23 | #include "llvm/Analysis/VectorUtils.h"
|
23 | 24 | #include "llvm/IR/ConstantRange.h"
|
| 25 | +#include "llvm/IR/Constants.h" |
24 | 26 | #include "llvm/IR/DataLayout.h"
|
25 | 27 | #include "llvm/IR/InstrTypes.h"
|
| 28 | +#include "llvm/IR/Instructions.h" |
26 | 29 | #include "llvm/IR/IntrinsicInst.h"
|
27 | 30 | #include "llvm/IR/PatternMatch.h"
|
28 | 31 | #include "llvm/Support/KnownBits.h"
|
@@ -8222,6 +8225,98 @@ static Instruction *foldFCmpReciprocalAndZero(FCmpInst &I, Instruction *LHSI,
|
8222 | 8225 | return new FCmpInst(Pred, LHSI->getOperand(1), RHSC, "", &I);
|
8223 | 8226 | }
|
8224 | 8227 |
|
| 8228 | +// Transform 'fptrunc(x) cmp C' to 'x cmp ext(C)' if possible. |
| 8229 | +// Patterns include: |
| 8230 | +// fptrunc(x) < C --> x < ext(C) |
| 8231 | +// fptrunc(x) <= C --> x <= ext(C) |
| 8232 | +// fptrunc(x) > C --> x > ext(C) |
| 8233 | +// fptrunc(x) >= C --> x >= ext(C) |
| 8234 | +// where 'ext(C)' is the extension of 'C' to the type of 'x' with a small bias |
| 8235 | +// due to precision loss. |
| 8236 | +static Instruction *foldFCmpFpTrunc(FCmpInst &I, const Instruction &FPTrunc, |
| 8237 | + const Constant &C) { |
| 8238 | + FCmpInst::Predicate Pred = I.getPredicate(); |
| 8239 | + bool RoundDown = false; |
| 8240 | + |
| 8241 | + if (Pred == FCmpInst::FCMP_OGE || Pred == FCmpInst::FCMP_UGE || |
| 8242 | + Pred == FCmpInst::FCMP_OLT || Pred == FCmpInst::FCMP_ULT) |
| 8243 | + RoundDown = true; |
| 8244 | + else if (Pred == FCmpInst::FCMP_OGT || Pred == FCmpInst::FCMP_UGT || |
| 8245 | + Pred == FCmpInst::FCMP_OLE || Pred == FCmpInst::FCMP_ULE) |
| 8246 | + RoundDown = false; |
| 8247 | + else |
| 8248 | + return nullptr; |
| 8249 | + |
| 8250 | + const APFloat *CValue; |
| 8251 | + if (!match(&C, m_APFloat(CValue))) |
| 8252 | + return nullptr; |
| 8253 | + |
| 8254 | + if (CValue->isNaN() || CValue->isInfinity()) |
| 8255 | + return nullptr; |
| 8256 | + |
| 8257 | + auto ConvertFltSema = [](const APFloat &Src, const fltSemantics &Sema) { |
| 8258 | + bool LosesInfo; |
| 8259 | + APFloat Dest = Src; |
| 8260 | + Dest.convert(Sema, APFloat::rmNearestTiesToEven, &LosesInfo); |
| 8261 | + return Dest; |
| 8262 | + }; |
| 8263 | + |
| 8264 | + auto NextValue = [](const APFloat &Value, bool RoundDown) { |
| 8265 | + APFloat NextValue = Value; |
| 8266 | + NextValue.next(RoundDown); |
| 8267 | + return NextValue; |
| 8268 | + }; |
| 8269 | + |
| 8270 | + APFloat NextCValue = NextValue(*CValue, RoundDown); |
| 8271 | + |
| 8272 | + Type *DestType = FPTrunc.getOperand(0)->getType(); |
| 8273 | + const fltSemantics &DestFltSema = |
| 8274 | + DestType->getScalarType()->getFltSemantics(); |
| 8275 | + |
| 8276 | + APFloat ExtCValue = ConvertFltSema(*CValue, DestFltSema); |
| 8277 | + APFloat ExtNextCValue = ConvertFltSema(NextCValue, DestFltSema); |
| 8278 | + |
| 8279 | + // When 'NextCValue' is infinity, use an imaged 'NextCValue' that equals |
| 8280 | + // 'CValue + bias' to avoid the infinity after conversion. The bias is |
| 8281 | + // estimated as 'CValue - PrevCValue', where 'PrevCValue' is the previous |
| 8282 | + // value of 'CValue'. |
| 8283 | + if (NextCValue.isInfinity()) { |
| 8284 | + APFloat PrevCValue = NextValue(*CValue, !RoundDown); |
| 8285 | + APFloat Bias = ConvertFltSema(*CValue - PrevCValue, DestFltSema); |
| 8286 | + |
| 8287 | + ExtNextCValue = ExtCValue + Bias; |
| 8288 | + } |
| 8289 | + |
| 8290 | + APFloat ExtMidValue = |
| 8291 | + scalbn(ExtCValue + ExtNextCValue, -1, APFloat::rmNearestTiesToEven); |
| 8292 | + |
| 8293 | + const fltSemantics &SrcFltSema = |
| 8294 | + C.getType()->getScalarType()->getFltSemantics(); |
| 8295 | + |
| 8296 | + // 'MidValue' might be rounded to 'NextCValue'. Correct it here. |
| 8297 | + APFloat MidValue = ConvertFltSema(ExtMidValue, SrcFltSema); |
| 8298 | + if (MidValue != *CValue) |
| 8299 | + ExtMidValue.next(!RoundDown); |
| 8300 | + |
| 8301 | + // Check whether 'ExtMidValue' is a valid result since the assumption on |
| 8302 | + // imaged 'NextCValue' might not hold for new float types. |
| 8303 | + // ppc_fp128 can't pass here when converting from max float because of |
| 8304 | + // APFloat implementation. |
| 8305 | + if (NextCValue.isInfinity()) { |
| 8306 | + // ExtMidValue --- narrowed ---> Finite |
| 8307 | + if (ConvertFltSema(ExtMidValue, SrcFltSema).isInfinity()) |
| 8308 | + return nullptr; |
| 8309 | + |
| 8310 | + // NextExtMidValue --- narrowed ---> Infinity |
| 8311 | + APFloat NextExtMidValue = NextValue(ExtMidValue, RoundDown); |
| 8312 | + if (ConvertFltSema(NextExtMidValue, SrcFltSema).isFinite()) |
| 8313 | + return nullptr; |
| 8314 | + } |
| 8315 | + |
| 8316 | + return new FCmpInst(Pred, FPTrunc.getOperand(0), |
| 8317 | + ConstantFP::get(DestType, ExtMidValue), "", &I); |
| 8318 | +} |
| 8319 | + |
8225 | 8320 | /// Optimize fabs(X) compared with zero.
|
8226 | 8321 | static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombinerImpl &IC) {
|
8227 | 8322 | Value *X;
|
@@ -8712,6 +8807,10 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
|
8712 | 8807 | cast<LoadInst>(LHSI), GEP, GV, I))
|
8713 | 8808 | return Res;
|
8714 | 8809 | break;
|
| 8810 | + case Instruction::FPTrunc: |
| 8811 | + if (Instruction *NV = foldFCmpFpTrunc(I, *LHSI, *RHSC)) |
| 8812 | + return NV; |
| 8813 | + break; |
8715 | 8814 | }
|
8716 | 8815 | }
|
8717 | 8816 |
|
|
0 commit comments