This is an archive of the discontinued LLVM Phabricator instance.

The [2/3] Fix mangle problem when variable used in inline asm (Add modifier P for ARR[BaseReg+IndexReg+..])
ClosedPublic

Authored by xiangzhangllvm on Mar 3 2022, 3:10 AM.

Details

Summary

I encounter serval problems about using Global Value (GV) in inline asm. ( both today and before)
I think it is may be a right time to discuss/fix it.

Simply speaking:
We encounter a mangle problem in inlineasm when it directly use Global Value's name.
D113096 once fix the mangle problem. But it cause some other problems.
D115225 and D116090 reverted the D113096 to fix the new fails.
But it didn't fix the mangle problem in inline asm.

So I create 2 patches to fix it.
The first is D120886 (only do revert).
The other is current patch [2/3].
The Next one [3/3] at D121785.

Mangler problem with GV used in inline asm
Currently (and before too) we directly use the GV’s name in inline asm for some cases (I don’t know the early reason, but that doesn’t make sense to me)

For example (Mangler problem)

$cat t.c
int GArr[]={0,1,3,};
int foo(int x) {
  __asm {mov eax, 0};
  __asm {mov DWORD PTR GArr[ecx+eax*2+2], 4};

  return GArr[x];
}

Let’s compile it with clang -fasm-blocks -target i686-windows-msvc t.c -S

15 _foo:                                   # @foo
16 # %bb.0:                                # %entry
…
29         movl    $4, GArr+2(ecx,%eax,2)       # inline asm
...
34         movl    _GArr(,%eax,4), %eax   # read GArr[x] to eax
..
37         retl
…
42 _GArr:
43         .long   0                               # 0x0
44         .long   1                               # 0x1
45         .long   3                               # 0x3

Bug: The Mangler didn’t work on the GArr in inline asm, so it can’t rename to _GArr
(Reason: due to we didn’t connected the GArr with its real value in parse process, it just a string name)

History fix (build fail)
I find Shengchen and Pheobe has fix the relation problem before.
They once try to fix it by connecting the GArr with its real value in parse process, but quickly revert it. Because meet 2 fails:
1st Fail: We can't an’t build upper code.
clang -fasm-blocks t.c -S

test.c:5:3: error: BaseReg/IndexReg already set!
  __asm {mov DWORD PTR GArr[ecx+eax*2+2], 4};
  ^
<inline asm>:2:48: note: instantiated into assembly here
        mov DWORD PTR [rip + offset GArr][ecx + eax * 2 + 2], 4
                                                      ^
1 error generated.

2n Fail: We can’t build upper code in PIC mode even we remove the base reg (this is not a new fail).

int GArr[]={0,1,3,};
int foo(int x) {
  __asm {mov eax, 0};
  __asm {mov DWORD PTR GArr[eax*2+2], 4};
 // __asm {mov DWORD PTR GArr[ecx+eax*2+2], 4};

  return GArr[x];
}

$clang -fasm-blocks t.c -fpic -S

test.c:5:3: error: base register is 64-bit, but index register is not
  __asm {mov DWORD PTR GArr[eax*2+2], 4};
  ^
<inline asm>:2:16: note: instantiated into assembly here
        mov DWORD PTR [rax][eax * 2 + 2], 4
                      ^
1 error generated.

Status of current LLVM: (has relocation problem in fpic/ GCC too)
$clang -fasm-blocks t-pic.c -fpic -S

…
20         movq    GArr@GOTPCREL(%rip), %rax
23         movl    $4, **GArr**+2(,%eax,2)                   # inline asm   (not right code, should accessed from GOT)
26         movslq  -4(%rbp), %rcx
27         movq    GArr@GOTPCREL(%rip), %rax
28         movl    (%rax,%rcx,4), %eax                 # read GArr[x] to eax
31         retq
…

Though current llvm successful generate out the code for inline asm, but it is not right code.
Because in PIC mode, the GArr should be accessed from GOT. This will cause segment fault.

