> If you have an aggressive optimizer, you can mark cases that bypass the aggression with a handful of lines of code

Now either your code is implementation dependent, or the way you mark those cases are part of the language semantics. And we're back to the original argument.

> In fact doing it with function calls can be easier and better than teaching the compiler about memory access semantics

You are teaching the compiler about memory access semantics if you add rules to the optimizer such as that it can't elide memory accesses in inlined functions.

> by very slightly altering the compiler

... in other words by altering the language semantics, either for just this implementation, or in general.

> Memory-mapped I/O is a platform-specific thing. It shouldn't really be baked into the language.

I agree, but this is one of the reasons why language semantics ought to cover what memory access guarantees are provided when and how, because otherwise you can't reliably even use such OS level facilities without digging into how a specific implementation works.

> And even that would be a notable bloat; Lua does not have a big spec.

It doesn't take a big spec to say "memory writes inside functions [where ... ] should be treated the same as IO for the purposes of optimization, and e.g. can not be elided, coalesced or reordered", or whatever semantics you prefer. Saying "an optimizer is free to elide, coalesce or reorder memory accesses as long as it does not alter the behaviour observable from Lua" would be an acceptable decision too, though in e.g. this case it would mean the use in the article is unsupported and relies on undefined behaviour, but knowing is better than not knowing; at least then you make an informed decision. It's not about giving complex guarantees, it's about not leaving giant gaping unspecified holes that makes it unclear what optimizations are legal and safe for example, but that could be plugged with a sentence or two.