aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/tcctest.c6
-rw-r--r--x86_64-gen.c16
2 files changed, 22 insertions, 0 deletions
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 30d78b8..f8a9ca6 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -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;
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 8a2d03a..ea06708 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -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 */