How to fix
For GV in inline asm, I prefer to keep the connection between the GV and its real value, (not just keep a GV name in inline asm).
So the GV can be seen in all the optimization pass.

So 1st step, I will revert the patch D115225 and D116090 at D120886
And then 2nd step, I will fix the upper bug Fail 1 (current patch).

Diff Detail

Event Timeline

xiangzhangllvm created this revision.Mar 3 2022, 3:10 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 3 2022, 3:10 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
xiangzhangllvm requested review of this revision.Mar 3 2022, 3:10 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 3 2022, 3:10 AM
xiangzhangllvm retitled this revision from The [2/2] Patch (Current Patch) revert 2 history commits: to The [2/2] Fix mangle problem when variable used in inline asm (non-rip for ARR[BaseReg+IndexReg+..]).Mar 3 2022, 5:36 PM
xiangzhangllvm edited the summary of this revision. (Show Details)Mar 3 2022, 5:50 PM
xiangzhangllvm edited the summary of this revision. (Show Details)Mar 3 2022, 6:25 PM
xiangzhangllvm edited the summary of this revision. (Show Details)
efriedma added inline comments.Mar 3 2022, 8:11 PM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

If I'm understanding correctly, this is trying to detect two adjacent expressions in a specific form, and then transform one of them so they can be concatenated? This is way too much magic. If we aren't parsing expressions correctly, please fix the initial parse; don't fudge the expressions afterwards.

xiangzhangllvm added inline comments.Mar 3 2022, 9:23 PM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

I think you understand a part of it.
Here the instruction parsing are finished. The Operands info written into AsmStrRewrites[].
Let me take a example:
Both follow cases will get same Operands info into AsmStrRewrites[i] (ARR) and AsmStrRewrites[i+1] ([edx+eax*4])
Case 1:

mov     eax,ARR[edx+eax*4]

Case 2:

mov     eax,ARR ;   call  dword ptr[edx+eax*4]

So here code (line 5967-5990) is just to distinguish the 2 case.

