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