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).
Unified · Split
| @@ -2677,6 +2677,7 @@ void asm_test(void) · 2676 unmodified lines | ||
| 2677 | 2677 | asm block gets the outer one. */ |
| 2678 | 2678 | int base_func = 42; |
| 2679 | 2679 | void override_func3 (void); |
| 2680 | + unsigned long asmret; | |
| 2680 | 2681 | |
| 2681 | 2682 | printf("inline asm:\n"); |
| 2682 | 2683 | |
| @@ -2720,6 +2721,11 @@ void asm_test(void) · 37 unmodified lines | ||
| 2720 | 2721 | the global one, not the local decl from this function. */ |
| 2721 | 2722 | asm volatile(".weak override_func3\n.set override_func3, base_func"); |
| 2722 | 2723 | override_func3(); |
| 2724 | + /* Check that we can also load structs of appropriate layout | |
| 2725 | + into registers. */ | |
| 2726 | + asm volatile("" : "=r" (asmret) : "0"(s2)); | |
| 2727 | + if (asmret != s2.addr) | |
| 2728 | + printf("asmstr: failed\n"); | |
| 2723 | 2729 | return; |
| 2724 | 2730 | label1: |
| 2725 | 2731 | goto label2; |
| @@ -382,6 +382,22 @@ void load(int r, SValue *sv) · 381 unmodified lines | ||
| 382 | 382 | load(fr, &v1); |
| 383 | 383 | } |
| 384 | 384 | ll = 0; |
| 385 | + /* Like GCC we can load from small enough properly sized | |
| 386 | + structs and unions as well. | |
| 387 | + XXX maybe move to generic operand handling, but should | |
| 388 | + occur only with asm, so tccasm.c might also be a better place */ | |
| 389 | + if ((ft & VT_BTYPE) == VT_STRUCT) { | |
| 390 | + int align; | |
| 391 | + switch (type_size(&sv->type, &align)) { | |
| 392 | + case 1: ft = VT_BYTE; break; | |
| 393 | + case 2: ft = VT_SHORT; break; | |
| 394 | + case 4: ft = VT_INT; break; | |
| 395 | + case 8: ft = VT_LLONG; break; | |
| 396 | + default: | |
| 397 | + tcc_error("invalid aggregate type for register load"); | |
| 398 | + break; | |
| 399 | + } | |
| 400 | + } | |
| 385 | 401 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
| 386 | 402 | b = 0x6e0f66; |
| 387 | 403 | r = REG_VALUE(r); /* movd */ |