Depends on D116935.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D116968
/// values. Also applies target-specific constant folding when not using
/// InstructionSimplify.
class InstSimplifyFolder final : public IRBuilderFolder {
- const DataLayout &DL;
TargetFolder ConstFolder;
+ SimplifyQuery SQ;
virtual void anchor();
public:
- InstSimplifyFolder(const DataLayout &DL) : DL(DL), ConstFolder(DL) {}
+ InstSimplifyFolder(const DataLayout &DL) : ConstFolder(DL), SQ(DL) {}
//===--------------------------------------------------------------------===//
// Value-based folders.
// Return an existing value or a constant if the operation can be simplified.
// Otherwise return nullptr.
//===--------------------------------------------------------------------===//
+ Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
+ bool HasNSW = false) const override {
+ return SimplifyAddInst(LHS, RHS, HasNUW, HasNSW, SQ);
+ }
+
Value *FoldOr(Value *LHS, Value *RHS) const override {
- return SimplifyOrInst(LHS, RHS, SimplifyQuery(DL));
+ return SimplifyOrInst(LHS, RHS, SQ);
}
//===--------------------------------------------------------------------===//
// Binary Operators
//===--------------------------------------------------------------------===//
- Value *CreateAdd(Constant *LHS, Constant *RHS, bool HasNUW = false,
- bool HasNSW = false) const override {
- return ConstFolder.CreateAdd(LHS, RHS, HasNUW, HasNSW);
- }
Value *CreateFAdd(Constant *LHS, Constant *RHS) const override {
return ConstFolder.CreateFAdd(LHS, RHS);
}
// Return an existing value or a constant if the operation can be simplified.
// Otherwise return nullptr.
//===--------------------------------------------------------------------===//
+ Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
+ bool HasNSW = false) const override {
+ auto *LC = dyn_cast<Constant>(LHS);
+ auto *RC = dyn_cast<Constant>(RHS);
+ if (LC && RC)
+ return Fold(ConstantExpr::getAdd(LC, RC, HasNUW, HasNSW));
+ return nullptr;
+ }
+
Value *FoldOr(Value *LHS, Value *RHS) const override {
auto *LC = dyn_cast<Constant>(LHS);
auto *RC = dyn_cast<Constant>(RHS);
// Binary Operators
//===--------------------------------------------------------------------===//
- Constant *CreateAdd(Constant *LHS, Constant *RHS,
- bool HasNUW = false, bool HasNSW = false) const override {
- return Fold(ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW));
- }
Constant *CreateFAdd(Constant *LHS, Constant *RHS) const override {
return Fold(ConstantExpr::getFAdd(LHS, RHS));
}
// Return an existing value or a constant if the operation can be simplified.
// Otherwise return nullptr.
//===--------------------------------------------------------------------===//
+ Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
+ bool HasNSW = false) const override {
+ auto *LC = dyn_cast<Constant>(LHS);
+ auto *RC = dyn_cast<Constant>(RHS);
+ if (LC && RC)
+ return ConstantExpr::getAdd(LC, RC, HasNUW, HasNSW);
+ return nullptr;
+ }
+
Value *FoldOr(Value *LHS, Value *RHS) const override {
auto *LC = dyn_cast<Constant>(LHS);
auto *RC = dyn_cast<Constant>(RHS);
// Binary Operators
//===--------------------------------------------------------------------===//
- Constant *CreateAdd(Constant *LHS, Constant *RHS,
- bool HasNUW = false, bool HasNSW = false) const override {
- return ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW);
- }
-
Constant *CreateFAdd(Constant *LHS, Constant *RHS) const override {
return ConstantExpr::getFAdd(LHS, RHS);
}
public:
Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "",
bool HasNUW = false, bool HasNSW = false) {
- if (auto *LC = dyn_cast<Constant>(LHS))
- if (auto *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateAdd(LC, RC, HasNUW, HasNSW), Name);
+ if (auto *V = Folder.FoldAdd(LHS, RHS, HasNUW, HasNSW))
+ return V;
return CreateInsertNUWNSWBinOp(Instruction::Add, LHS, RHS, Name,
HasNUW, HasNSW);
}
// Return an existing value or a constant if the operation can be simplified.
// Otherwise return nullptr.
//===--------------------------------------------------------------------===//
+ virtual Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
+ bool HasNSW = false) const = 0;
virtual Value *FoldOr(Value *LHS, Value *RHS) const = 0;
//===--------------------------------------------------------------------===//
// Binary Operators
//===--------------------------------------------------------------------===//
- virtual Value *CreateAdd(Constant *LHS, Constant *RHS,
- bool HasNUW = false, bool HasNSW = false) const = 0;
virtual Value *CreateFAdd(Constant *LHS, Constant *RHS) const = 0;
virtual Value *CreateSub(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const = 0;
// Return an existing value or a constant if the operation can be simplified.
// Otherwise return nullptr.
//===--------------------------------------------------------------------===//
+ Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
+ bool HasNSW = false) const override {
+ return nullptr;
+ }
+
Value *FoldOr(Value *LHS, Value *RHS) const override { return nullptr; }
//===--------------------------------------------------------------------===//
// Binary Operators
//===--------------------------------------------------------------------===//
- Instruction *CreateAdd(Constant *LHS, Constant *RHS,
- bool HasNUW = false,
- bool HasNSW = false) const override {
- BinaryOperator *BO = BinaryOperator::CreateAdd(LHS, RHS);
- if (HasNUW) BO->setHasNoUnsignedWrap();
- if (HasNSW) BO->setHasNoSignedWrap();
- return BO;
- }
-
Instruction *CreateFAdd(Constant *LHS, Constant *RHS) const override {
return BinaryOperator::CreateFAdd(LHS, RHS);
}
; CHECK: vector.scevcheck:
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N]], i32 1)
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 0, [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP1]], 0
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP4]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[UMAX1]], 4
; CHECK: vector.scevcheck:
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N]], i32 1)
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 0, [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP1]], 0
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP4]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[UMAX1]], 4
; CHECK: vector.scevcheck:
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[K]], -1
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i32
-; CHECK-NEXT: [[TMP2:%.*]] = add i32 0, [[TMP1]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP2]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[TMP0]], 4294967295
; CHECK-NEXT: [[TMP8:%.*]] = or i1 [[TMP5]], [[TMP7]]
; CHECK-NEXT: br i1 [[TMP8]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; UNROLL-NO-IC: vector.scevcheck:
; UNROLL-NO-IC-NEXT: [[TMP0:%.*]] = add i64 [[K]], -1
; UNROLL-NO-IC-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i32
-; UNROLL-NO-IC-NEXT: [[TMP2:%.*]] = add i32 0, [[TMP1]]
-; UNROLL-NO-IC-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP2]], 0
+; UNROLL-NO-IC-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
; UNROLL-NO-IC-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[TMP0]], 4294967295
; UNROLL-NO-IC-NEXT: [[TMP8:%.*]] = or i1 [[TMP5]], [[TMP7]]
; UNROLL-NO-IC-NEXT: br i1 [[TMP8]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[TMP4]], i8 [[TMP5]])
; CHECK-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0
; CHECK-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1
-; CHECK-NEXT: [[TMP6:%.*]] = add i8 0, [[MUL_RESULT]]
; CHECK-NEXT: [[TMP7:%.*]] = sub i8 0, [[MUL_RESULT]]
-; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP6]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[MUL_RESULT]], 0
; CHECK-NEXT: [[TMP9:%.*]] = icmp sgt i8 [[TMP7]], 0
; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP3]], i1 [[TMP9]], i1 [[TMP8]]
; CHECK-NEXT: [[TMP14:%.*]] = or i1 [[TMP10]], [[MUL_OVERFLOW]]
; UNROLL-NO-IC-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[TMP4]], i8 [[TMP5]])
; UNROLL-NO-IC-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0
; UNROLL-NO-IC-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1
-; UNROLL-NO-IC-NEXT: [[TMP6:%.*]] = add i8 0, [[MUL_RESULT]]
; UNROLL-NO-IC-NEXT: [[TMP7:%.*]] = sub i8 0, [[MUL_RESULT]]
-; UNROLL-NO-IC-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP6]], 0
+; UNROLL-NO-IC-NEXT: [[TMP8:%.*]] = icmp slt i8 [[MUL_RESULT]], 0
; UNROLL-NO-IC-NEXT: [[TMP9:%.*]] = icmp sgt i8 [[TMP7]], 0
; UNROLL-NO-IC-NEXT: [[TMP10:%.*]] = select i1 [[TMP3]], i1 [[TMP9]], i1 [[TMP8]]
; UNROLL-NO-IC-NEXT: [[TMP14:%.*]] = or i1 [[TMP10]], [[MUL_OVERFLOW]]
; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[TMP4]], i8 [[TMP5]])
; CHECK-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0
; CHECK-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1
-; CHECK-NEXT: [[TMP6:%.*]] = add i8 0, [[MUL_RESULT]]
; CHECK-NEXT: [[TMP7:%.*]] = sub i8 0, [[MUL_RESULT]]
-; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP6]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[MUL_RESULT]], 0
; CHECK-NEXT: [[TMP9:%.*]] = icmp sgt i8 [[TMP7]], 0
; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP3]], i1 [[TMP9]], i1 [[TMP8]]
; CHECK-NEXT: [[TMP14:%.*]] = or i1 [[TMP10]], [[MUL_OVERFLOW]]
; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[TMP4]], i8 [[TMP5]])
; CHECK-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0
; CHECK-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1
-; CHECK-NEXT: [[TMP6:%.*]] = add i8 0, [[MUL_RESULT]]
; CHECK-NEXT: [[TMP7:%.*]] = sub i8 0, [[MUL_RESULT]]
-; CHECK-NEXT: [[TMP8:%.*]] = icmp ult i8 [[TMP6]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ult i8 [[MUL_RESULT]], 0
; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i8 [[TMP7]], 0
; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP3]], i1 [[TMP9]], i1 [[TMP8]]
; CHECK-NEXT: [[TMP14:%.*]] = or i1 [[TMP10]], [[MUL_OVERFLOW]]
; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[TMP3]], i8 [[TMP4]])
; CHECK-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0
; CHECK-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1
-; CHECK-NEXT: [[TMP5:%.*]] = add i8 0, [[MUL_RESULT]]
; CHECK-NEXT: [[TMP6:%.*]] = sub i8 0, [[MUL_RESULT]]
-; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i8 [[TMP5]], 0
+; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i8 [[MUL_RESULT]], 0
; CHECK-NEXT: [[TMP8:%.*]] = icmp sgt i8 [[TMP6]], 0
; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[TMP2]], i1 [[TMP8]], i1 [[TMP7]]
; CHECK-NEXT: [[TMP13:%.*]] = or i1 [[TMP9]], [[MUL_OVERFLOW]]
; LV-NEXT: [[MUL1:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 2, i32 [[TMP1]])
; LV-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i32, i1 } [[MUL1]], 0
; LV-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i32, i1 } [[MUL1]], 1
-; LV-NEXT: [[TMP2:%.*]] = add i32 0, [[MUL_RESULT]]
-; LV-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP2]], 0
+; LV-NEXT: [[TMP5:%.*]] = icmp slt i32 [[MUL_RESULT]], 0
; LV-NEXT: [[TMP8:%.*]] = or i1 [[TMP5]], [[MUL_OVERFLOW]]
; LV-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[TMP0]], 4294967295
; LV-NEXT: [[TMP9:%.*]] = or i1 [[TMP8]], [[TMP7]]