For Case 1, we can not let ARR be a RIP related address, because it already has base reg and index reg. (We can't use 3 regs for a mem address)
For Case 2, it is no problem let ARR use RIP, the [edx+eax*4] are in another instruction.

xiangzhangllvm added inline comments.Mar 3 2022, 9:32 PM
llvm/lib/MC/MCParser/AsmParser.cpp
6160

MODIFIER :P will disable ASMPrinter print PC related style for a Global Address.

LuoYuanke added inline comments.Mar 4 2022, 5:32 PM
clang/test/CodeGen/ms-inline-asm-variables.c
14

Is the ":P" you added fit the below description from https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers?

P: Print a memory reference or operand for use as the argument of a call instruction. (E.g. omit (rip), even though it’s PC-relative.)

Should the ":P" be specified only in -pic mode?

LuoYuanke added inline comments.Mar 4 2022, 6:02 PM
clang/test/CodeGen/ms-inline-asm-variables.c
14

Would you post the example code lowering from IR to assembly? I can't create an valid IR code with :P flag in https://godbolt.org/z/doP83Wr1a

pengfei added inline comments.Mar 6 2022, 6:16 AM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

I agree with @efriedma and think the use of :P is hacky. I wrote an experiment patch which seems more concise D121072.

xiangzhangllvm added inline comments.Mar 6 2022, 5:15 PM
clang/test/CodeGen/ms-inline-asm-variables.c
14

Yes, it fit asm-template-argument-modifiers ,

P: Print a memory reference or operand for use as the argument of a call instruction. (E.g. omit (rip), even though it’s PC-relative.)

In fact, the real implement of "P" is only non-RIP in X86AsmPrinter

14

Try use llc to build it. The fail in https://godbolt.org/z/doP83Wr1a is not relation with "P"
(I can't logon my sever now)

llvm/lib/MC/MCParser/AsmParser.cpp
5990

I have explained that efriedma's understand is not correct. There is not concatenated them, just distinguish. PLS refer my previous explain.

and then transform one of them so they can be concatenated? This is way too much magic. If we ...

D121072 is still try to replace the Global name in IR/MIR, that is not good way to let follow process see it. (for example Mangler), and no reason do it on codegen. Using Modifer ":P", let all process see it, and let exsiting code to handle it, in my eye, is better.

pengfei added inline comments.Mar 6 2022, 6:12 PM
clang/test/CodeGen/ms-inline-asm-variables.c
14

As you showed, the P is used for call instruction. I don't think it's a good idea to apply it to non call instruction.

llvm/lib/MC/MCParser/AsmParser.cpp
5990

I think you misunderstood efriedma's point. He meant you should distinguish during parsing instead of distinguishing again.
Besides, I think you missed the case when ARR inside [], e.g, [gVar + ecx + ebx]. I agreed with him the logic is magic and not easy to understand.
D121072 intends do the mangling at front end. No following process is needed. I see front end do mangling sometime, so I think we can do it there.

xiangzhangllvm added inline comments.Mar 6 2022, 6:41 PM
clang/test/CodeGen/ms-inline-asm-variables.c
14

We can modify the description in asm-template-argument-modifiers , because the real implement of it is only print non-RIP in X86AsmPrinter. Now reason show non-rip address can on work on function label. That is not a beautiful design from beginning.

llvm/lib/MC/MCParser/AsmParser.cpp
5990

D121072 intends do the mangling at front end. No following process is needed.

We can't make sure "No following process is needed. "
One problem I can see is a symbol both used for lea and call. Call may @plt (or some others), but lea not.

In fact, D121072 is only the idea of do part print job at codegen. If it can be replaced in MIR why it can be directly repalced in IR ? Just try getSymbol (which will use mangler name)
That is not a good arch for IR/MIR. All the operands should be visible to IR/MIR.

xiangzhangllvm added inline comments.Mar 6 2022, 6:52 PM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

Besides, I think you missed the case when ARR inside [], e.g, [gVar + ecx + ebx]

Let me refine the code to cover this case,
BTW, that is not a good/standard way to get address in this way.

xiangzhangllvm added inline comments.Mar 6 2022, 7:16 PM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

I did a test in my local.
I think you mean the line 13 is fail. The fail is directly a “syntax error”, it is not supported by inlineasm before too. (No relation with this patch)

 1 // -fasm-blocks -S -emit-llvm
 2 int ARR[10];
 3 int ARR2[10];
 4 int main()
 5 {
 6         int x;
 7         ARR[6] = 7;
 8     __asm {
 9         mov      eax, 1
10         mov      ecx, 20
11         mov eax, DWORD PTR ARR[ecx + eax * 4]     // OK
12         mov eax, DWORD PTR [ARR + ecx + eax * 4]  // OK
13 //        mov eax, DWORD PTR ARR2[ARR + ecx + eax * 4]  // Err: cannot use more than one symbol in memory operand
14         mov DWORD PTR [x], eax
15     }
16 }
xiangzhangllvm added inline comments.Mar 6 2022, 7:33 PM
llvm/lib/MC/MCParser/AsmParser.cpp
6160

Let me take a look if here isSpecialIntelExprAppend can be checked earlier and cover case "[ARR + ecx + eax * 4]"

pengfei added inline comments.Mar 6 2022, 7:50 PM
llvm/lib/MC/MCParser/AsmParser.cpp
5990

One problem I can see is a symbol both used for lea and call. Call may @plt (or some others), but lea not.

I think you mean the problem in D109407? Seems the patch is still arguable. I think we can solve one by one. Since it's already fail, I don't think it's a problem for this one.

I think you mean the line 13 is fail.

No, I meant line 12. Why is it OK? I didn't find you handle it here. How about ARR is the last one, e.g., [ecx + eax * 4 + ARR] ?

My point is you almost do the parsing logic here again. It's redundant and fragile. If there's any update in the parser code, people is not aware they should update here too.

Generate IR for Mem symbol + IntelExpr in inline asm

Still need to fix PIC problem.
The mem ARR in asm(ARR[...]) can not transfer to PC-related style in PIC model.
Because the Parser and Printer will both share inline-asm Parser which can not handle "[ARR-BaseSymbol][...]".

skan added inline comments.Mar 14 2022, 1:41 AM
llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h
66

inline asm

67

ARR can be represented a displacement in non-pic mode. The comments need to be more specified.

llvm/lib/MC/MCParser/AsmParser.cpp
5947–5950

This function is unused?

6166–6170

This looks much better than the previous patch.

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
439

accident change?

xiangzhangllvm added inline comments.Mar 14 2022, 6:02 PM
llvm/lib/MC/MCParser/AsmParser.cpp
6166–6170

Here is similar with previous patch.
The only diff is use "if (AR.IntelExpRestricted)" replace of "if (function call)"
The previous patch can also fix the case "[ARR + ecx + eax * 4]".
The purpose I update the patch is let it more fit to fix PIC problem late.

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
439

I mark here to fix PIC problem in win32, l am writing another patch to fix it. Let me update it and remove the unused "getAffected".

xiangzhangllvm retitled this revision from The [2/2] Fix mangle problem when variable used in inline asm (non-rip for ARR[BaseReg+IndexReg+..]) to The [2/3] Fix mangle problem when variable used in inline asm (non-rip for ARR[BaseReg+IndexReg+..]).Mar 14 2022, 6:07 PM
xiangzhangllvm edited the summary of this revision. (Show Details)
pengfei added inline comments.Mar 14 2022, 11:39 PM
clang/test/CodeGen/ms-inline-asm-variables.c
6–12

Should these change to ${{{[0-9]}}:P} too?

24–33

How about local variables?

I'll update this patch and commit the [3/3] patch soon. Thanks!

clang/test/CodeGen/ms-inline-asm-variables.c
6–12

Currently Modifier ":P" is only need for function call or GV with both baseReg and IndexReg.
For one reg case, for example

"__asm {mov DWORD PTR GArr[rax*2+2], 4};"

current llvm has ability to handle it by split into 2 steps:

mov     ecx, dword ptr [eax + GArr@GOT]
mov     dword ptr [ecx + 2*eax + GArr+22], 4
24–33

Local variables is not allow use 2 regs in offset "[]", since it always fetch form stack or load. That must introduce extra regs.

xiangzhangllvm retitled this revision from The [2/3] Fix mangle problem when variable used in inline asm (non-rip for ARR[BaseReg+IndexReg+..]) to The [2/3] Fix mangle problem when variable used in inline asm (Add modifier P for ARR[BaseReg+IndexReg+..]).
xiangzhangllvm edited the summary of this revision. (Show Details)Mar 16 2022, 3:12 AM
xiangzhangllvm marked 9 inline comments as done.Mar 16 2022, 3:14 AM
skan added inline comments.Mar 16 2022, 3:50 AM
llvm/lib/MC/MCParser/AsmParser.cpp
6158

I think this is the first new usage of P here, so you update the llvm/docs/LangRef.rst

llvm/lib/Target/X86/AsmParser/X86Operand.h
72

inline asm, specify

xiangzhangllvm added inline comments.Mar 16 2022, 5:21 PM
llvm/lib/MC/MCParser/AsmParser.cpp
6158

Yes I am planning to, I'll update it in [3/3] patch. https://reviews.llvm.org/D121785

xiangzhangllvm marked an inline comment as done.
skan accepted this revision.Mar 16 2022, 8:46 PM

LGTM

This revision is now accepted and ready to land.Mar 16 2022, 8:46 PM

LGTM

Thanks a lot! I'll commit it after [3/3] is accepted too. then push them at same time.

This revision was landed with ongoing or failed builds.Mar 23 2022, 6:41 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptMar 23 2022, 6:41 PM