Skip to content

[IR] Add nowrap flags for trunc instruction #85592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 29, 2024
Merged

Conversation

elhewaty
Copy link
Member

This patch adds the nuw (no unsigned wrap) and nsw (no signed wrap)
poison-generating flags to the trunc instruction.

Discourse thread: https://discourse.llvm.org/t/rfc-add-nowrap-flags-to-trunc/77453

@llvmbot
Copy link
Member

llvmbot commented Mar 18, 2024

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-ir

Author: None (elhewaty)

Changes

This patch adds the nuw (no unsigned wrap) and nsw (no signed wrap)
poison-generating flags to the trunc instruction.

Discourse thread: https://discourse.llvm.org/t/rfc-add-nowrap-flags-to-trunc/77453


Full diff: https://github.com/llvm/llvm-project/pull/85592.diff

12 Files Affected:

  • (modified) llvm/docs/LangRef.rst (+10)
  • (modified) llvm/include/llvm/Bitcode/LLVMBitCodes.h (+7)
  • (modified) llvm/include/llvm/IR/InstrTypes.h (+50)
  • (modified) llvm/lib/AsmParser/LLParser.cpp (+13-1)
  • (modified) llvm/lib/Bitcode/Reader/BitcodeReader.cpp (+13-3)
  • (modified) llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (+5)
  • (modified) llvm/lib/IR/AsmWriter.cpp (+5)
  • (modified) llvm/lib/IR/Instruction.cpp (+30-4)
  • (modified) llvm/lib/IR/Operator.cpp (+4)
  • (modified) llvm/test/Assembler/flags.ll (+24)
  • (modified) llvm/test/Bitcode/flags.ll (+8)
  • (modified) llvm/test/Transforms/InstCombine/freeze.ll (+15-4)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 77ec72f176d6ed..902ba737bb1dd7 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,13 @@ 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.
 
+``nuw`` and ``nsw`` stand for "No Unsigned Wrap" and "No Signed Wrap",
+respectively. If the ``nuw`` and/or ``nsw`` keywords are present, the
+result value of the ``add`` is a :ref:`poison value <poisonvalues>` if
+any of the truncated bits are non-zero and/or any of the truncated bits
+are not the same as the top bit of the truncation result,respectively,
+occurs.
+
 Example:
 """"""""
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index c0a52d64a101d0..5e776c940e197e 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
 };
 
+/// PossiblyNoWrapInstOptionalFlags - Flags for serializing
+/// PossiblyNoWrapInstOptionalFlags's SubclassOptionalData contents.
+enum PossiblyNoWrapInstOptionalFlags {
+  PNWIO_NO_UNSIGNED_WRAP = 0,
+  PNWIO_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/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index fed21b992e3d10..dd7b253f2f0d93 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -946,6 +946,56 @@ class PossiblyNonNegInst : public CastInst {
   }
 };
 
+/// Cast Instruction that can have a nowrap flags (only trunc)
+class PossiblyNoWrapInst : public CastInst {
+public:
+  enum { AnyWrap = 0, NoUnsignedWrap = (1 << 0), NoSignedWrap = (1 << 1) };
+
+  static bool classof(const Instruction *I) {
+    return I->getOpcode() == Instruction::Trunc;
+  }
+
+  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);
+  }
+
+  /// Transparently provide more efficient getOperand methods.
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+
+  /// 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;
+  }
+};
+
 //===----------------------------------------------------------------------===//
 //                               CmpInst Class
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 2e0f5ba82220c9..83c0121265139d 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<PossiblyNoWrapInst>(Inst)->setHasNoUnsignedWrap(true);
+    if (NSW)
+      cast<PossiblyNoWrapInst>(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..a1a493b201a3b1 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::PNWIO_NO_UNSIGNED_WRAP))
+            cast<PossiblyNoWrapInst>(I)->setHasNoUnsignedWrap(true);
+          if (Record[OpNum] & (1 << bitc::PNWIO_NO_SIGNED_WRAP))
+            cast<PossiblyNoWrapInst>(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..e0ddf123254ddc 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 *PNWI = dyn_cast<PossiblyNoWrapInst>(V)) {
+    if (PNWI->hasNoSignedWrap())
+      Flags |= 1 << bitc::PNWIO_NO_SIGNED_WRAP;
+    if (PNWI->hasNoUnsignedWrap())
+      Flags |= 1 << bitc::PNWIO_NO_UNSIGNED_WRAP;
   }
 
   return Flags;
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 1beb4c069a6997..546b2ffdaa5256 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 *PNWI = dyn_cast<PossiblyNoWrapInst>(U)) {
+    if (PNWI->hasNoUnsignedWrap())
+      Out << " nuw";
+    if (PNWI->hasNoSignedWrap())
+      Out << " nsw";
   }
 }
 
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index e0892398f43445..1c8dca7e40f0c7 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -368,11 +368,19 @@ bool Instruction::isOnlyUserOfAnyOperand() {
 }
 
 void Instruction::setHasNoUnsignedWrap(bool b) {
-  cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(b);
+  if (auto Inst = cast<OverflowingBinaryOperator>(this)) {
+    Inst->setHasNoUnsignedWrap(b);
+  } else {
+    cast<PossiblyNoWrapInst>(this)->setHasNoUnsignedWrap(b);
+  }
 }
 
 void Instruction::setHasNoSignedWrap(bool b) {
-  cast<OverflowingBinaryOperator>(this)->setHasNoSignedWrap(b);
+  if (auto Inst = cast<OverflowingBinaryOperator>(this)) {
+    Inst->setHasNoSignedWrap(b);
+  } else {
+    cast<PossiblyNoWrapInst>(this)->setHasNoSignedWrap(b);
+  }
 }
 
 void Instruction::setIsExact(bool b) {
@@ -386,11 +394,17 @@ void Instruction::setNonNeg(bool b) {
 }
 
 bool Instruction::hasNoUnsignedWrap() const {
-  return cast<OverflowingBinaryOperator>(this)->hasNoUnsignedWrap();
+  if (auto Inst = cast<OverflowingBinaryOperator>(this))
+    return Inst->hasNoUnsignedWrap();
+
+  return cast<PossiblyNoWrapInst>(this)->hasNoUnsignedWrap();
 }
 
 bool Instruction::hasNoSignedWrap() const {
-  return cast<OverflowingBinaryOperator>(this)->hasNoSignedWrap();
+  if (auto Inst = cast<OverflowingBinaryOperator>(this))
+    return Inst->hasNoSignedWrap();
+
+  return cast<PossiblyNoWrapInst>(this)->hasNoSignedWrap();
 }
 
 bool Instruction::hasNonNeg() const {
@@ -430,6 +444,11 @@ void Instruction::dropPoisonGeneratingFlags() {
   case Instruction::ZExt:
     setNonNeg(false);
     break;
+
+  case Instruction::Trunc:
+    cast<PossiblyNoWrapInst>(this)->setHasNoUnsignedWrap(false);
+    cast<PossiblyNoWrapInst>(this)->setHasNoSignedWrap(false);
+    break;
   }
 
   if (isa<FPMathOperator>(this)) {
@@ -624,6 +643,13 @@ void Instruction::andIRFlags(const Value *V) {
     }
   }
 
+  if (auto *PNWI = dyn_cast<PossiblyNoWrapInst>(V)) {
+    if (isa<PossiblyNoWrapInst>(this)) {
+      setHasNoSignedWrap(hasNoSignedWrap() && PNWI->hasNoSignedWrap());
+      setHasNoUnsignedWrap(hasNoUnsignedWrap() && PNWI->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..ec292316d1265f 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 *PNWI = dyn_cast<PossiblyNoWrapInst>(this);
+    return PNWI->hasNoUnsignedWrap() || PNWI->hasNoSignedWrap();
+  }
   case Instruction::UDiv:
   case Instruction::SDiv:
   case Instruction::AShr:
diff --git a/llvm/test/Assembler/flags.ll b/llvm/test/Assembler/flags.ll
index 04bddd02f50c81..aef2aeba7c78a6 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}
 ;.

@elhewaty
Copy link
Member Author

elhewaty commented Mar 18, 2024

@nikic, @jayfoad, @preames, @topperc @dtcxzyw @arsenm @goldsteinn @RKSimon please review.
It causes some regressions, but I shared it to get some ideas.

@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 18, 2024

Failed Tests (8):
LLVM :: CodeGen/Hexagon/packed-store.ll
LLVM :: Transforms/GVN/callbr-scalarpre-critedge.ll
LLVM :: Transforms/GVN/invariant.group.ll
LLVM :: Transforms/GVN/pre-new-inst.ll
LLVM :: Transforms/GVNHoist/hoist-pr20242.ll
LLVM :: Transforms/GVNSink/sink-common-code.ll
LLVM :: Transforms/PhaseOrdering/X86/vec-load-combine.ll
LLVM :: Transforms/SimplifyCFG/dont-hoist-deoptimize.ll

Please fix test failures.

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow up should add support to llvm-reduce to strip these

@nikic
Copy link
Contributor

nikic commented Mar 18, 2024

One more place you need to update for correctness reasons is InstCombineSimplifyDemanded: You need to drop poison generating flags when doing demanded bits simplification of trunc now. (This should be tested.)

Another place to update is SCEVExpander, which backs up poison-generating flags. Needs an adjustment to handle these on trunc now. (Don't think this needs a test, it's pretty tricky to do that.)

@nikic
Copy link
Contributor

nikic commented Mar 18, 2024

Please also add a test in llvm/test/Transforms/SimplifyCFG/HoistCode.ll for the flag intersection behavior. See existing disjoint/nneg tests.

@elhewaty
Copy link
Member Author

Another place to update is SCEVExpander, which backs up poison-generating flags. Needs an adjustment to handle these on trunc now. (Don't think this needs a test, it's pretty tricky to do that.)

before modifying the SCEVExpander, are these places legal to modify here, should we add a class like this, should we modift this to

@nikic
Copy link
Contributor

nikic commented Mar 18, 2024

Another place to update is SCEVExpander, which backs up poison-generating flags. Needs an adjustment to handle these on trunc now. (Don't think this needs a test, it's pretty tricky to do that.)

before modifying the SCEVExpander, are these places legal to modify here, should we add a class like this, should we modift this to

You should not modify any of those places (at least in this PR), only

PoisonFlags::PoisonFlags(const Instruction *I) {
NUW = false;
NSW = false;
Exact = false;
Disjoint = false;
NNeg = false;
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(I)) {
NUW = OBO->hasNoUnsignedWrap();
NSW = OBO->hasNoSignedWrap();
}
if (auto *PEO = dyn_cast<PossiblyExactOperator>(I))
Exact = PEO->isExact();
if (auto *PDI = dyn_cast<PossiblyDisjointInst>(I))
Disjoint = PDI->isDisjoint();
if (auto *PNI = dyn_cast<PossiblyNonNegInst>(I))
NNeg = PNI->hasNonNeg();
}
void PoisonFlags::apply(Instruction *I) {
if (isa<OverflowingBinaryOperator>(I)) {
I->setHasNoUnsignedWrap(NUW);
I->setHasNoSignedWrap(NSW);
}
if (isa<PossiblyExactOperator>(I))
I->setIsExact(Exact);
if (auto *PDI = dyn_cast<PossiblyDisjointInst>(I))
PDI->setIsDisjoint(Disjoint);
if (auto *PNI = dyn_cast<PossiblyNonNegInst>(I))
PNI->setNonNeg(NNeg);
}

@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 22, 2024


Failed Tests (8):
LLVM :: CodeGen/Hexagon/packed-store.ll
LLVM :: Transforms/GVN/callbr-scalarpre-critedge.ll
LLVM :: Transforms/GVN/invariant.group.ll
LLVM :: Transforms/GVN/pre-new-inst.ll
LLVM :: Transforms/GVNHoist/hoist-pr20242.ll
LLVM :: Transforms/GVNSink/sink-common-code.ll
LLVM :: Transforms/PhaseOrdering/X86/vec-load-combine.ll
LLVM :: Transforms/SimplifyCFG/dont-hoist-deoptimize.ll

@elhewaty
Copy link
Member Author

@dtcxzyw can you please take a look at the review questions I posted?

@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 22, 2024

@dtcxzyw can you please take a look at the review questions I posted?

It seems all questions have been answered by other reviewers. Did you forget to submit your pending comments?

Copy link

github-actions bot commented Mar 22, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@antoniofrighetto
Copy link
Contributor

@elhewaty Looks like we have to check that dyn_cast is actually applicable, as we may be dealing with ConstantExpr, not just Instruction (which is the case in the above function that leads to the crash), e.g.:

--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -28,8 +28,9 @@ bool Operator::hasPoisonGeneratingFlags() const {
     return OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap();
   }
   case Instruction::Trunc: {
-    auto *TI = dyn_cast<TruncInst>(this);
-    return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap();
+    if (auto *TI = dyn_cast<TruncInst>(this))
+      return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap();
+    return false;
   }
   case Instruction::UDiv:
   case Instruction::SDiv:

searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Mar 31, 2024
pullls in experimentally to try and fix asan hip build
[IR] Fix crashes caused by llvm#85592 llvm#87169

Change-Id: Iee30a92a0e28b6949b69c34047fe2df9aabdd424
@programmerjake
Copy link
Contributor

found a semantically important typo: #87285

dtcxzyw pushed a commit that referenced this pull request Apr 2, 2024
This patch fixes the crash caused by the pull request:
#85592
RKSimon added a commit that referenced this pull request Apr 3, 2024
Based off #85592 - our truncation -> PACKSS/PACKUS folds should be able to use the nsw/nuw flags to recognise when we don't need to mask/sext_inreg prior to the PACKSS/PACKUS nodes.
@dtcxzyw
Copy link
Member

dtcxzyw commented Apr 4, 2024

@elhewaty Would you like to add the support for dropping nsw/nuw flags in llvm/tools/llvm-reduce/deltas/ReduceInstructionFlags.cpp:reduceFlagsInModule?

@elhewaty
Copy link
Member Author

elhewaty commented Apr 5, 2024

@dtcxzyw, I am thinking of filing a meta issue (task), and work on tasks related to this patch:

  • Add nowrap flags
  • Fix unexpected crashes
  • Lower the nowrap flags to SDAG
  • Add the support for dropping nsw/nuw flags to llvm-reduce
  • Infer nsw/nuw flags in instCombine
  • Implement zext(trunc nuw) and sext(trunc nsw) fold
  • Emit trunc nuw/nsw in SimplifyIndVars IV widening
  • Look for opportunities in the code to use trunc nuw/nsw

but I am busy these days, I will continue working on these tasks, but if you need them, and they are urgent you can work on them.

what do you think?

@arsenm
Copy link
Contributor

arsenm commented Apr 6, 2024

  • Add the support for dropping nsw/nuw flags to llvm-reduce

I've already implemented this but haven't had working internet to push it

@XChy
Copy link
Member

XChy commented Apr 7, 2024

I would like to add the support for the flags in SCCP.

XChy added a commit that referenced this pull request Apr 11, 2024
Following #85592, add support for nsw/nuw flags of trunc in SCCP.
@dtcxzyw
Copy link
Member

dtcxzyw commented Apr 19, 2024

We forgot to support these flags in Instruction::copyIRFlags :(
I will post a patch later.

@elhewaty
Copy link
Member Author

We forgot to support these flags in Instruction::copyIRFlags :( I will post a patch later.

And Instruction::andIRFlags too :(

dtcxzyw added a commit that referenced this pull request Apr 19, 2024
aniplcc pushed a commit to aniplcc/llvm-project that referenced this pull request Apr 21, 2024
@elhewaty
Copy link
Member Author

We forgot to support these flags in Instruction::copyIRFlags :( I will post a patch later.

And Instruction::andIRFlags too :(

@dtcxzyw are you working on this, too?

@dtcxzyw
Copy link
Member

dtcxzyw commented Apr 24, 2024

We forgot to support these flags in Instruction::copyIRFlags :( I will post a patch later.

And Instruction::andIRFlags too :(

@dtcxzyw are you working on this, too?

if (auto *TI = dyn_cast<TruncInst>(V)) {
if (isa<TruncInst>(this)) {
setHasNoSignedWrap(hasNoSignedWrap() && TI->hasNoSignedWrap());
setHasNoUnsignedWrap(hasNoUnsignedWrap() && TI->hasNoUnsignedWrap());
}
}

Isn't it handled by this patch?

@elhewaty
Copy link
Member Author

I am sorry I missed this I read copyIRflags as andIRflags.
I should have double-checked this

@dtcxzyw
Copy link
Member

dtcxzyw commented May 20, 2024

  • Add the support for dropping nsw/nuw flags to llvm-reduce

I've already implemented this but haven't had working internet to push it

Ping?

@arsenm
Copy link
Contributor

arsenm commented May 20, 2024

  • Add the support for dropping nsw/nuw flags to llvm-reduce

I've already implemented this but haven't had working internet to push it

Ping?

This was fc9a507

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.