struct ObjectSizeOpts {
/// Controls how we handle conditional statements with unknown conditions.
enum class Mode : uint8_t {
- /// Fail to evaluate an unknown condition.
- Exact,
+ /// All branches must be known and have the same size, starting from the
+ /// offset, to be merged.
+ ExactSizeFromOffset,
+ /// All branches must be known and have the same underlying size and offset
+ /// to be merged.
+ ExactUnderlyingSizeAndOffset,
/// Evaluate all branches of an unknown condition. If all evaluations
/// succeed, pick the minimum size.
Min,
/// Same as Min, except we pick the maximum size of all of the branches.
- Max
+ Max,
};
/// How we want to evaluate this object's size.
- Mode EvalMode = Mode::Exact;
+ Mode EvalMode = Mode::ExactSizeFromOffset;
/// Whether to round the result up to the alignment of allocas, byval
/// arguments, and global variables.
bool RoundToAlign = false;
EvalOptions.EvalMode =
MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min;
else
- EvalOptions.EvalMode = ObjectSizeOpts::Mode::Exact;
+ EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset;
EvalOptions.NullIsUnknownSize =
cast<ConstantInt>(ObjectSize->getArgOperand(2))->isOne();
return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
case ObjectSizeOpts::Mode::Max:
return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
- case ObjectSizeOpts::Mode::Exact:
+ case ObjectSizeOpts::Mode::ExactSizeFromOffset:
return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) ? LHS
: unknown();
+ case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset:
+ return LHS == RHS && LHS.second.eq(RHS.second) ? LHS : unknown();
}
llvm_unreachable("missing an eval mode");
}
}
; Check that merging sizes in a phi works.
-; FIXME: bounds-checking thinks that %alloc has an underlying size of 0.
define i8 @f14(i1 %i) {
; CHECK-LABEL: @f14(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[A]], i32 32
; CHECK-NEXT: br label [[BB2]]
; CHECK: bb2:
-; CHECK-NEXT: [[ALLOC:%.*]] = phi ptr [ null, [[ENTRY:%.*]] ], [ [[G]], [[BB1]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 32, [[BB1]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ 32, [[BB1]] ]
+; CHECK-NEXT: [[ALLOC:%.*]] = phi ptr [ null, [[ENTRY]] ], [ [[G]], [[BB1]] ]
; CHECK-NEXT: [[IND:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ -4, [[BB1]] ]
-; CHECK-NEXT: [[TMP0:%.*]] = add i64 0, [[IND]]
+; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[IND]]
; CHECK-NEXT: [[P:%.*]] = getelementptr i8, ptr [[ALLOC]], i64 [[IND]]
-; CHECK-NEXT: [[TMP1:%.*]] = sub i64 0, [[TMP0]]
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 0, [[TMP0]]
-; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i64 [[TMP1]], 1
-; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[TMP2]], [[TMP3]]
-; CHECK-NEXT: br i1 [[TMP4]], label [[TRAP:%.*]], label [[TMP5:%.*]]
-; CHECK: 5:
+; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i64 [[TMP3]], 1
+; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP4]], [[TMP5]]
+; CHECK-NEXT: br i1 [[TMP6]], label [[TRAP:%.*]], label [[TMP7:%.*]]
+; CHECK: 7:
; CHECK-NEXT: [[RET:%.*]] = load i8, ptr [[P]], align 1
; CHECK-NEXT: ret i8 [[RET]]
; CHECK: trap: