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)
asm block gets the outer one. */
int base_func = 42;
void override_func3 (void);
unsigned long asmret;
printf("inline asm:\n");
@ -2720,6 +2721,11 @@ void asm_test(void)
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;
label1:
goto label2;

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 */