llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

[IR] Add nowrap flags for trunc instruction

Open elhewaty opened this issue 1 year ago • 12 comments

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

elhewaty avatar Mar 18 '24 01:03 elhewaty

@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}
 ;.

llvmbot avatar Mar 18 '24 01:03 llvmbot

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

elhewaty avatar Mar 18 '24 01:03 elhewaty

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.

dtcxzyw avatar Mar 18 '24 04:03 dtcxzyw

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 avatar Mar 18 '24 11:03 nikic

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

nikic avatar Mar 18 '24 11:03 nikic

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

elhewaty avatar Mar 18 '24 15:03 elhewaty

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 https://github.com/llvm/llvm-project/blob/12b802ac0bc6ddf0742aa3fe8caecd8204d70ca5/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp#L46-L75

nikic avatar Mar 18 '24 15:03 nikic


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

dtcxzyw avatar Mar 22 '24 16:03 dtcxzyw

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

elhewaty avatar Mar 22 '24 17:03 elhewaty

@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?

dtcxzyw avatar Mar 22 '24 17:03 dtcxzyw

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

github-actions[bot] avatar Mar 22 '24 22:03 github-actions[bot]

:white_check_mark: With the latest revision this PR passed the Python code formatter.

github-actions[bot] avatar Mar 22 '24 22:03 github-actions[bot]

@RKSimon, If you plan to propagate this down to SDAG I want to work on it, if possible. Can you share similar work as a reference?

elhewaty avatar Mar 26 '24 13:03 elhewaty

@nikic is there any follow-up work depending on this?

elhewaty avatar Mar 26 '24 13:03 elhewaty

@elhewaty There is a lot of possible followup work here, I think some of the most important piece would be:

  • Implement inference for nuw/nsw flags in InstCombine
  • Implement zext(trunc nuw) and sext(trunc nsw) fold
  • Emit trunc nuw/nsw in SimplifyIndVars IV widening

And beyond that switching various transform to make use of the flags, for example this fold should use the flags instead of checking KnownBits: https://github.com/llvm/llvm-project/blob/3a2c70b3713a856ea416d92abdddb7893fca308b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp#L1504

nikic avatar Mar 26 '24 13:03 nikic

@elhewaty I've started playing with some vector test coverage already - once this has landed I'll commit the tests, raise a ticket and assign it to you.

RKSimon avatar Mar 26 '24 13:03 RKSimon

@nikic, Thanks, I will work on them all.

elhewaty avatar Mar 26 '24 14:03 elhewaty

@elhewaty I've started playing with some vector test coverage already - once this has landed I'll commit the tests, raise a ticket and assign it to you.

Thanks, I am looking forward to it.

elhewaty avatar Mar 26 '24 14:03 elhewaty

@elhewaty There is a lot of possible followup work here, I think some of the most important piece would be:

  • Implement inference for nuw/nsw flags in InstCombine
  • Implement zext(trunc nuw) and sext(trunc nsw) fold
  • Emit trunc nuw/nsw in SimplifyIndVars IV widening

@nikic, I'm taking a look at point 3. Not super familiar w/ IV widening, but I guess whenever the uses are truncated, we want to preserve the information that previously got lost? I'm mainly referring to widenIVUse/truncateIVUse and variants thereof (e.g., widenWithVariantUse) (cc/ @dtcxzyw).

antoniofrighetto avatar Mar 26 '24 15:03 antoniofrighetto

@antoniofrighetto

@nikic, I'm taking a look at point 3. Not super familiar w/ IV widening, but I guess whenever the uses are truncated, we want to preserve the information that previously got lost? I'm mainly referring to widenIVUse/truncateIVUse and variants thereof (e.g., widenWithVariantUse) (cc/ @dtcxzyw).

I am taking a look too, I am not familiar with w/ IV widening, So I think it's a good chance for me to work on it. I will look at the functions you mentioned too. Thanks

elhewaty avatar Mar 26 '24 15:03 elhewaty

@dtcxzyw, @nikic ping :bell: !

elhewaty avatar Mar 27 '24 19:03 elhewaty

I bisected a crash that I see when building the Linux kernel for arm64 to this change.

