Index: llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1747,6 +1747,32 @@ return true; } + // Try to evaluate the value range of the source integer. If all the value is + // within the value range of 2^DestNumSigBits, then the value can be + // accurately represented. + PHINode *Phi = dyn_cast(Src); + if (Phi && (Phi->getNumIncomingValues() == 2) && + Phi->getParent() == Phi->getIncomingBlock(1) && Phi->getNumUses() == 2 && + (I.getParent() == Phi->getIncomingBlock(1))) { + auto *Previous = dyn_cast( + Phi->getIncomingValueForBlock(Phi->getIncomingBlock(0))); + auto *Next = dyn_cast( + Phi->getIncomingValueForBlock(Phi->getIncomingBlock(1))); + + if (!Previous || !Next || Next->getOpcode() != Instruction::Add) + return false; + + int64_t InitValue = Previous->getSExtValue(); + ICmpInst *CmpInst = dyn_cast(Next->use_begin()->getUser()); + if (!CmpInst || !dyn_cast(CmpInst->getOperand(1))) + return false; + int64_t EndValue = + cast(CmpInst->getOperand(1))->getSExtValue(); + + return ((InitValue >> DestNumSigBits) == 0) && + ((EndValue >> DestNumSigBits) == 0); + } + // TODO: // Try harder to find if the source integer type has less significant bits. // For example, compute number of sign bits or compute low bit mask. Index: llvm/test/Transforms/InstCombine/fptrunc.ll =================================================================== --- llvm/test/Transforms/InstCombine/fptrunc.ll +++ llvm/test/Transforms/InstCombine/fptrunc.ll @@ -190,3 +190,74 @@ %r = fptrunc float %x to half ret half %r } + +@array = dso_local global [101 x i32] zeroinitializer, align 4 +; Positive test - intermediate 16777215 (= 1 << 24 - 1) rounding in float type. +define void @foo_max () { +; CHECK-LABEL: @foo_max( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[INDVAR_PHI:%.*]] = phi i32 [ 16777215, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[IDX:%.*]] = sext i32 [[INDVAR_PHI]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 [[IDX]] +; CHECK-NEXT: store i32 [[INDVAR_PHI]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[DEC_INT]] = add nsw i32 [[INDVAR_PHI]], -1 +; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[DEC_INT]], 0 +; CHECK-NEXT: br i1 [[CMP_NOT]], label [[CLEANUP:%.*]], label [[FOR_BODY]] +; CHECK: cleanup: +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %indvar.phi = phi i32 [ 16777215, %entry ], [ %dec.int, %for.body ] + %indvar.fp = sitofp i32 %indvar.phi to float + %indvar.si = fptosi float %indvar.fp to i32 + %idx = sext i32 %indvar.si to i64 + %arrayidx = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 %idx + store i32 %indvar.si, i32* %arrayidx, align 4 + %dec.int = add nsw i32 %indvar.phi, -1 + %cmp = icmp ugt i32 %dec.int, 0 + br i1 %cmp, label %for.body, label %cleanup + +cleanup: ; preds = %for.body + ret void +} + +; Negative test - intermediate 16777216 (= 1 << 24) rounding in float type. +define void @float_overflow () { +; CHECK-LABEL: @float_overflow( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[INDVAR_PHI:%.*]] = phi i32 [ 16777216, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[INDVAR_FP:%.*]] = sitofp i32 [[INDVAR_PHI]] to float +; CHECK-NEXT: [[INDVAR_SI:%.*]] = fptosi float [[INDVAR_FP]] to i32 +; CHECK-NEXT: [[IDX:%.*]] = sext i32 [[INDVAR_SI]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 [[IDX]] +; CHECK-NEXT: store i32 [[INDVAR_SI]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[DEC_INT]] = add nsw i32 [[INDVAR_PHI]], -1 +; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[DEC_INT]], 0 +; CHECK-NEXT: br i1 [[CMP_NOT]], label [[CLEANUP:%.*]], label [[FOR_BODY]] +; CHECK: cleanup: +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %indvar.phi = phi i32 [ 16777216, %entry ], [ %dec.int, %for.body ] + %indvar.fp = sitofp i32 %indvar.phi to float + %indvar.si = fptosi float %indvar.fp to i32 + %idx = sext i32 %indvar.si to i64 + %arrayidx = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 %idx + store i32 %indvar.si, i32* %arrayidx, align 4 + %dec.int = add nsw i32 %indvar.phi, -1 + %cmp = icmp ugt i32 %dec.int, 0 + br i1 %cmp, label %for.body, label %cleanup + +cleanup: ; preds = %for.body + ret void +}