Skip to content

Commit 27dc031

Browse files
committed
IRGen: better code generation for the _assumeNonNegative intrinsic
So far we only supported this for `load` and `call` arguments. Now we use `llvm.assume` for other kind of argument values. This helps optimizing bounds checking for `Span`.
1 parent b540204 commit 27dc031

File tree

3 files changed

+16
-16
lines changed

3 files changed

+16
-16
lines changed

lib/IRGen/GenBuiltin.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,8 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
600600
}
601601
if (Builtin.ID == BuiltinValueKind::AssumeNonNegative) {
602602
llvm::Value *v = args.claimNext();
603-
// Set a value range on the load instruction, which must be the argument of
604-
// the builtin.
603+
// If the argument is a `load` or `call` we can use a range metadata to
604+
// specify the >= 0 constraint.
605605
if (isa<llvm::LoadInst>(v) || isa<llvm::CallInst>(v)) {
606606
// The load must be post-dominated by the builtin. Otherwise we would get
607607
// a wrong assumption in the else-branch in this example:
@@ -626,6 +626,10 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
626626
llvm::MDNode *range = llvm::MDNode::get(ctx, rangeElems);
627627
I->setMetadata(llvm::LLVMContext::MD_range, range);
628628
}
629+
} else {
630+
// Otherwise, we specify the constraint with an `llvm.assume` intrinsic.
631+
auto *cmp = IGF.Builder.CreateICmpSGE(v, llvm::ConstantInt::get(v->getType(), 0));
632+
IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::assume, cmp);
629633
}
630634
// Don't generate any code for the builtin.
631635
return out.add(v);

test/IRGen/builtins.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,13 @@ func assumeNonNegative_test2(_ x: Builtin.Word) -> Builtin.Word {
646646
return Builtin.assumeNonNegative_Word(return_word(x))
647647
}
648648

649+
// CHECK-LABEL: define hidden {{.*}}@"$s8builtins23assumeNonNegative_test3yBwBwF"
650+
func assumeNonNegative_test3(_ x: Builtin.Word) -> Builtin.Word {
651+
// CHECK: [[C:%.*]] = icmp sge i{{[0-9]+}} %0, 0
652+
// CHECK: call void @llvm.assume(i1 [[C]])
653+
return Builtin.assumeNonNegative_Word(x)
654+
}
655+
649656
struct Empty {}
650657
struct Pair { var i: Int, b: Bool }
651658

test/SILOptimizer/span_bounds_check_tests.swift

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public func span_sum_iterate_to_count_wo_trap(_ v: Span<Int>) -> Int {
2828
for i in 0..<v.count {
2929
sum &+= v[i]
3030
}
31-
return sum
31+
return sum &+ 1 // adding 1 to avoid LLVM function merging
3232
}
3333

3434
// Bounds check should be eliminated
@@ -175,15 +175,10 @@ public func span_sum_iterate_to_deducible_count2_with_trap(_ v: Span<Int>, _ n:
175175
}
176176

177177
// Bounds check should be eliminated
178-
// SIL optimizer hoists bounds checks from the loop
178+
// TODO: there should not be any cond_fail in this function
179179

180180
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF :
181-
// CHECK-SIL: bb1
182-
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
183-
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
184-
// CHECK-SIL: bb3
185181
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
186-
// CHECK-SIL: cond_br
187182
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF'
188183

189184
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF"
@@ -200,12 +195,7 @@ public func span_iterate_over_indices_wo_trap(_ v: Span<Int>) -> Int {
200195
// SIL optimizer hoists bounds checks from the loop
201196

202197
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A31_iterate_over_indices_with_trapySis4SpanVySiGF :
203-
// CHECK-SIL: bb1
204-
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
205-
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
206-
// CHECK-SIL: bb3
207198
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
208-
// CHECK-SIL: cond_br
209199
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A31_iterate_over_indices_with_trapySis4SpanVySiGF'
210200
public func span_iterate_over_indices_with_trap(_ v: Span<Int>) -> Int {
211201
var sum = 0
@@ -254,12 +244,11 @@ public func span_search<T : Equatable>(_ v: Span<T>, _ elem: T) -> Int? {
254244
return nil
255245
}
256246

257-
// Bounds check should be eliminated
247+
// TODO: Bounds check should be eliminated
258248

259249
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A11_search_splySiSgs4SpanVySiG_SitF :
260250
// CHECK-SIL: bb3:
261251
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
262-
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
263252
// CHECK-SIL: cond_br
264253
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A11_search_splySiSgs4SpanVySiG_SitF'
265254
public func span_search_spl(_ v: Span<Int>, _ elem: Int) -> Int? {

0 commit comments

Comments
 (0)