# bad: [a4de589d117a4fd52554da3c61ae6eb26c90a0c8] [InstallAPI] Add support for parsing dSYMs (#86852)
# good: [552c8eb731a1fabef4d81e2a69911506adf39e22] [SLP][NFC]Add a test with the wrong result extension after reduction, NFC.
git bisect start 'a4de589d117a4fd52554da3c61ae6eb26c90a0c8' '552c8eb731a1fabef4d81e2a69911506adf39e22'
# good: [39fe729502006f1b108828b75af8d63a27364f80] [lld-macho] Ignore -no_warn_duplicate_libraries flag (#86303)
git bisect good 39fe729502006f1b108828b75af8d63a27364f80
# good: [219511aee21cc652e1ede0458de4a4a66f04c81c] [APINotes] Make an assert in a std::sort call tolerate self-comparisons
git bisect good 219511aee21cc652e1ede0458de4a4a66f04c81c
# bad: [28760b63bbf9e267713957105a8d17091fb0d20e] Revert "Reapply "[clang][nullability] allow _Nonnull etc on nullable class types (#82705)"" (#87041)
git bisect bad 28760b63bbf9e267713957105a8d17091fb0d20e
# good: [01e02e0b6a15562e241e9ed18b295c66ae20f410] [SLP]Fix PR87011: Do not assume that initial ext/trunc nodes can be represented by bitwidth without analysis.
git bisect good 01e02e0b6a15562e241e9ed18b295c66ae20f410
# good: [e005a09df5b5c7d210ac7cd8cbddb3a4a8663173] [RISCV][TypePromotion] Dont generate truncs if PromotedType is greater than Source Type (#86941)
git bisect good e005a09df5b5c7d210ac7cd8cbddb3a4a8663173
# bad: [235d6841601a9dbea293b8e82b0c994f91f42d76] [C++20] [Modules] [Reduced BMI] Don't record declarations in functions by default
git bisect bad 235d6841601a9dbea293b8e82b0c994f91f42d76
# bad: [7d3924cee30a87a51f9dc04ec843ae6bc3d1c90e] [IR] Add nowrap flags for trunc instruction (#85592)
git bisect bad 7d3924cee30a87a51f9dc04ec843ae6bc3d1c90e
# good: [ba6b2d22af177a72b132cdb8e9350a708f282d2c] [LLDB] Add APFloat helper functions to Scalar class. (#86862)
git bisect good ba6b2d22af177a72b132cdb8e9350a708f282d2c
# first bad commit: [7d3924cee30a87a51f9dc04ec843ae6bc3d1c90e] [IR] Add nowrap flags for trunc instruction (#85592)

A trivial C and LLVM IR reproducer:

int __kmalloc_index(long size) {
  if (size <= 4)
    return 1;
  if (size <= 4 * 4)
    return 2;
  asm("");
  __builtin_unreachable();
}
void kmalloc_trace(int *);
void *kmalloc(long size) {
  int index = __kmalloc_index(size);
  kmalloc_trace(&index);
  return 0;
}
int unittest_data_add() {
  extern unsigned char __dtbo_testcases_begin[], __dtbo_testcases_end[];
  int size = __dtbo_testcases_end - __dtbo_testcases_begin;
  void *ret = kmalloc(size + 8);
  if (ret)
    ;
  return 0;
}
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@__dtbo_testcases_begin = external global [0 x i8]

define i32 @__kmalloc_index(i64 %size) {
entry:
  %cmp = icmp slt i64 %size, 0
  br i1 %cmp, label %return, label %if.end

if.end:                                           ; preds = %entry
  %cmp1 = icmp eq i64 %size, 0
  br i1 %cmp1, label %return, label %if.end3

if.end3:                                          ; preds = %if.end
  store volatile i32 0, ptr null, align 4294967296
  unreachable

return:                                           ; preds = %if.end, %entry
  %retval.0 = phi i32 [ 1, %entry ], [ 0, %if.end ]
  ret i32 %retval.0
}

define ptr @kmalloc(i64 %size, ptr %index) {
entry:
  %call = call i32 @__kmalloc_index(i64 %size)
  store i32 %call, ptr %index, align 4
  ret ptr null
}

