interesting LLVM code optimization issue regarding timer registers

This problem was reported to me by a friend who has an LLVM port that is not put back to open source.

Essentially, there is an intrinsic call _lr which is a load register.

so then user code has something like:

start_time = _lr(TIMER_REGISTER)
.....
some_code_to_time
....
end_time = _lr(TIMER_REGISTER)

So what happens is that LLVM moves the code as follows:

start_time = _lr(TIMER_REGISTER)
end_time = _lr(TIMER_REGISTER)
.....
some_code_to_time
......

How would this intrinsic be implemented properly in llvm so this cannot happen?

TIA.

Reed

I vaguely remember having the same problem… Removing [IntrNoMem] on the intrinsic fixed it.

Hi Reed,

How would this intrinsic be implemented properly in llvm so this cannot
happen?

At the intrinsic level, you'd make sure @llvm.whatever had the most
side-effecty definition possible (I think it's actually the default:
"this may read or write completely random memory wherever it feels
like").

At the instruction level, you'd make sure hasSideEffects=1 was set.

Theoretically, a completely side-effect-free sequence of instructions
might still be moved around, but you're almost certainly Doing It
Wrong if that affects you: LLVM is always going to be able to insert
COPYs, spills and various other bits in there that you didn't write
down.

Cheers.

Tim.

He has tried this and it does not solve the problem.

The problem is that someone wants to, for example, time a dsp instruction.

THe dsp instruction has no side effects and does not access memory.

It's a valid thing to do.

Should be some way to do this I would think.

Tia.

Reed

THe dsp instruction has no side effects and does not access memory.

It's a valid thing to do.

At's a sympathetic desire, but doesn't fit entirely well with what the
compiler's doing. Associated with tha DSP instruction are likely to be
argument marshalling COPYs, and it's not entirely clear what semantics
they should have w.r.t. moving past the timer (even in an ideal
world).

Regardless, I don't think LLVM has that level of "keep your hands off" hints.

Should be some way to do this I would think.

If I really wanted that degree of control I'd put the whole lot into
an inline assembly block.

Sorry I couldn't suggest anything neater.

Tim.

Is compiling with -O0 acceptable here?
Probably not if you want "some_code_to_time" to be optimized with LLVM.
Is "_Ir(TIMER_REGISTER)" being set as volatile?

If it doesn't, we really need to consider adding them. Essentially, the read of a timer register here is a stand-in for any unmodelled side effect. There are lots of other cases where this arises as well:
- changing the floating point context
- changing control registers of most any variety (including ones which effect the behaviour of the instruction in question!)
- touching a potentially faulting page (to trigger a known trap)
- unwinding the stack

Having the ability to model a function with potentially arbitrary side effects is necessary.

Just to be clear, I'm not suggesting that the most conservative modelling needs to be the default. Frankly, I think it should be, but I'm open to arguments about that not being the specified behaviour for the languages we primarily target. Having said that, we definitely need the ability to represent more conservative semantics - both for existing C/C++ code and to correctly support other languages.

Philip

Do we need something equivalent to gcc's
emit_insn (gen_blockage ());