x86-64: Allow loads from some structs/unions

GCC allows register loads for asms based on type mode,
and correctly sized structs/union have an allowed mode
(basically 1,2,4,8 sized aggregates).
This commit is contained in:
Michael Matz
2016-08-08 20:18:11 +02:00
parent 9ae10cad1f
commit ca8c1cd643
2 changed files with 22 additions and 0 deletions

View File

@ -2677,6 +2677,7 @@ void asm_test(void)
struct struct1231 s2 = { (unsigned long)&s1 };
/* Hide the outer base_func, but check later that the inline
asm block gets the outer one. */
int base_func = 42;
void override_func3 (void);
unsigned long asmret;
@ -2720,6 +2721,11 @@ void asm_test(void)
override_func2();
/* The base_func ref from the following inline asm should find
the global one, not the local decl from this function. */
asm volatile(".weak override_func3\n.set override_func3, base_func");
override_func3();
/* Check that we can also load structs of appropriate layout
into registers. */
asm volatile("" : "=r" (asmret) : "0"(s2));
if (asmret != s2.addr)
printf("asmstr: failed\n");
return;

View File

@ -382,6 +382,22 @@ void load(int r, SValue *sv)
load(fr, &v1);
}
ll = 0;
/* Like GCC we can load from small enough properly sized
structs and unions as well.
XXX maybe move to generic operand handling, but should
occur only with asm, so tccasm.c might also be a better place */
if ((ft & VT_BTYPE) == VT_STRUCT) {
int align;
switch (type_size(&sv->type, &align)) {
case 1: ft = VT_BYTE; break;
case 2: ft = VT_SHORT; break;
case 4: ft = VT_INT; break;
case 8: ft = VT_LLONG; break;
default:
tcc_error("invalid aggregate type for register load");
break;
}
}
if ((ft & VT_BTYPE) == VT_FLOAT) {
b = 0x6e0f66;
r = REG_VALUE(r); /* movd */