define i32 @unittest_data_add() {
entry:
  %add = add i32 trunc (i64 sub (i64 0, i64 ptrtoint (ptr @__dtbo_testcases_begin to i64)) to i32), 1
  %conv = sext i32 %add to i64
  %call1 = call ptr @kmalloc(i64 %conv, ptr null)
  ret i32 0
}
$ clang -O2 -c -o /dev/null unittest.i
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: clang -O2 -c -o /dev/null unittest.i
1.	<eof> parser at end of file
2.	Optimizer
 #0 0x0000555c136a5e06 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4087e06)
 #1 0x0000555c136a387e llvm::sys::RunSignalHandlers() (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x408587e)
 #2 0x0000555c1361e6ed CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007f3fbb0f0770 (/usr/lib/libc.so.6+0x3c770)
 #4 0x0000555c131e1727 llvm::Operator::hasPoisonGeneratingFlags() const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3bc3727)
 #5 0x0000555c131e18e9 llvm::Operator::hasPoisonGeneratingFlagsOrMetadata() const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3bc38e9)
 #6 0x0000555c12a7335f canCreateUndefOrPoison(llvm::Operator const*, UndefPoisonKind, bool) ValueTracking.cpp:0:0
 #7 0x0000555c12a73bca isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
 #8 0x0000555c12a8f0b5 llvm::Use const* std::__find_if_not<llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>>(llvm::Use const*, llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>) ValueTracking.cpp:0:0
 #9 0x0000555c12a73d77 isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
