|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | 
|  | ; RUN: opt -S -passes=early-cse -earlycse-debug-hash < %s | FileCheck %s | 
|  |  | 
|  | ; While it is normally okay to do memory optimizations over calls to | 
|  | ; @readonly_function and @readnone_function, we cannot do that if | 
|  | ; they're carrying unknown operand bundles since the presence of | 
|  | ; unknown operand bundles implies arbitrary memory effects. | 
|  |  | 
|  | declare void @readonly_function() readonly nounwind willreturn | 
|  | declare void @readnone_function() readnone nounwind willreturn | 
|  |  | 
|  | define i32 @test0(ptr %x) { | 
|  | ; CHECK-LABEL: @test0( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 100, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    call void @readonly_function() [ "tag"() ] | 
|  | ; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[X]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 [[V]] | 
|  | ; | 
|  | entry: | 
|  | store i32 100, ptr %x | 
|  | call void @readonly_function() [ "tag"() ] | 
|  |  | 
|  | %v = load i32, ptr %x | 
|  | ret i32 %v | 
|  | } | 
|  |  | 
|  | define i32 @test1(ptr %x) { | 
|  | ; CHECK-LABEL: @test1( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 100, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 100 | 
|  | ; | 
|  | entry: | 
|  | store i32 100, ptr %x | 
|  | call void @readonly_function() readonly [ "tag"() ] | 
|  | %v = load i32, ptr %x | 
|  | ret i32 %v | 
|  | } | 
|  |  | 
|  | define i32 @test3(ptr %x) { | 
|  | ; CHECK-LABEL: @test3( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 100, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 100 | 
|  | ; | 
|  | entry: | 
|  | store i32 100, ptr %x | 
|  | call void @readonly_function() | 
|  | %v = load i32, ptr %x | 
|  | ret i32 %v | 
|  | } | 
|  |  | 
|  | define void @test4(ptr %x) { | 
|  | ; CHECK-LABEL: @test4( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 100, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    call void @readnone_function() [ "tag"() ] | 
|  | ; CHECK-NEXT:    store i32 200, ptr [[X]], align 4 | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | store i32 100, ptr %x | 
|  | call void @readnone_function() [ "tag"() ] | 
|  | store i32 200, ptr %x | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test5(ptr %x) { | 
|  | ; CHECK-LABEL: @test5( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 200, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | store i32 100, ptr %x | 
|  | call void @readnone_function() readnone [ "tag"() ] | 
|  | store i32 200, ptr %x | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test6(ptr %x) { | 
|  | ; The "deopt" operand bundle does not make the call to | 
|  | ; @readonly_function read-write; and so the nounwind readonly call can | 
|  | ; be deleted. | 
|  | ; CHECK-LABEL: @test6( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    store i32 200, ptr [[X:%.*]], align 4 | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  |  | 
|  | store i32 100, ptr %x | 
|  | call void @readonly_function() [ "deopt"() ] | 
|  | store i32 200, ptr %x | 
|  | ret void | 
|  | } |