Files
swift-mirror/test/SILOptimizer/access_dom.sil
Erik Eckstein 7cceaff5f3 SIL: don't print operand types in textual SIL
Type annotations for instruction operands are omitted, e.g.

```
  %3 = struct $S(%1, %2)
```

Operand types are redundant anyway and were only used for sanity checking in the SIL parser.

But: operand types _are_ printed if the definition of the operand value was not printed yet.
This happens:

* if the block with the definition appears after the block where the operand's instruction is located

* if a block or instruction is printed in isolation, e.g. in a debugger

The old behavior can be restored with `-Xllvm -sil-print-types`.
This option is added to many existing test files which check for operand types in their check-lines.
2024-11-21 18:49:52 +01:00

557 lines
19 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// RUN: %target-sil-opt -sil-print-types -access-enforcement-dom %s -enable-sil-verify-all | %FileCheck %s
//
// Test the AccessEnforcementDom pass in isolation. This ensures that
// no upstream passes have removed SIL-level access markers that are
// required to ensure the pass is not overly optimistic.
sil_stage canonical
import Builtin
import Swift
import SwiftShims
struct X {
@_hasStorage var i: Int64 { get set }
init(i: Int64)
init()
}
var globalX: X
var globalOtherX: X
sil_global hidden @globalX : $X
sil_global hidden @globalOtherX : $X
sil hidden @Xinit : $@convention(method) (@thin X.Type) -> X {
bb0(%0 : $@thin X.Type):
%1 = alloc_stack $X, var, name "self"
%2 = integer_literal $Builtin.Int64, 7
%3 = struct $Int64 (%2 : $Builtin.Int64)
%4 = struct_element_addr %1 : $*X, #X.i
store %3 to %4 : $*Int64
%6 = struct $X (%3 : $Int64)
dealloc_stack %1 : $*X
return %6 : $X
}
// public func testDomSimpleRead() {
// Checks 3 scopes, two of which are dominated and access the same storage
//
// CHECK-LABEL: sil @testDomSimpleRead : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testDomSimpleRead'
sil @testDomSimpleRead : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [read] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
%4 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%7 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%8 = load %7 : $*X
end_access %7 : $*X
%10 = tuple ()
return %10 : $()
}
// public func testDomSimpleWrite() {
// Checks 3 scopes, two of which are dominated and access the same storage
//
// CHECK-LABEL: sil @testDomSimpleWrite : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK: [[BEGIN:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK: store {{.*}} to [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testDomSimpleWrite'
sil @testDomSimpleWrite : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [modify] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
%4 = metatype $@thin X.Type
// function_ref X.init()
%5 = function_ref @Xinit : $@convention(method) (@thin X.Type) -> X
%6 = apply %5(%4) : $@convention(method) (@thin X.Type) -> X
%7 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
store %6 to %7 : $*X
end_access %7 : $*X
%10 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%11 = load %10 : $*X
end_access %10 : $*X
%12 = tuple ()
return %12 : $()
}
// public func testDomAcrossBBs() {
// Checks static-setting of scopes across basic blocks
//
// CHECK-LABEL: sil @testDomAcrossBBs : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: br bb1
// CHECK: br bb2
// CHECK: bb2:
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testDomAcrossBBs'
sil @testDomAcrossBBs : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [modify] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
br bb1
bb1:
br bb2
bb2:
%4 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%7 = tuple ()
return %7 : $()
}
// public func testDomAcrossInnerLoop() {
// Checksstatic-setting of scopes across an inner loop
//
// CHECK-LABEL: sil @testDomAcrossInnerLoop : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: br bb1
// CHECK: cond_br {{.*}}, bb1, bb2
// CHECK: bb2:
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testDomAcrossInnerLoop'
sil @testDomAcrossInnerLoop : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [modify] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
br bb1
bb1:
%cond = integer_literal $Builtin.Int1, 1
cond_br %cond, bb1, bb2
bb2:
%4 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%7 = tuple ()
return %7 : $()
}
// public func testIrreducibleGraph() {
// Checks domination in an irreducible control flow
//
// CHECK-LABEL: sil @testIrreducibleGraph : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: br bb1
// CHECK: [[BEGIN2:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb3
// CHECK: [[BEGIN3:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN3]] : $*X
// CHECK-NEXT: end_access [[BEGIN3]] : $*X
// CHECK: cond_br {{.*}}, bb3, bb4
// CHECK: [[BEGIN4:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN4]] : $*X
// CHECK-NEXT: end_access [[BEGIN4]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb1
// CHECK: [[BEGIN5:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN5]] : $*X
// CHECK-NEXT: end_access [[BEGIN5]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testIrreducibleGraph'
sil @testIrreducibleGraph : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [read] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
br bb1
bb1:
%4 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%cond1 = integer_literal $Builtin.Int1, 1
cond_br %cond1, bb2, bb3
bb2:
%6 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%7 = load %6 : $*X
end_access %6 : $*X
%cond2 = integer_literal $Builtin.Int1, 1
cond_br %cond2, bb3, bb4
bb3:
%8 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%9 = load %8 : $*X
end_access %8 : $*X
%cond3 = integer_literal $Builtin.Int1, 1
cond_br %cond3, bb2, bb1
bb4:
%10 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%11 = load %10 : $*X
end_access %10 : $*X
%12 = tuple ()
return %12 : $()
}
// public func testIrreducibleGraph2() {
// Checks detection of irreducible control flow / bail for *some* of them
//
// CHECK-LABEL: sil @testIrreducibleGraph2 : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: br bb1
// CHECK: cond_br {{.*}}, bb2, bb3
// CHECK: bb2:
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK: [[BEGIN3:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN3]] : $*X
// CHECK-NEXT: end_access [[BEGIN3]] : $*X
// CHECK: br bb4
// CHECK: [[BEGIN4:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN4]] : $*X
// CHECK-NEXT: end_access [[BEGIN4]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb5
// CHECK: [[BEGIN5:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN5]] : $*X
// CHECK-NEXT: end_access [[BEGIN5]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testIrreducibleGraph2'
sil @testIrreducibleGraph2 : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
br bb1
bb1:
%cond1 = integer_literal $Builtin.Int1, 1
cond_br %cond1, bb2, bb3
bb2:
%6 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%7 = load %6 : $*X
end_access %6 : $*X
br bb3
bb3:
%8 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%9 = load %8 : $*X
end_access %8 : $*X
br bb4
bb4:
%10 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%11 = load %10 : $*X
end_access %10 : $*X
%cond2 = integer_literal $Builtin.Int1, 1
cond_br %cond2, bb2, bb5
bb5:
%13 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%14 = load %13 : $*X
end_access %13 : $*X
%16 = tuple ()
return %16 : $()
}
// public func testDomUnpaired() {
// Checks 3 scopes, two of which are dominated and access the same storage
// However, The second access is unpaired - we cant optimized
//
// CHECK-LABEL: sil @testDomUnpaired : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NEXT: [[ALLOC:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
// CHECK-NEXT: begin_unpaired_access [read] [dynamic] [[GLOBAL]] : $*X, [[ALLOC]] : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: end_unpaired_access [dynamic] [[ALLOC]] : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK-NOT: begin_access
// CHECK-LABEL: } // end sil function 'testDomUnpaired'
sil @testDomUnpaired : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [read] [dynamic] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
%buffer = alloc_stack $Builtin.UnsafeValueBuffer
begin_unpaired_access [read] [dynamic] %0 : $*X, %buffer : $*Builtin.UnsafeValueBuffer
end_unpaired_access [dynamic] %buffer : $*Builtin.UnsafeValueBuffer
%7 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%8 = load %7 : $*X
end_access %7 : $*X
dealloc_stack %buffer : $*Builtin.UnsafeValueBuffer
%10 = tuple ()
return %10 : $()
}
// public func testLoopDominatingAccessAdderSimple() {
// Checks creation of new scope in loop preheader
//
// CHECK-LABEL: sil @testLoopDominatingAccessAdderSimple : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: bb1:
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK: bb3:
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb4
// CHECK-LABEL: } // end sil function 'testLoopDominatingAccessAdderSimple'
sil @testLoopDominatingAccessAdderSimple : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
br bb1
bb1:
br bb2
bb2:
br bb3
bb3:
%4 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%cond = integer_literal $Builtin.Int1, 1
cond_br %cond, bb2, bb4
bb4:
%10 = tuple ()
return %10 : $()
}
// public func testLoopDominatingAccessAdderBailSimple() {
// Checks bailing on the creation of new scope in loop preheader if the access has a nested conflict
//
// CHECK-LABEL: sil @testLoopDominatingAccessAdderBailSimple : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: bb1:
// CHECK-NEXT: br bb2
// CHECK: bb3:
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb4
// CHECK-LABEL: } // end sil function 'testLoopDominatingAccessAdderBailSimple'
sil @testLoopDominatingAccessAdderBailSimple : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
br bb1
bb1:
br bb2
bb2:
br bb3
bb3:
%4 = begin_access [read] [dynamic] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%cond = integer_literal $Builtin.Int1, 1
cond_br %cond, bb2, bb4
bb4:
%10 = tuple ()
return %10 : $()
}
// public func testLoopDominatingAccessAdderMulti() {
// Checks creation of a single new scope in loop preheader if we have multi-access in loop
//
// CHECK-LABEL: sil @testLoopDominatingAccessAdderMulti : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: bb1:
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK: bb3:
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK: [[BEGIN3:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN3]] : $*X
// CHECK-NEXT: end_access [[BEGIN3]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb4
// CHECK-LABEL: } // end sil function 'testLoopDominatingAccessAdderMulti'
sil @testLoopDominatingAccessAdderMulti : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
br bb1
bb1:
br bb2
bb2:
br bb3
bb3:
%4 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%6 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%7 = load %6 : $*X
end_access %6 : $*X
%cond = integer_literal $Builtin.Int1, 1
cond_br %cond, bb2, bb4
bb4:
%10 = tuple ()
return %10 : $()
}
// public func testLoopDominatingAccessAdderMultiChangeKind() {
// Checks creation of a single new scope in loop preheader with [modify]
// if one of the accesses changes the kind we first encounter
//
// CHECK-LABEL: sil @testLoopDominatingAccessAdderMultiChangeKind : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: bb1:
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: end_access [[BEGIN]] : $*X
// CHECK: bb3:
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN2]] : $*X
// CHECK-NEXT: end_access [[BEGIN2]] : $*X
// CHECK: [[BEGIN3:%.*]] = begin_access [modify] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN3]] : $*X
// CHECK-NEXT: end_access [[BEGIN3]] : $*X
// CHECK: [[BEGIN4:%.*]] = begin_access [read] [static] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-NEXT: load [[BEGIN4]] : $*X
// CHECK-NEXT: end_access [[BEGIN4]] : $*X
// CHECK: cond_br {{.*}}, bb2, bb4
// CHECK-LABEL: } // end sil function 'testLoopDominatingAccessAdderMultiChangeKind'
sil @testLoopDominatingAccessAdderMultiChangeKind : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
br bb1
bb1:
br bb2
bb2:
br bb3
bb3:
%4 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%5 = load %4 : $*X
end_access %4 : $*X
%6 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
%7 = load %6 : $*X
end_access %6 : $*X
%8 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%9 = load %8 : $*X
end_access %8 : $*X
%cond = integer_literal $Builtin.Int1, 1
cond_br %cond, bb2, bb4
bb4:
%10 = tuple ()
return %10 : $()
}
// public func testBailOnNestedDomWrite() {
// Checks that we bail when the dominated begin comes before the dominating begin
//
// CHECK-LABEL: sil @testBailOnNestedDomWrite : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: [[BEGIN:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*X
// CHECK: [[BEGIN2:%.*]] = begin_access [modify] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-LABEL: } // end sil function 'testBailOnNestedDomWrite'
sil @testBailOnNestedDomWrite : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%4 = begin_access [modify] [dynamic] %0 : $*X
%5 = load %4 : $*X
%7 = begin_access [modify] [dynamic] [no_nested_conflict] %0 : $*X
%8 = load %7 : $*X
end_access %7 : $*X
end_access %4 : $*X
%10 = tuple ()
return %10 : $()
}
// public func testOptOnNestedDomRead() {
//
// Bail on a nested access. The dominator-based algorithm does not
// remove nested access scopes because those could generally be
// conflicts. This one just happens to be a read-read, so it isn't a real
// conflict.
//
// FIXME: simple nested dynamic reads to identical storage could very
// easily be removed via separate logic, but it does not fit with the
// dominator-based algorithm. For example, during the analysis phase, we
// could simply mark the "fully nested" read scopes, then convert them to
// [static] right after the analysis, removing them from the result
// map. I didn't do this because I don't know if it happens in practice.
//
// CHECK-LABEL: sil @testOptOnNestedDomRead : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
// CHECK: [[BEGIN:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*X
// CHECK: [[BEGIN2:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
// CHECK-LABEL: } // end sil function 'testOptOnNestedDomRead'
sil @testOptOnNestedDomRead : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%4 = begin_access [read] [dynamic] %0 : $*X
%5 = load %4 : $*X
%7 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%8 = load %7 : $*X
end_access %7 : $*X
end_access %4 : $*X
%10 = tuple ()
return %10 : $()
}