On Thu, Jan 4, 2024 at 12:06 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote: > > On Mon, 2023-12-25 at 12:33 -0800, Alexei Starovoitov wrote: > [...] > > Regarding disappearing asm blocks. > > > https://godbolt.org/z/Kqszr6q3v > > > > Another issue is llvm removes asm() completely when output "+r" > > constraint is used. It has to be asm volatile to convince llvm > > to keep that asm block. That's bad1() case. > > asm() stays in place when input "r" constraint is used. > > That's bad2(). > > asm() removal happens with x86 backend too. So maybe it's a feature? > > The difference between bad1() and bad2() is small: > > .---- output operand > v > bad1: asm("%[reg] += 1":[reg]"+r"(var)); > bad2: asm("%[reg] += 1"::[reg]"r"(var)); > ^ > '--- input operand > > This leads to different IR generation at the beginning of translation: > > %1 = call i32 asm "$0 += 1", "=r,0"(i32 %0) > > vs. > > call void asm sideeffect "$0 += 1", "r"(i32 %0) > > Whether or not to add "sideeffect" property to asm call seem to be > controlled by the following condition in CodeGenFunction::EmitAsmStmt(): > > bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0; > > See [1]. > This is documented in [2] (assuming that clang and gcc are compatible): > > > asm statements that have no output operands and asm goto statements, > > are implicitly volatile. > > Asm block w/o sideeffect, output value of which is not used, > is removed from selection DAG at early stages of instruction generation. > If "bad1" is modified to use "var" after asm block (e.g. return it) > the asm block is not removed. > > So, this looks like regular clang behavior, not specific to BPF target. Wow. Thanks for those details. I didn't know that getNumOutputs() == 0 is equivalent to volatile in that sense. Sounds like we should always add volatile to avoid surprises.