IR inline assembly: the x86 Intel "offset" operator

Hi all,

I’m trying to land (a rebased version of) http://llvm.org/D37461 - which should make it possible to handle x86 Intel assembly like
mov eax, offset Foo::ptr + 1
(Currently, omitting the +1 works… but offset doesn’t work in compound expressions.)

I’m having trouble figuring out what inline assembly I can emit into the LLVM IR that will work properly. So far, the closest I’ve gotten is
call void asm sideeffect inteldialect “mov eax, offset $0 + $$1, “m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @”?ptr@Foo@@2PAHA”)
But that expands to
mov eax, offset [?ptr@Foo@@2PAHA] + 1
which ends up incorrectly dereferencing the address first.

I haven’t found a working combination of code & constraints that will expand to
mov eax, offset ?ptr@Foo@@2PAHA + 1
Is this possible?

Thanks,

  • Eric

Actually, there’s more of a bug here than I realized:

https://godbolt.org/z/fktmVn seems to show that LLVM’s current handling of offset goes wrong with global variables… with a global int Bar;, inline assembly
mov eax, offset Bar
ends up as
mov eax, dword ptr [Bar]
which I’m pretty sure is not what’s intended here.

I’ve written LLVM IR that does produce an equivalent result (see the Compiler Explorer link above), but I’m not sure how to get X86Operand to produce a direct memory operand… I can’t figure out where the memory constraint gets turned into an indirect memory constraint ("*m"). Anyone have any leads I can follow?

Thanks,

  • Eric

Argh. Apologies, found what I’d done wrong in the godbolt link. I’d forgotten to set the target triple to i386-pc-windows-msvc.

This brings me back to my original question: is there anything I can write in LLVM IR inline assembly to get llc to emit
mov eax, offset ?ptr@Foo@@2PAHA + 1
?

I think perhaps we want to make this LLVM IR asm string:
call void asm sideeffect inteldialect “mov eax, $0”, “i,~{eax},~{dirflag},~{fpsr},~{flags}”(i32* @"?Bar@@3HA") #1, !srcloc !3

The key thing is the ‘i’ constraint. That ends up producing the wrong assembly right now, but maybe with your rebased patch, now it will do the right thing.

If you change up the dialect and switch to an ELF triple, this inline asm will produce the expected instruction sequence:
call void asm sideeffect “movl $0, %eax”, “i,~{eax},~{dirflag},~{fpsr},~{flags}”(i32* @"?Bar@@3HA") #1, !srcloc !3
Which is what makes me think this is the way to go.

It’s consistent with the AOK_Skip rewrite we do today to skip the “offset” text.

Interesting - the patch doesn’t address this yet. It looks like we have a difference (maybe bug?) in how we handle Intel vs. AT&T inline assembly: https://godbolt.org/z/GQw9ED

Suppose we’re expanding an operand with an ‘i’ constraint, where the operand is given as, e.g. (i32* @Bar).
If the inline assembly is in Intel dialect, this expands as “Bar” in AT&T syntax or “dword ptr [Bar]” in Intel syntax.
If the inline assembly is in AT&T dialect, it expands as “$Bar” in AT&T syntax or “offset Bar” in Intel syntax.

I’d like to try to reconcile this, but I haven’t been able to track down where inline-assembly operands are expanded yet… anyone know where I should be looking?

Interesting - the patch doesn’t address this yet. It looks like we have a difference (maybe bug?) in how we handle Intel vs. AT&T inline assembly: https://godbolt.org/z/GQw9ED

Suppose we’re expanding an operand with an ‘i’ constraint, where the operand is given as, e.g. (i32* @Bar).
If the inline assembly is in Intel dialect, this expands as “Bar” in AT&T syntax or “dword ptr [Bar]” in Intel syntax.
If the inline assembly is in AT&T dialect, it expands as “$Bar” in AT&T syntax or “offset Bar” in Intel syntax.

That sounds right.

I’d like to try to reconcile this, but I haven’t been able to track down where inline-assembly operands are expanded yet… anyone know where I should be looking?

I’m pretty sure this is llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp.

That did it: issue was in X86AsmPrinter::PrintOperand, which emitted a prefix of “$” when printing an address operand in AT&T syntax… but didn’t add the prefix "offset " when in Intel syntax.

Still need to get clang to emit the operand with the “i” constraint, but now at least I know what success will look like.