[PATCH] D10476: Additional fix for PR14269: Clang crashes when a bit field is used as inline assembler input / output with memory constraint
Andrey Bokhanko
andreybokhanko at gmail.com
Fri Jul 10 07:19:55 PDT 2015
andreybokhanko added a comment.
Hi Eric,
Thanks for looking into the patch!
In http://reviews.llvm.org/D10476#200564, @echristo wrote:
> This seems to be a bit overconstrained versus what gcc accepts on the testcase:
There are three cases that GCC accepts and clang (with my fix) doesn't:
1. Output to a bit-field:
typedef struct test16_foo {
unsigned int field1 : 1;
unsigned int field2 : 2;
unsigned int field3 : 3;
} test16_foo;
void test16()
{
test16_foo a;
__asm__("movl $5, %0"
: "=rm" (a.field2)); // expected-error {{reference to a non-addressable value in asm output with a memory constraint '=rm'}}
}
GCC accepts this, but generates incorrect code, that is not even accepted by assembler:
$ gcc test1.c
test1.c: Assembler messages:
test1.c:11: Error: `%al' not allowed with `movl'
2. Vector elements:
typedef __attribute__((vector_size(16))) int test16_bar;
int main()
{
test16_bar b = {1, 2, 3, 4};
__asm__("movl $5, %0"
: "=rm" (b[2]));
return b[2];
}
The problem here is that LLVM IR represents vectors with a specific vector type; you can't get address of a random element inside vector. Specific instructions should be used to get individual vector elements ("extractelement" and "insertelement"), but then again -- they don't provide //addresses// of elements. GCC simply treats a vector as an array of elements and computes desired address. In theory, this can be done in LLVM IR as well, but I don't think this is the right approach -- we generally can't make any assumptions on how vectors are represented by a target CPU.
Do you agree?
3. Global register variables:
register int test16_baz asm("rbx");
void test16()
{
__asm__("movl $5, %0"
: "=rm" (test16_baz)); // expected-error {{reference to a non-addressable value in asm output with a memory constraint '=rm'}}
}
The constraint here says "register *or* memory". GCC chooses register and compiles the test fine. Clang always chooses memory -- due to the following check at CGStmt.cpp:1874:
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
I have no idea why it checks for "!info.allowsMemory()" and not for "info.allowsRegister", but this is a separate issue, not related to my patch.
When a test is re-written in a way that allows *only* memory, GCC complains as well:
register int test16_baz asm("rbx");
void test16()
{
__asm__("movl $5, %0"
: "=m" (test16_baz)); // expected-error {{reference to a non-addressable value in asm output with a memory constraint '=rm'}}
}
$ gcc test3.c
test3.c: In function ?test16?:
test3.c:6:11: error: address of global register variable ?test16_baz? requested
: "=m" (test16_baz)); // expected-error {{reference to a non-addressable value in asm output with a memory constraint '=rm'}}
^
test3.c:5:3: error: invalid lvalue in asm output 0
__asm__("movl $5, %0"
^
In http://reviews.llvm.org/D10476#200564, @echristo wrote:
> also, the precision in error messages is nice. :)
Done!
Please re-review.
Andrey
http://reviews.llvm.org/D10476
More information about the cfe-commits
mailing list