Consider corner case: MSInlineAsm may contain operands of both
implicit-def $eax and implicit-def early-clobber $eax
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
This patch is to fix a regression bug (https://gcc.godbolt.org/z/GG44f6) on recent rewrite on RegAllocFast.cpp. The situation that implicit-def $eax and implicit-def early-clobber $eax both occur in MI is rare. But since old implement can handle it, so I add a some condition to check such MI.
llvm/test/CodeGen/X86/phys-msInline-fastregalloc.ll | ||
---|---|---|
11 | It seems to be invalid inline assembly. We can't set eax both as output and clobber. The clobbered register and output register should be in different physical register. [llvm]$ cat t.c void foo(int a, int b) { int c; asm volatile("addl %1, %2 \n" "movl %2, %0\n" :"=a"(c) :"r"(a), "r"(b) :"eax"); } [llvm]$ clang -S t.c t.c:8:17: error: asm-specifier for input or output variable conflicts with asm clobber list :"eax"); ^ 1 error generated. [llvm]$ gcc -S t.c t.c: In function ‘foo’: t.c:4:3: error: ‘asm’ operand has impossible constraints 4 | asm volatile("addl %1, %2 \n" | ^~~ [llvm]$ This is from https://llvm.org/docs/LangRef.html#output-constraints. If this is not safe (e.g. if the assembly contains two instructions, where the first writes to one output, and the second reads an input and writes to a second output), then the “&” modifier must be used (e.g. “=&r”) to specify that the output is an “early-clobber” output. Marking an output as “early-clobber” ensures that LLVM will not use the same register for any inputs (other than an input tied to this output). The eax is an output, so front-end need to mark the early-clobber for eax with "=&{eax}", so it seems to be a front-end issue? |
llvm/test/CodeGen/X86/phys-msInline-fastregalloc.ll | ||
---|---|---|
11 | Thanks for review! Sorry for failing to know this output constraint in IR before. Yes, both GNU inline asm and llvm IR don't allow setting one register both as output and clobber. So the front-end seems to deal wrong with MS inline assembler. Seems like clang front-end always generate ={eax} and set each output register in asm as clobber when dealing with MS inline assembler. So this conflict may happen in clang front-end. I will abandon this review. |
llvm/test/CodeGen/X86/phys-msInline-fastregalloc.ll | ||
---|---|---|
11 | I'll double check on conclusions above. |
llvm/lib/CodeGen/RegAllocFast.cpp | ||
---|---|---|
1241 | I don't understand what's special about MSVC inline asm. Aren't the constraints semantically the same for any asm type? | |
llvm/test/CodeGen/X86/corner-msInline-fastregalloc.mir | ||
5–24 ↗ | (On Diff #314589) | You should be able to drop the whole IR section |
26–62 ↗ | (On Diff #314589) | Can delete most of this (-simplify-mir helps) |
llvm/lib/CodeGen/RegAllocFast.cpp | ||
---|---|---|
1241 | MSVC inline asm is wrote in Intel assembly format. So the method isMsInlineAsm() here uses flag inteldialect to distinguish from GNU inline asm. (I don't know why this flag didn't show in this MIR test, but it indeed works.) From the investigation I've done so far, I have several conclusions:
The rules above will then generate corner case like this patch's IR and MIR test. Yuanke mentioned about set early clobber in LLVM IR (i.e. =&r). I did a experiment. It indeed can pass this bug without this patch. But seems like this rule is for user side. Becasue I found that clang also cannot set =&r for GNU inline asm when output register is written to before the last asm. But clang can deal with similar semantics GNU inline case, because eax is not set as clobber by front-end. (https://gcc.godbolt.org/z/We3b9c). |
THX for review!
llvm/test/CodeGen/X86/corner-msInline-fastregalloc.mir | ||
---|---|---|
5–24 ↗ | (On Diff #314589) | I failed to drop the IR. Because if dropped, %stack.0.retval and %stack.1.c will parsed by llc as not defined. Maybe I'm doing the wrong way. I'm not so familiar with MIR. Can you show me an example also drops IR but with stack variable? |
I uploaded another patch in front-end D94466. It also can fix this regression bug. Both solutions are reasonable to me, since for now clang is weak to deal with MS inline asm.
llvm/lib/CodeGen/RegAllocFast.cpp | ||
---|---|---|
1241 | There shouldn't be a semantic difference. Ultimately the MIR should have the same flags/semantics regardless of the syntax used. This is either correct for all asm dialects, or it's generally incorrect |
clang-format not found in user's PATH; not linting file.