> On Jul 12, 2017, at 9:53 AM, Johannes Weiß <johanneswe...@apple.com> wrote: > > Hi Michael, > > >> [...] >>> Long story short, I think the RLE actually works for the test case I >>> created. It's even clever enough to see through my invalid function bad() >>> which modified the storage despite its claim that it doesn't. I might also >>> be misunderstanding something. >> >> When something is marked as in_guaranteed, it should be immutable. If the >> callee violates that, then the SIL is malformed. Perhaps, we can add some >> sort of verification check. > > Right, yes I was aware that that'd be illegal but I added it as a way to > check whether this optimisation is 'looking into' the called function. > > >> That being said, I have a good feeling that there is some sort of analysis >> occuring here since you provided enough information to the optimizer. The >> optimization here is regardless of whether or not we can see the body of a >> function, we know that it is safe to optimize this just based off the >> @in_guaranteed. This implies using a declaration, not a definition of the >> bad function. > > makes sense, didn't think about just only declaring it... > > >> When I said write the SIL by hand, what I meant was writing the whole >> program by hand. In general, we prefer SIL programs that do not have >> extraneous stuff that is added by the compiler (for instance debug_value). >> Additionally, it is important for SIL files to not have dependencies on the >> stdlib unless absolutely necessary (i.e. your usage of Int). This prevents >> the stdlib maintainers from having to update these tests given chances to >> the stdlib. Below is a cleaned up version that shows the problem. Look at >> how small it is and how it tests /exactly/ what we are trying to test and >> via the use of declarations and the like we are able to exclude other >> optimizations: > > That makes a lot of sense, thank you. I wasn't yet that familiar with SIL so > I thought I start from a program generated by the compiler and then replace > the guts with handwritten SIL. But your version is clearly a lot easier to > understand and shows what precisely we want to see! > > Today, I looked into why this is happening more precisely. > > So we don't get the RLE because in this code > > if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { > for (unsigned i = 0; i < Locs.size(); ++i) { > if (isTrackingLocation(ForwardSetIn, Ctx.getLocationBit(Locs[i]))) > continue; > updateForwardSetAndValForRead(Ctx, Ctx.getLocationBit(Locs[i]), > Ctx.getValueBit(Vals[i])); > // We can not perform the forwarding as we are at least missing > // some pieces of the read location. > CanForward = false; > > (https://github.com/apple/swift/blob/86620aaa7ebd32d33f4cdf61add5c63a72d3f02a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp#L917) > > we're not taking the `continue` for the call to `buz()`. The reason why is > that here > > if (!AA->mayWriteToMemory(I, R.getBase())) > continue; > // MayAlias. > stopTrackingLocation(ForwardSetIn, i); > stopTrackingValue(ForwardValIn, i); > > (https://github.com/apple/swift/blob/86620aaa7ebd32d33f4cdf61add5c63a72d3f02a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp#L972) > > we're not taking the `continue`, ie. `AA->mayWriteToMemory(I, R.getBase())` > is true. The reason for that is that the `SILFunction` for `buz` has > > EffectsKindAttr = Unspecified > > which equates to `MayHaveSideEffects`, that's also what > `-debug-only=sil-redundant-load-elim,sil-membehavior` outputs: > > GET MEMORY BEHAVIOR FOR: > %5 = apply %4(%0) : $@convention(thin) (@in_guaranteed Int) -> () > %0 = argument of bb0 : $*Int // users: %6, %5, %3 > Found apply, returning MayHaveSideEffects > > > So where I'm stuck today is that I'm not sure how `EffectsKindAttr` is > actually defined. Sure, `$@convention(thin) (@in_guaranteed Int) -> ()` > doesn't actually write to the `@in_guaranteed Int` (as that'd be illegal) but > it may have other side effects. So I'm not sure if we can just create the > function differently if we find only "read-only" kind of parameters. That'd > be I think in > > > auto *fn = SILMod.createFunction(SILLinkage::Private, Name.str(), Ty, > nullptr, loc, IsNotBare, > IsNotTransparent, IsNotSerialized); > > (https://github.com/apple/swift/blob/ec6fc4d54db95f78ae72dab29734533f709ea2d7/lib/Parse/ParseSIL.cpp#L508 > -> > https://github.com/apple/swift/blob/157db57506b813837481b574a9d38e806bf954b6/lib/SIL/SILModule.cpp#L249) > > which doesn't specify any EffectsAttrKind and therefore it defaults to > `Unspecified`. > > > Just as a test, I did put a `[readonly]` in `sil @buz : $@convention(thin) > (@in_guaranteed Int) -> ()` and as expected everything propagates through > correctly and we get a successful RLE. > > So yes, maybe you have some pointers on where to best educate the compiler > that the `buz` function won't write to that bit of memory.
I have a few ideas of where to put it, but really the person to bring in here is Erik. He is the one who wrote the side-effect part of the optimizer. Keep in mind he is on vacation right now until next week. So I wouldn't expect a response until then. Michael > > Many thanks, > Johannes > >> >> ---- >> sil_stage canonical >> >> import Builtin >> >> struct Int { >> var _value : Builtin.Int64 >> } >> >> sil @test : $@convention(thin) (Int) -> () >> sil @buz : $@convention(thin) (@in_guaranteed Int) -> () >> sil @bad : $@convention(thin) (@in_guaranteed Int) -> () >> >> sil @bar : $@convention(thin) (@in Int) -> () { >> bb0(%0 : $*Int): >> %value_raw = integer_literal $Builtin.Int64, 42 >> %value = struct $Int (%value_raw : $Builtin.Int64) >> store %value to %0 : $*Int >> >> %f_buz = function_ref @buz : $@convention(thin) (@in_guaranteed Int) -> () >> %r1 = apply %f_buz(%0) : $@convention(thin) (@in_guaranteed Int) -> () >> >> %value_again = load %0 : $*Int >> %f_test = function_ref @test : $@convention(thin) (Int) -> () >> %r2 = apply %f_test(%value_again) : $@convention(thin) (Int) -> () >> >> %f_bad = function_ref @bad : $@convention(thin) (@in_guaranteed Int) -> () >> %r3 = apply %f_bad(%0) : $@convention(thin) (@in_guaranteed Int) -> () >> >> %value_again2 = load %0 : $*Int >> %r4 = apply %f_test(%value_again2) : $@convention(thin) (Int) -> () >> >> %9999 = tuple() >> return %9999 : $() >> } >> ---- >> >> When I run this test file through rle, I get: >> >> ---- >> sil_stage canonical >> >> import Builtin >> import Swift >> import SwiftShims >> >> struct Int { >> @sil_stored var _value: Builtin.Int64 >> init(_value: Builtin.Int64) >> } >> >> // test >> sil @test : $@convention(thin) (Int) -> () >> >> // buz >> sil @buz : $@convention(thin) (@in_guaranteed Int) -> () >> >> // bad >> sil @bad : $@convention(thin) (@in_guaranteed Int) -> () >> >> // bar >> sil @bar : $@convention(thin) (@in Int) -> () { >> // %0 // users: %11, %10, %6, >> %5, %3 >> bb0(%0 : $*Int): >> %1 = integer_literal $Builtin.Int64, 42 // user: %2 >> %2 = struct $Int (%1 : $Builtin.Int64) // user: %3 >> store %2 to %0 : $*Int // id: %3 >> // function_ref buz >> %4 = function_ref @buz : $@convention(thin) (@in_guaranteed Int) -> () // >> user: %5 >> %5 = apply %4(%0) : $@convention(thin) (@in_guaranteed Int) -> () >> %6 = load %0 : $*Int // user: %8 >> // function_ref test >> %7 = function_ref @test : $@convention(thin) (Int) -> () // users: %12, %8 >> %8 = apply %7(%6) : $@convention(thin) (Int) -> () >> // function_ref bad >> %9 = function_ref @bad : $@convention(thin) (@in_guaranteed Int) -> () // >> user: %10 >> %10 = apply %9(%0) : $@convention(thin) (@in_guaranteed Int) -> () >> %11 = load %0 : $*Int // user: %12 >> %12 = apply %7(%11) : $@convention(thin) (Int) -> () >> %13 = tuple () // user: %14 >> return %13 : $() // id: %14 >> } // end sil function 'bar' >> ---- >> >> Michael >> >>> >>> Does that all make sense? >>> >>> Thanks, >>> Johannes >>> <test-load-forwarding.sil><test-load-forwarding.sil-opt> >>> >>> >>>> >>>>> >>>>> Thanks, >>>>> Johannes >>>>> >>>>> [1]: https://bugs.swift.org/browse/SR-5403 > _______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev