[llvm] [IR] Add nowrap flags for trunc instruction (PR #85592)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 26 05:25:49 PDT 2024
https://github.com/elhewaty updated https://github.com/llvm/llvm-project/pull/85592
>From d1fb0cd61f5c4aa4373be8d1be3ab18d501e0466 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Mon, 18 Mar 2024 02:27:11 +0200
Subject: [PATCH 1/2] [IR] Add nowrap flags for trunc instruction
---
llvm/docs/LangRef.rst | 8 +++++
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 7 ++++
llvm/include/llvm/IR/Instructions.h | 35 +++++++++++++++++++
llvm/lib/AsmParser/LLParser.cpp | 14 +++++++-
llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 16 +++++++--
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 5 +++
llvm/lib/IR/AsmWriter.cpp | 5 +++
llvm/lib/IR/Instruction.cpp | 32 ++++++++++++++---
llvm/lib/IR/Operator.cpp | 4 +++
.../Utils/ScalarEvolutionExpander.cpp | 8 +++++
llvm/test/Assembler/flags.ll | 24 +++++++++++++
llvm/test/Bitcode/flags.ll | 8 +++++
llvm/test/Transforms/InstCombine/freeze.ll | 19 +++++++---
llvm/test/Transforms/InstCombine/trunc.ll | 34 ++++++++++++++++++
llvm/test/Transforms/SimplifyCFG/HoistCode.ll | 34 ++++++++++++++++--
15 files changed, 239 insertions(+), 14 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 77ec72f176d6ed..b9774f5ed08cea 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11295,6 +11295,9 @@ Syntax:
::
<result> = trunc <ty> <value> to <ty2> ; yields ty2
+ <result> = trunc nsw <ty> <value> to <ty2> ; yields ty2
+ <result> = trunc nuw <ty> <value> to <ty2> ; yields ty2
+ <result> = trunc nuw nsw <ty> <value> to <ty2> ; yields ty2
Overview:
"""""""""
@@ -11318,6 +11321,11 @@ and converts the remaining bits to ``ty2``. Since the source size must
be larger than the destination size, ``trunc`` cannot be a *no-op cast*.
It will always truncate bits.
+If the ``nuw`` keyword is present, and any of the truncated bits are zero,
+the result is a :ref:`poison value <poisonvalues>`. If the ``nsw`` keyword
+is present, and any of the truncated bits are not the same as the top bit
+of the truncation result, the result is a :ref:`poison value <poisonvalues>`.
+
Example:
""""""""
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index c0a52d64a101d0..660bd29a42858a 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -491,6 +491,13 @@ enum OverflowingBinaryOperatorOptionalFlags {
OBO_NO_SIGNED_WRAP = 1
};
+/// TruncInstOptionalFlags - Flags for serializing
+/// TruncInstOptionalFlags's SubclassOptionalData contents.
+enum TruncInstOptionalFlags {
+ TIO_NO_UNSIGNED_WRAP = 0,
+ TIO_NO_SIGNED_WRAP = 1
+};
+
/// FastMath Flags
/// This is a fixed layout derived from the bitcode emitted by LLVM 5.0
/// intended to decouple the in-memory representation from the serialization.
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 4e4cf71a349d74..4ffa6349871baf 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -5345,6 +5345,8 @@ class TruncInst : public CastInst {
TruncInst *cloneImpl() const;
public:
+ enum { AnyWrap = 0, NoUnsignedWrap = (1 << 0), NoSignedWrap = (1 << 1) };
+
/// Constructor with insert-before-instruction semantics
TruncInst(
Value *S, ///< The value to be truncated
@@ -5376,6 +5378,39 @@ class TruncInst : public CastInst {
static bool classof(const Value *V) {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
}
+
+ void setHasNoUnsignedWrap(bool B) {
+ SubclassOptionalData =
+ (SubclassOptionalData & ~NoUnsignedWrap) | (B * NoUnsignedWrap);
+ }
+ void setHasNoSignedWrap(bool B) {
+ SubclassOptionalData =
+ (SubclassOptionalData & ~NoSignedWrap) | (B * NoSignedWrap);
+ }
+
+ /// Test whether this operation is known to never
+ /// undergo unsigned overflow, aka the nuw property.
+ bool hasNoUnsignedWrap() const {
+ return SubclassOptionalData & NoUnsignedWrap;
+ }
+
+ /// Test whether this operation is known to never
+ /// undergo signed overflow, aka the nsw property.
+ bool hasNoSignedWrap() const {
+ return (SubclassOptionalData & NoSignedWrap) != 0;
+ }
+
+ /// Returns the no-wrap kind of the operation.
+ unsigned getNoWrapKind() const {
+ unsigned NoWrapKind = 0;
+ if (hasNoUnsignedWrap())
+ NoWrapKind |= NoUnsignedWrap;
+
+ if (hasNoSignedWrap())
+ NoWrapKind |= NoSignedWrap;
+
+ return NoWrapKind;
+ }
};
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 2e0f5ba82220c9..8d641ff6e121a1 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -6772,7 +6772,19 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
Inst->setNonNeg();
return 0;
}
- case lltok::kw_trunc:
+ case lltok::kw_trunc: {
+ bool NUW = EatIfPresent(lltok::kw_nuw);
+ bool NSW = EatIfPresent(lltok::kw_nsw);
+ if (!NUW)
+ NUW = EatIfPresent(lltok::kw_nuw);
+ if (parseCast(Inst, PFS, KeywordVal))
+ return true;
+ if (NUW)
+ cast<TruncInst>(Inst)->setHasNoUnsignedWrap(true);
+ if (NSW)
+ cast<TruncInst>(Inst)->setHasNoSignedWrap(true);
+ return false;
+ }
case lltok::kw_sext:
case lltok::kw_fptrunc:
case lltok::kw_fpext:
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 9c63116114f3c5..62a3cbd4f53cab 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -4995,9 +4995,19 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
return error("Invalid cast");
I = CastInst::Create(CastOp, Op, ResTy);
}
- if (OpNum < Record.size() && isa<PossiblyNonNegInst>(I) &&
- (Record[OpNum] & (1 << bitc::PNNI_NON_NEG)))
- I->setNonNeg(true);
+
+ if (OpNum < Record.size()) {
+ if (Opc == Instruction::ZExt) {
+ if (Record[OpNum] & (1 << bitc::PNNI_NON_NEG))
+ cast<PossiblyNonNegInst>(I)->setNonNeg(true);
+ } else if (Opc == Instruction::Trunc) {
+ if (Record[OpNum] & (1 << bitc::TIO_NO_UNSIGNED_WRAP))
+ cast<TruncInst>(I)->setHasNoUnsignedWrap(true);
+ if (Record[OpNum] & (1 << bitc::TIO_NO_SIGNED_WRAP))
+ cast<TruncInst>(I)->setHasNoSignedWrap(true);
+ }
+ }
+
InstructionList.push_back(I);
break;
}
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 597f49332fad25..0f92dd36ebb3b5 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1636,6 +1636,11 @@ static uint64_t getOptimizationFlags(const Value *V) {
} else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(V)) {
if (NNI->hasNonNeg())
Flags |= 1 << bitc::PNNI_NON_NEG;
+ } else if (const auto *TI = dyn_cast<TruncInst>(V)) {
+ if (TI->hasNoSignedWrap())
+ Flags |= 1 << bitc::TIO_NO_SIGNED_WRAP;
+ if (TI->hasNoUnsignedWrap())
+ Flags |= 1 << bitc::TIO_NO_UNSIGNED_WRAP;
}
return Flags;
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 1beb4c069a6997..41511d429fc9a8 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1411,6 +1411,11 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
} else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(U)) {
if (NNI->hasNonNeg())
Out << " nneg";
+ } else if (const auto *TI = dyn_cast<TruncInst>(U)) {
+ if (TI->hasNoUnsignedWrap())
+ Out << " nuw";
+ if (TI->hasNoSignedWrap())
+ Out << " nsw";
}
}
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index e0892398f43445..33e2e41b7947c2 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -368,11 +368,17 @@ bool Instruction::isOnlyUserOfAnyOperand() {
}
void Instruction::setHasNoUnsignedWrap(bool b) {
- cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(b);
+ if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
+ Inst->setHasNoUnsignedWrap(b);
+ else
+ cast<TruncInst>(this)->setHasNoUnsignedWrap(b);
}
void Instruction::setHasNoSignedWrap(bool b) {
- cast<OverflowingBinaryOperator>(this)->setHasNoSignedWrap(b);
+ if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
+ Inst->setHasNoSignedWrap(b);
+ else
+ cast<TruncInst>(this)->setHasNoSignedWrap(b);
}
void Instruction::setIsExact(bool b) {
@@ -386,11 +392,17 @@ void Instruction::setNonNeg(bool b) {
}
bool Instruction::hasNoUnsignedWrap() const {
- return cast<OverflowingBinaryOperator>(this)->hasNoUnsignedWrap();
+ if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
+ return Inst->hasNoUnsignedWrap();
+
+ return cast<TruncInst>(this)->hasNoUnsignedWrap();
}
bool Instruction::hasNoSignedWrap() const {
- return cast<OverflowingBinaryOperator>(this)->hasNoSignedWrap();
+ if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
+ return Inst->hasNoSignedWrap();
+
+ return cast<TruncInst>(this)->hasNoSignedWrap();
}
bool Instruction::hasNonNeg() const {
@@ -430,6 +442,11 @@ void Instruction::dropPoisonGeneratingFlags() {
case Instruction::ZExt:
setNonNeg(false);
break;
+
+ case Instruction::Trunc:
+ cast<TruncInst>(this)->setHasNoUnsignedWrap(false);
+ cast<TruncInst>(this)->setHasNoSignedWrap(false);
+ break;
}
if (isa<FPMathOperator>(this)) {
@@ -624,6 +641,13 @@ void Instruction::andIRFlags(const Value *V) {
}
}
+ if (auto *TI = dyn_cast<TruncInst>(V)) {
+ if (isa<TruncInst>(this)) {
+ setHasNoSignedWrap(hasNoSignedWrap() && TI->hasNoSignedWrap());
+ setHasNoUnsignedWrap(hasNoUnsignedWrap() && TI->hasNoUnsignedWrap());
+ }
+ }
+
if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
if (isa<PossiblyExactOperator>(this))
setIsExact(isExact() && PE->isExact());
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index caf8fe654a36dc..e738a11074a400 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -27,6 +27,10 @@ bool Operator::hasPoisonGeneratingFlags() const {
auto *OBO = cast<OverflowingBinaryOperator>(this);
return OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap();
}
+ case Instruction::Trunc: {
+ auto *TI = dyn_cast<TruncInst>(this);
+ return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap();
+ }
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::AShr:
diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
index 3a3bcde7c3dcdd..74cffbc005c82d 100644
--- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
+++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
@@ -59,6 +59,10 @@ PoisonFlags::PoisonFlags(const Instruction *I) {
Disjoint = PDI->isDisjoint();
if (auto *PNI = dyn_cast<PossiblyNonNegInst>(I))
NNeg = PNI->hasNonNeg();
+ if (auto *TI = dyn_cast<TruncInst>(I)) {
+ NUW = TI->hasNoUnsignedWrap();
+ NSW = TI->hasNoSignedWrap();
+ }
}
void PoisonFlags::apply(Instruction *I) {
@@ -72,6 +76,10 @@ void PoisonFlags::apply(Instruction *I) {
PDI->setIsDisjoint(Disjoint);
if (auto *PNI = dyn_cast<PossiblyNonNegInst>(I))
PNI->setNonNeg(NNeg);
+ if (isa<TruncInst>(I)) {
+ I->setHasNoUnsignedWrap(NUW);
+ I->setHasNoSignedWrap(NSW);
+ }
}
/// ReuseOrCreateCast - Arrange for there to be a cast of V to Ty at IP,
diff --git a/llvm/test/Assembler/flags.ll b/llvm/test/Assembler/flags.ll
index 04bddd02f50c81..942575584219da 100644
--- a/llvm/test/Assembler/flags.ll
+++ b/llvm/test/Assembler/flags.ll
@@ -261,3 +261,27 @@ define i64 @test_or(i64 %a, i64 %b) {
%res = or disjoint i64 %a, %b
ret i64 %res
}
+
+define i32 @test_trunc_signed(i64 %a) {
+; CHECK: %res = trunc nsw i64 %a to i32
+ %res = trunc nsw i64 %a to i32
+ ret i32 %res
+}
+
+define i32 @test_trunc_unsigned(i64 %a) {
+; CHECK: %res = trunc nuw i64 %a to i32
+ %res = trunc nuw i64 %a to i32
+ ret i32 %res
+}
+
+define i32 @test_trunc_both(i64 %a) {
+; CHECK: %res = trunc nuw nsw i64 %a to i32
+ %res = trunc nuw nsw i64 %a to i32
+ ret i32 %res
+}
+
+define i32 @test_trunc_both_reversed(i64 %a) {
+; CHECK: %res = trunc nuw nsw i64 %a to i32
+ %res = trunc nsw nuw i64 %a to i32
+ ret i32 %res
+}
diff --git a/llvm/test/Bitcode/flags.ll b/llvm/test/Bitcode/flags.ll
index e3fc827d865d7e..2eee96f3356424 100644
--- a/llvm/test/Bitcode/flags.ll
+++ b/llvm/test/Bitcode/flags.ll
@@ -20,6 +20,10 @@ second: ; preds = %first
%ll = zext i32 %s to i64
%jj = or disjoint i32 %a, 0
%oo = or i32 %a, 0
+ %tu = trunc nuw i32 %a to i16
+ %ts = trunc nsw i32 %a to i16
+ %tus = trunc nuw nsw i32 %a to i16
+ %t = trunc i32 %a to i16
unreachable
first: ; preds = %entry
@@ -32,5 +36,9 @@ first: ; preds = %entry
%rr = zext i32 %ss to i64
%mm = or disjoint i32 %a, 0
%nn = or i32 %a, 0
+ %tuu = trunc nuw i32 %a to i16
+ %tss = trunc nsw i32 %a to i16
+ %tuss = trunc nuw nsw i32 %a to i16
+ %tt = trunc i32 %a to i16
br label %second
}
diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll
index da59101d5710cb..e8105b6287d0c5 100644
--- a/llvm/test/Transforms/InstCombine/freeze.ll
+++ b/llvm/test/Transforms/InstCombine/freeze.ll
@@ -1049,7 +1049,7 @@ exit:
define ptr @freeze_load_noundef(ptr %ptr) {
; CHECK-LABEL: @freeze_load_noundef(
-; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !noundef !0
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !noundef [[META0:![0-9]+]]
; CHECK-NEXT: ret ptr [[P]]
;
%p = load ptr, ptr %ptr, !noundef !0
@@ -1059,7 +1059,7 @@ define ptr @freeze_load_noundef(ptr %ptr) {
define ptr @freeze_load_dereferenceable(ptr %ptr) {
; CHECK-LABEL: @freeze_load_dereferenceable(
-; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable !1
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable [[META1:![0-9]+]]
; CHECK-NEXT: ret ptr [[P]]
;
%p = load ptr, ptr %ptr, !dereferenceable !1
@@ -1138,6 +1138,17 @@ define i32 @propagate_drop_flags_or(i32 %arg) {
ret i32 %v1.fr
}
+define i32 @propagate_drop_flags_trunc(i64 %arg) {
+; CHECK-LABEL: @propagate_drop_flags_trunc(
+; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i64 [[ARG:%.*]]
+; CHECK-NEXT: [[V1:%.*]] = trunc i64 [[ARG_FR]] to i32
+; CHECK-NEXT: ret i32 [[V1]]
+;
+ %v1 = trunc nsw nuw i64 %arg to i32
+ %v1.fr = freeze i32 %v1
+ ret i32 %v1.fr
+}
+
!0 = !{}
!1 = !{i64 4}
!2 = !{i32 0, i32 100}
@@ -1145,8 +1156,8 @@ define i32 @propagate_drop_flags_or(i32 %arg) {
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { nounwind }
;.
-; CHECK: [[META0:![0-9]+]] = !{}
-; CHECK: [[META1:![0-9]+]] = !{i64 4}
+; CHECK: [[META0]] = !{}
+; CHECK: [[META1]] = !{i64 4}
; CHECK: [[RNG2]] = !{i32 0, i32 100}
; CHECK: [[RNG3]] = !{i32 0, i32 33}
;.
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index c6bc06d666d0ae..5e1fa9faabcb6b 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1021,3 +1021,37 @@ define i16 @PR44545(i32 %t0, i32 %data) {
%sub = add nsw i16 %cast, -1
ret i16 %sub
}
+
+; Make sure that SimplifyDemandedBits drops the nowrap flags
+define i16 @drop_nsw_trunc(i32 %x) {
+; CHECK-LABEL: @drop_nsw_trunc(
+; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], -2
+; CHECK-NEXT: ret i16 [[B]]
+;
+ %t = and i32 %x, -2
+ %b = trunc nsw i32 %t to i16
+ ret i16 %b
+}
+
+define i16 @drop_nuw_trunc(i32 %x) {
+; CHECK-LABEL: @drop_nuw_trunc(
+; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], 1
+; CHECK-NEXT: ret i16 [[B]]
+;
+ %t = and i32 %x, 1
+ %b = trunc nuw i32 %t to i16
+ ret i16 %b
+}
+
+define i16 @drop_both_trunc(i32 %x) {
+; CHECK-LABEL: @drop_both_trunc(
+; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], -2
+; CHECK-NEXT: ret i16 [[B]]
+;
+ %t = and i32 %x, -2
+ %b = trunc nsw nuw i32 %t to i16
+ ret i16 %b
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
index a081eddfc45660..4a4c94098ab94c 100644
--- a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
+++ b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
@@ -64,8 +64,8 @@ define float @PR39535min_switch(i64 %i, float %x) {
; CHECK-LABEL: @PR39535min_switch(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i64 [[I:%.*]], label [[END:%.*]] [
-; CHECK-NEXT: i64 1, label [[BB1:%.*]]
-; CHECK-NEXT: i64 2, label [[BB2:%.*]]
+; CHECK-NEXT: i64 1, label [[BB1:%.*]]
+; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: bb1:
; CHECK-NEXT: br label [[END]]
@@ -154,3 +154,33 @@ F:
%z2 = or disjoint i32 %x, %y
ret i32 %z2
}
+
+define i16 @hoist_trunc_flags_preserve(i1 %C, i32 %x) {
+; CHECK-LABEL: @hoist_trunc_flags_preserve(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = trunc nuw nsw i32 [[X:%.*]] to i16
+; CHECK-NEXT: ret i16 [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = trunc nsw nuw i32 %x to i16
+ ret i16 %z1
+F:
+ %z2 = trunc nsw nuw i32 %x to i16
+ ret i16 %z2
+}
+
+define i16 @hoist_trunc_flags_drop(i1 %C, i32 %x) {
+; CHECK-LABEL: @hoist_trunc_flags_drop(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: ret i16 [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = trunc i32 %x to i16
+ ret i16 %z1
+F:
+ %z2 = trunc nsw nuw i32 %x to i16
+ ret i16 %z2
+}
>From 65196554de472ca37fdb170bb4f2871a5ece17b1 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Tue, 26 Mar 2024 14:24:35 +0200
Subject: [PATCH 2/2] Fixup InstCombine tests(NFC)
---
llvm/test/Transforms/InstCombine/trunc.ll | 47 ++++++++++++-----------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 5e1fa9faabcb6b..760825d6b1da0d 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1023,35 +1023,38 @@ define i16 @PR44545(i32 %t0, i32 %data) {
}
; Make sure that SimplifyDemandedBits drops the nowrap flags
-define i16 @drop_nsw_trunc(i32 %x) {
+define i8 @drop_nsw_trunc(i16 %x, i16 %y) {
; CHECK-LABEL: @drop_nsw_trunc(
-; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
-; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], -2
-; CHECK-NEXT: ret i16 [[B]]
+; CHECK-NEXT: [[AND2:%.*]] = and i16 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = trunc i16 [[AND2]] to i8
+; CHECK-NEXT: ret i8 [[RES]]
;
- %t = and i32 %x, -2
- %b = trunc nsw i32 %t to i16
- ret i16 %b
+ %and = and i16 %x, 255
+ %and2 = and i16 %and, %y
+ %res = trunc nsw i16 %and2 to i8
+ ret i8 %res
}
-define i16 @drop_nuw_trunc(i32 %x) {
+define i8 @drop_nuw_trunc(i16 %x, i16 %y) {
; CHECK-LABEL: @drop_nuw_trunc(
-; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
-; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], 1
-; CHECK-NEXT: ret i16 [[B]]
+; CHECK-NEXT: [[AND2:%.*]] = and i16 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = trunc i16 [[AND2]] to i8
+; CHECK-NEXT: ret i8 [[B]]
;
- %t = and i32 %x, 1
- %b = trunc nuw i32 %t to i16
- ret i16 %b
+ %and = and i16 %x, 255
+ %and2 = and i16 %and, %y
+ %res = trunc nuw i16 %and2 to i8
+ ret i8 %res
}
-define i16 @drop_both_trunc(i32 %x) {
+define i8 @drop_both_trunc(i16 %x, i16 %y) {
; CHECK-LABEL: @drop_both_trunc(
-; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
-; CHECK-NEXT: [[B:%.*]] = and i16 [[TMP1]], -2
-; CHECK-NEXT: ret i16 [[B]]
-;
- %t = and i32 %x, -2
- %b = trunc nsw nuw i32 %t to i16
- ret i16 %b
+; CHECK-NEXT: [[AND2:%.*]] = and i16 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = trunc i16 [[AND2]] to i8
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %and = and i16 %x, 255
+ %and2 = and i16 %and, %y
+ %res = trunc nuw nsw i16 %and2 to i8
+ ret i8 %res
}
More information about the llvm-commits
mailing list