#10 0x0000555c12a8f0b5 llvm::Use const* std::__find_if_not<llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>>(llvm::Use const*, llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>) ValueTracking.cpp:0:0
#11 0x0000555c12a73d77 isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
#12 0x0000555c12a737b7 impliesPoison(llvm::Value const*, llvm::Value const*, unsigned int) ValueTracking.cpp:0:0
#13 0x0000555c137cbfb1 createLogicalOp(llvm::IRBuilderBase&, llvm::Instruction::BinaryOps, llvm::Value*, llvm::Value*, llvm::Twine const&) SimplifyCFG.cpp:0:0
#14 0x0000555c137da5cb (anonymous namespace)::SimplifyCFGOpt::simplifyCondBranch(llvm::BranchInst*, llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>&) SimplifyCFG.cpp:0:0
#15 0x0000555c137c6805 (anonymous namespace)::SimplifyCFGOpt::run(llvm::BasicBlock*) SimplifyCFG.cpp:0:0
#16 0x0000555c137c3923 llvm::simplifyCFG(llvm::BasicBlock*, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&, llvm::ArrayRef<llvm::WeakVH>) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x41a5923)
#17 0x0000555c135b996d iterativelySimplifyCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#18 0x0000555c135b9373 simplifyFunctionCFGImpl(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#19 0x0000555c135b803f simplifyFunctionCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#20 0x0000555c135b7df6 llvm::SimplifyCFGPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3f99df6)
#21 0x0000555c13ecb9ad llvm::detail::PassModel<llvm::Function, llvm::SimplifyCFGPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) BackendUtil.cpp:0:0
#22 0x0000555c131e65e6 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3bc85e6)
#23 0x0000555c1277464d llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) X86CodeGenPassBuilder.cpp:0:0
#24 0x0000555c132858a1 llvm::CGSCCToFunctionPassAdaptor::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3c678a1)
#25 0x0000555c14b2246d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::CGSCCToFunctionPassAdaptor, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilder.cpp:0:0
#26 0x0000555c132805ce llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3c625ce)
#27 0x0000555c14b08b5d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilder.cpp:0:0
#28 0x0000555c13283aed llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3c65aed)
#29 0x0000555c14b232dd llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::DevirtSCCRepeatedPass, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilder.cpp:0:0
#30 0x0000555c1328250d llvm::ModuleToPostOrderCGSCCPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3c6450d)
#31 0x0000555c14b08e0d llvm::detail::PassModel<llvm::Module, llvm::ModuleToPostOrderCGSCCPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilder.cpp:0:0
#32 0x0000555c131e5826 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3bc7826)
#33 0x0000555c14c285ef llvm::ModuleInlinerWrapperPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x560a5ef)
#34 0x0000555c14b0fa3d llvm::detail::PassModel<llvm::Module, llvm::ModuleInlinerWrapperPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilder.cpp:0:0
#35 0x0000555c131e5826 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x3bc7826)
#36 0x0000555c13ec1967 (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>&, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>&, clang::BackendConsumer*) BackendUtil.cpp:0:0
#37 0x0000555c13eb7c20 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4899c20)
#38 0x0000555c13edda31 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x48bfa31)
#39 0x0000555c152f57a9 clang::ParseAST(clang::Sema&, bool, bool) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x5cd77a9)
#40 0x0000555c14351a5d clang::FrontendAction::Execute() (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4d33a5d)
#41 0x0000555c142b949d clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4c9b49d)
#42 0x0000555c1442cc54 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4e0ec54)
#43 0x0000555c11eb9af0 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x289baf0)
#44 0x0000555c11eb63be ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#45 0x0000555c140eb429 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::$_0>(long) Job.cpp:0:0
#46 0x0000555c1361e426 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4000426)
#47 0x0000555c140eaab3 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4accab3)
#48 0x0000555c140a153c clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4a8353c)
#49 0x0000555c140a1a97 clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4a83a97)
#50 0x0000555c140c3819 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x4aa5819)
#51 0x0000555c11eb58ad clang_main(int, char**, llvm::ToolContext const&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x28978ad)
#52 0x0000555c11ec6b76 main (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x28a8b76)
#53 0x00007f3fbb0d9cd0 (/usr/lib/libc.so.6+0x25cd0)
#54 0x00007f3fbb0d9d8a __libc_start_main (/usr/lib/libc.so.6+0x25d8a)
#55 0x0000555c11eb3ca5 _start (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/clang-19+0x2895ca5)
clang: error: clang frontend command failed with exit code 139 (use -v to see invocation)
ClangBuiltLinux clang version 19.0.0git (https://github.com/llvm/llvm-project.git 7d3924cee30a87a51f9dc04ec843ae6bc3d1c90e)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin
clang: note: diagnostic msg: Error generating preprocessed source(s) - no preprocessable inputs.
$ opt -O2 -disable-output reduced.ll
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: opt -O2 -disable-output reduced.ll
 #0 0x000055f4ac43a636 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1e31636)
 #1 0x000055f4ac437f9e llvm::sys::RunSignalHandlers() (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1e2ef9e)
 #2 0x000055f4ac43b074 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f7a8edde770 (/usr/lib/libc.so.6+0x3c770)
 #4 0x000055f4ac5e93e7 llvm::Operator::hasPoisonGeneratingFlags() const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1fe03e7)
 #5 0x000055f4ac5e95a9 llvm::Operator::hasPoisonGeneratingFlagsOrMetadata() const (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1fe05a9)
 #6 0x000055f4ac768d2f canCreateUndefOrPoison(llvm::Operator const*, UndefPoisonKind, bool) ValueTracking.cpp:0:0
 #7 0x000055f4ac76959a isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
 #8 0x000055f4ac7867d5 llvm::Use const* std::__find_if_not<llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>>(llvm::Use const*, llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>) ValueTracking.cpp:0:0
 #9 0x000055f4ac769747 isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
#10 0x000055f4ac7867d5 llvm::Use const* std::__find_if_not<llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>>(llvm::Use const*, llvm::Use const*, __gnu_cxx::__ops::_Iter_pred<isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind)::$_0>) ValueTracking.cpp:0:0
#11 0x000055f4ac769747 isGuaranteedNotToBeUndefOrPoison(llvm::Value const*, llvm::AssumptionCache*, llvm::Instruction const*, llvm::DominatorTree const*, unsigned int, UndefPoisonKind) ValueTracking.cpp:0:0
#12 0x000055f4ac769187 impliesPoison(llvm::Value const*, llvm::Value const*, unsigned int) ValueTracking.cpp:0:0
#13 0x000055f4acae4931 createLogicalOp(llvm::IRBuilderBase&, llvm::Instruction::BinaryOps, llvm::Value*, llvm::Value*, llvm::Twine const&) SimplifyCFG.cpp:0:0
#14 0x000055f4acaf307b (anonymous namespace)::SimplifyCFGOpt::simplifyCondBranch(llvm::BranchInst*, llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>&) SimplifyCFG.cpp:0:0
#15 0x000055f4acaded85 (anonymous namespace)::SimplifyCFGOpt::run(llvm::BasicBlock*) SimplifyCFG.cpp:0:0
#16 0x000055f4acadbea3 llvm::simplifyCFG(llvm::BasicBlock*, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&, llvm::ArrayRef<llvm::WeakVH>) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x24d2ea3)
#17 0x000055f4ad4731fd iterativelySimplifyCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#18 0x000055f4ad472c03 simplifyFunctionCFGImpl(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#19 0x000055f4ad47180f simplifyFunctionCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#20 0x000055f4ad4715c6 llvm::SimplifyCFGPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x2e685c6)
#21 0x000055f4adf2082d llvm::detail::PassModel<llvm::Function, llvm::SimplifyCFGPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilderPipelines.cpp:0:0
#22 0x000055f4ac632d16 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x2029d16)
#23 0x000055f4ada9781d llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) X86CodeGenPassBuilder.cpp:0:0
#24 0x000055f4adce5651 llvm::CGSCCToFunctionPassAdaptor::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x36dc651)
#25 0x000055f4adf2664d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::CGSCCToFunctionPassAdaptor, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilderPipelines.cpp:0:0
#26 0x000055f4adce037e llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x36d737e)
#27 0x000055f4adf3303d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilderPipelines.cpp:0:0
#28 0x000055f4adce389d llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x36da89d)
#29 0x000055f4adf58a1d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::DevirtSCCRepeatedPass, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) Inliner.cpp:0:0
#30 0x000055f4adce22bd llvm::ModuleToPostOrderCGSCCPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x36d92bd)
#31 0x000055f4adf290bd llvm::detail::PassModel<llvm::Module, llvm::ModuleToPostOrderCGSCCPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilderPipelines.cpp:0:0
#32 0x000055f4ac6317f6 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x20287f6)
#33 0x000055f4adf5577f llvm::ModuleInlinerWrapperPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x394c77f)
#34 0x000055f4adf26a7d llvm::detail::PassModel<llvm::Module, llvm::ModuleInlinerWrapperPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilderPipelines.cpp:0:0
#35 0x000055f4ac6317f6 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x20287f6)
#36 0x000055f4adeb5914 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x38ac914)
#37 0x000055f4ac3ffa45 optMain (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1df6a45)
#38 0x00007f7a8edc7cd0 (/usr/lib/libc.so.6+0x25cd0)
#39 0x00007f7a8edc7d8a __libc_start_main (/usr/lib/libc.so.6+0x25d8a)
#40 0x000055f4ac3f92e5 _start (/home/nathan/tmp/cvise.RCofO58saD/install/llvm-bad/bin/opt+0x1df02e5)

nathanchance avatar Mar 29 '24 22:03 nathanchance

I bisected a crash that I see when building the Linux kernel for arm64 to this change.

@dtcxzyw, Any idea about what may cause this?

elhewaty avatar Mar 30 '24 13:03 elhewaty

@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:

antoniofrighetto avatar Mar 30 '24 13:03 antoniofrighetto

found a semantically important typo: https://github.com/llvm/llvm-project/pull/87285

programmerjake avatar Apr 01 '24 22:04 programmerjake

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

dtcxzyw avatar Apr 04 '24 08:04 dtcxzyw

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

  • [x] Add nowrap flags
  • [x] Fix unexpected crashes
  • [ ] Lower the nowrap flags to SDAG
  • [x] Add the support for dropping nsw/nuw flags to llvm-reduce
  • [x] 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?

elhewaty avatar Apr 05 '24 01:04 elhewaty

  • [ ] 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

arsenm avatar Apr 06 '24 19:04 arsenm

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

XChy avatar Apr 07 '24 10:04 XChy

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

dtcxzyw avatar Apr 19 '24 06:04 dtcxzyw