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. [1] https://github.com/llvm/llvm-project/blob/166bd4e1f18da221621953bd5943c1a8d17201fe/clang/lib/CodeGen/CGStmt.cpp#L2843 [2]