Some complex types can still be small and simple enough to fit into register. Other compilers allow some operations on these types, and it seems to be quite a reasonable choice. From now on, we should be able to compile the following artificial example: struct combo { uint16_t lo; uint16_t hi; }; struct combo load(const _Atomic(struct combo) *atom) { return atomic_load(atom); } void store(_Atomic(struct combo) *atom, struct combo value) { atomic_store(atom, value); } struct combo xchg(_Atomic(struct combo) *atom, struct combo value) { return atomic_exchange(atom, value); } bool cmpxchg(_Atomic(struct combo) *atom, struct combo *cmp, struct combo xchg) { return atomic_compare_exchange_strong(atom, cmp, xchg); } This might be useful for some corner cases, though it is quite likely that many programmers will prefer operating on a single 32-bit value instead of using the structure consisting of 16-bit pair. Things will work as long as the overall structure size happens to be the same as for any integer type we support in atomics.
Unified · Split
| @@ -5766,6 +5766,7 @@ static void parse_atomic(int atok) · 5765 unmodified lines | |||
| 5766 | int mode; | 5766 | int mode; |
| 5767 | size_t arg; | 5767 | size_t arg; |
| 5768 | SValue *call; | 5768 | SValue *call; |
| 5769 | CType rv; | ||
| 5769 | CType atom; | 5770 | CType atom; |
| 5770 | static const char *const templates[] = { | 5771 | static const char *const templates[] = { |
| 5771 | /* | 5772 | /* |
| @@ -5795,6 +5796,8 @@ static void parse_atomic(int atok) · 23 unmodified lines | |||
| 5795 | 5796 | ||
| 5796 | next(); | 5797 | next(); |
| 5797 | 5798 | ||
| 5799 | memset(&rv, 0, sizeof(rv)); | ||
| 5800 | memset(&atom, 0, sizeof(atom)); | ||
| 5798 | mode = 0; /* pacify compiler */ | 5801 | mode = 0; /* pacify compiler */ |
| 5799 | vpush_helper_func(atok); | 5802 | vpush_helper_func(atok); |
| 5800 | call = vtop; | 5803 | call = vtop; |
| @@ -5824,7 +5827,7 @@ static void parse_atomic(int atok) · 23 unmodified lines | |||
| 5824 | expect_arg("qualified pointer to atomic value", arg); | 5827 | expect_arg("qualified pointer to atomic value", arg); |
| 5825 | if ((template[arg] == 'a') && (atom.t & VT_CONSTANT)) | 5828 | if ((template[arg] == 'a') && (atom.t & VT_CONSTANT)) |
| 5826 | expect_arg("pointer to writable atomic", arg); | 5829 | expect_arg("pointer to writable atomic", arg); |
| 5827 | switch (btype_size(atom.t & VT_BTYPE)) { | 5830 | switch (type_size(&atom, &(int){0})) { |
| 5828 | case 8: mode = 4; break; | 5831 | case 8: mode = 4; break; |
| 5829 | case 4: mode = 3; break; | 5832 | case 4: mode = 3; break; |
| 5830 | case 2: mode = 2; break; | 5833 | case 2: mode = 2; break; |
| @@ -5840,8 +5843,13 @@ static void parse_atomic(int atok) · 9 unmodified lines | |||
| 5840 | break; | 5843 | break; |
| 5841 | 5844 | ||
| 5842 | case 'v': | 5845 | case 'v': |
| 5843 | if (!is_integer_btype(vtop->type.t & VT_BTYPE)) | 5846 | if (atom.ref && is_integer_btype(vtop->type.t & VT_BTYPE)) { |
| 5844 | expect_arg("integer type", arg); | 5847 | if ((tok != TOK___atomic_store) && |
| 5848 | (tok != TOK___atomic_load) && | ||
| 5849 | (tok != TOK___atomic_exchange) && | ||
| 5850 | (tok != TOK___atomic_compare_exchange)) | ||
| 5851 | expect_arg("integer type", arg); | ||
| 5852 | } | ||
| 5845 | break; | 5853 | break; |
| 5846 | 5854 | ||
| 5847 | case 'm': | 5855 | case 'm': |
| @@ -5865,15 +5873,32 @@ static void parse_atomic(int atok) · 17 unmodified lines | |||
| 5865 | 5873 | ||
| 5866 | call->sym = external_helper_sym(atok + mode); | 5874 | call->sym = external_helper_sym(atok + mode); |
| 5867 | gfunc_call(argc); | 5875 | gfunc_call(argc); |
| 5868 | vpushi(0); | ||
| 5869 | 5876 | ||
| 5870 | switch (template[argc]) { | 5877 | switch (template[argc]) { |
| 5871 | case 'b': PUT_R_RET(vtop, VT_BOOL); break; | 5878 | case 'b': |
| 5872 | case 'v': PUT_R_RET(vtop, atom.t); break; | 5879 | vpushi(0); |
| 5873 | case 'p': PUT_R_RET(vtop, VT_SIZE_T); break; | 5880 | PUT_R_RET(vtop, VT_BOOL); |
| 5874 | case '?': PUT_R_RET(vtop, VT_VOID); break; | 5881 | break; |
| 5875 | default: tcc_error("incorrect atomic template"); | 5882 | |
| 5883 | case 'p': | ||
| 5884 | vpushs(0); | ||
| 5885 | PUT_R_RET(vtop, VT_SIZE_T); | ||
| 5886 | break; | ||
| 5887 | |||
| 5888 | case 'v': | ||
| 5889 | vpush(&atom); | ||
| 5890 | PUT_R_RET(vtop, atom.t); | ||
| 5891 | break; | ||
| 5892 | |||
| 5893 | case '?': | ||
| 5894 | vpushi(0); | ||
| 5895 | PUT_R_RET(vtop, VT_VOID); | ||
| 5896 | break; | ||
| 5897 | |||
| 5898 | default: | ||
| 5899 | tcc_error("incorrect atomic template"); | ||
| 5876 | } | 5900 | } |
| 5901 | vtop->r2 = VT_CONST; | ||
| 5877 | } | 5902 | } |
| 5878 | 5903 | ||
| 5879 | ST_FUNC void unary(void) | 5904 | ST_FUNC void unary(void) |