From 48df89e10e11f5449040731450e2ce856b6cadc2 Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 30 Mar 2021 09:26:26 +0200 Subject: [PATCH] stdatomics: tidy & cleanup - remove any error messages that were just for debugging the templates really - don't use c99 in tcc (array designators etc.) - remove memory model type (cannot be an own type really) and move memory model defines from built-in to stdatomics.h - apply normal casts to non-pointer atomic_function arguments - tidy the library support - add some tests for errors/warnings Also: - Makefile: move GIT_HASH stuff from CFLAGS to DEFINES and into main section (away from what is included by tests for example) - tccelf.c/tccgen.c: avoid some warnings with newer GCC --- Makefile | 13 +- include/stdatomic.h | 7 ++ include/tccdefs.h | 7 -- lib/Makefile | 4 +- lib/atomic-gen32.c | 25 ---- lib/atomic-gen64.c | 8 -- lib/atomic-i386.c | 19 --- lib/atomic-x86.h | 31 ----- lib/atomic-x86_64.c | 12 -- lib/atomic.h | 39 ------ lib/stdatomic.c | 113 ++++++++++++++++++ tcc.h | 2 - tccelf.c | 5 +- tccgen.c | 178 +++++++++------------------- tccpp.c | 5 - tcctok.h | 10 +- tests/tests2/125_atomic_misc.c | 108 +++++++++++++++++ tests/tests2/125_atomic_misc.expect | 33 ++++++ tests/tests2/Makefile | 9 +- 19 files changed, 334 insertions(+), 294 deletions(-) delete mode 100644 lib/atomic-gen32.c delete mode 100644 lib/atomic-gen64.c delete mode 100644 lib/atomic-i386.c delete mode 100644 lib/atomic-x86.h delete mode 100644 lib/atomic-x86_64.c delete mode 100644 lib/atomic.h create mode 100644 lib/stdatomic.c create mode 100644 tests/tests2/125_atomic_misc.c create mode 100644 tests/tests2/125_atomic_misc.expect diff --git a/Makefile b/Makefile index 5ed10d84..b4c9aa00 100644 --- a/Makefile +++ b/Makefile @@ -24,13 +24,6 @@ CFLAGS += -I$(TOP) CFLAGS += $(CPPFLAGS) VPATH = $(TOPSRC) -TCC_GIT_HASH=$(shell git rev-parse > /dev/null 2>&1 && git rev-parse --short HEAD || echo no) - -ifneq ($(TCC_GIT_HASH),no) - MODIFIED = $(shell git diff | grep --quiet +++ && echo "modified ") - CFLAGS += -DTCC_GIT_HASH="\"$(MODIFIED)$(TCC_GIT_HASH)\"" -endif - ifdef CONFIG_WIN32 CFG = -win ifneq ($(CONFIG_static),yes) @@ -229,6 +222,12 @@ $(TCC_FILES) : DEFINES += -DONE_SOURCE=0 $(X)tccpp.o : $(TCCDEFS_H) endif +TCC_GIT_HASH=$(shell git rev-parse > /dev/null 2>&1 && git rev-parse --short HEAD || echo no) +ifneq ($(TCC_GIT_HASH),no) +MODIFIED = $(shell git diff | grep --quiet +++ && echo "modified ") +$(X)tcc.o : DEFINES += += -DTCC_GIT_HASH="\"$(MODIFIED)$(TCC_GIT_HASH)\"" +endif + ifeq ($(CONFIG_debug),yes) CFLAGS += -g LDFLAGS += -g diff --git a/include/stdatomic.h b/include/stdatomic.h index b910d128..f00c62f0 100644 --- a/include/stdatomic.h +++ b/include/stdatomic.h @@ -15,6 +15,13 @@ #include #include +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 + /* Memory ordering */ typedef enum { memory_order_relaxed = __ATOMIC_RELAXED, diff --git a/include/tccdefs.h b/include/tccdefs.h index ba2a679f..ae0364eb 100644 --- a/include/tccdefs.h +++ b/include/tccdefs.h @@ -78,13 +78,6 @@ #endif #endif - #define __ATOMIC_RELAXED 0 - #define __ATOMIC_CONSUME 1 - #define __ATOMIC_ACQUIRE 2 - #define __ATOMIC_RELEASE 3 - #define __ATOMIC_ACQ_REL 4 - #define __ATOMIC_SEQ_CST 5 - #if defined _WIN32 #define __declspec(x) __attribute__((x)) #define __cdecl diff --git a/lib/Makefile b/lib/Makefile index fe2fd32e..aefe1fe6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -42,8 +42,8 @@ $(X)BT_O += tcov.o DSO_O = dsohandle.o -I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O) atomic-i386.o -X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O) atomic-x86_64.o +I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O) stdatomic.o +X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O) stdatomic.o ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o fetch_and_add_arm.o $(BT_O) ARM64_O = lib-arm64.o fetch_and_add_arm64.o $(BT_O) RISCV64_O = lib-arm64.o fetch_and_add_riscv64.o $(BT_O) diff --git a/lib/atomic-gen32.c b/lib/atomic-gen32.c deleted file mode 100644 index 64575cd5..00000000 --- a/lib/atomic-gen32.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "atomic.h" - -ATOMIC_EXCHANGE(uint8_t, 1) -ATOMIC_EXCHANGE(uint16_t, 2) -ATOMIC_EXCHANGE(uint32_t, 4) - -ATOMIC_FETCH_ADD(uint8_t, 1) -ATOMIC_FETCH_ADD(uint16_t, 2) -ATOMIC_FETCH_ADD(uint32_t, 4) - -ATOMIC_FETCH_SUB(uint8_t, 1) -ATOMIC_FETCH_SUB(uint16_t, 2) -ATOMIC_FETCH_SUB(uint32_t, 4) - -ATOMIC_FETCH_AND(uint8_t, 1) -ATOMIC_FETCH_AND(uint16_t, 2) -ATOMIC_FETCH_AND(uint32_t, 4) - -ATOMIC_FETCH_OR(uint8_t, 1) -ATOMIC_FETCH_OR(uint16_t, 2) -ATOMIC_FETCH_OR(uint32_t, 4) - -ATOMIC_FETCH_XOR(uint8_t, 1) -ATOMIC_FETCH_XOR(uint16_t, 2) -ATOMIC_FETCH_XOR(uint32_t, 4) diff --git a/lib/atomic-gen64.c b/lib/atomic-gen64.c deleted file mode 100644 index edd82632..00000000 --- a/lib/atomic-gen64.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "atomic.h" - -ATOMIC_EXCHANGE(uint64_t, 8) -ATOMIC_FETCH_ADD(uint64_t, 8) -ATOMIC_FETCH_SUB(uint64_t, 8) -ATOMIC_FETCH_AND(uint64_t, 8) -ATOMIC_FETCH_OR(uint64_t, 8) -ATOMIC_FETCH_XOR(uint64_t, 8) diff --git a/lib/atomic-i386.c b/lib/atomic-i386.c deleted file mode 100644 index ca8b2a49..00000000 --- a/lib/atomic-i386.c +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "atomic-x86.h" - -ATOMIC_X86_STORE(uint8_t, 1) -ATOMIC_X86_STORE(uint16_t, 2) -ATOMIC_X86_STORE(uint32_t, 4) - -ATOMIC_X86_LOAD(uint8_t, 1) -ATOMIC_X86_LOAD(uint16_t, 2) -ATOMIC_X86_LOAD(uint32_t, 4) - -ATOMIC_X86_COMPARE_EXCHANGE(uint8_t, 1, "b") -ATOMIC_X86_COMPARE_EXCHANGE(uint16_t, 2, "w") -ATOMIC_X86_COMPARE_EXCHANGE(uint32_t, 4, "l") - -#include "atomic-gen32.c" diff --git a/lib/atomic-x86.h b/lib/atomic-x86.h deleted file mode 100644 index ad4e1f07..00000000 --- a/lib/atomic-x86.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -#define ATOMIC_X86_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ - bool __atomic_compare_exchange_##MODE(_Atomic(TYPE) *atom, TYPE *ref, TYPE xchg) \ - { \ - TYPE rv; \ - TYPE cmp = *ref; \ - asm volatile( \ - "lock cmpxchg" SUFFIX " %2,%1\n" \ - : "=a" (rv), "+m" (*atom) \ - : "q" (xchg), "0" (cmp) \ - : "memory" \ - ); \ - *ref = rv; \ - return (rv == cmp); \ - } - -#define ATOMIC_X86_LOAD(TYPE, MODE) \ - TYPE __atomic_load_##MODE(const _Atomic(TYPE) *atom) \ - { \ - return *(volatile TYPE *)atom; \ - } - -#define ATOMIC_X86_STORE(TYPE, MODE) \ - void __atomic_store_##MODE(_Atomic(TYPE) *atom, TYPE value) \ - { \ - *(volatile TYPE *)atom = value; \ - } diff --git a/lib/atomic-x86_64.c b/lib/atomic-x86_64.c deleted file mode 100644 index 974615d1..00000000 --- a/lib/atomic-x86_64.c +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -#include "atomic-x86.h" -#include "atomic-i386.c" - -ATOMIC_X86_STORE(uint64_t, 8) -ATOMIC_X86_LOAD(uint64_t, 8) -ATOMIC_X86_COMPARE_EXCHANGE(uint64_t, 8, "q") - -#include "atomic-gen64.c" diff --git a/lib/atomic.h b/lib/atomic.h deleted file mode 100644 index 6c9190a6..00000000 --- a/lib/atomic.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP) \ - TYPE __atomic_##NAME##_##MODE(_Atomic(TYPE) *atom, TYPE value) \ - { \ - TYPE xchg; \ - TYPE cmp = __atomic_load(atom, __ATOMIC_RELAXED); \ - do { \ - xchg = (OP); \ - } while (!__atomic_compare_exchange(atom, &cmp, xchg, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \ - return cmp; \ - } - -#ifndef ATOMIC_EXCHANGE -# define ATOMIC_EXCHANGE(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, exchange, value) -#endif - -#ifndef ATOMIC_FETCH_ADD -# define ATOMIC_FETCH_ADD(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, fetch_add, (cmp + value)) -#endif - -#ifndef ATOMIC_FETCH_SUB -# define ATOMIC_FETCH_SUB(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, fetch_sub, (cmp - value)) -#endif - -#ifndef ATOMIC_FETCH_AND -# define ATOMIC_FETCH_AND(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, fetch_and, (cmp & value)) -#endif - -#ifndef ATOMIC_FETCH_OR -# define ATOMIC_FETCH_OR(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, fetch_or, (cmp | value)) -#endif - -#ifndef ATOMIC_FETCH_XOR -# define ATOMIC_FETCH_XOR(TYPE, MODE) ATOMIC_GEN_OP(TYPE, MODE, fetch_xor, (cmp ^ value)) -#endif diff --git a/lib/stdatomic.c b/lib/stdatomic.c new file mode 100644 index 00000000..e26fa1b2 --- /dev/null +++ b/lib/stdatomic.c @@ -0,0 +1,113 @@ +// for libtcc1, avoid including files that are not part of tcc +// #include +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t unsigned long long +#define bool _Bool +#define true 1 +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 + +#define ATOMIC_X86_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ + bool __atomic_compare_exchange_##MODE(_Atomic(TYPE) *atom, TYPE *ref, TYPE xchg) \ + { \ + TYPE rv; \ + TYPE cmp = *ref; \ + asm volatile( \ + "lock cmpxchg" SUFFIX " %2,%1\n" \ + : "=a" (rv), "+m" (*atom) \ + : "q" (xchg), "0" (cmp) \ + : "memory" \ + ); \ + *ref = rv; \ + return (rv == cmp); \ + } + +#define ATOMIC_X86_LOAD(TYPE, MODE) \ + TYPE __atomic_load_##MODE(const _Atomic(TYPE) *atom) \ + { \ + return *(volatile TYPE *)atom; \ + } + +#define ATOMIC_X86_STORE(TYPE, MODE) \ + void __atomic_store_##MODE(_Atomic(TYPE) *atom, TYPE value) \ + { \ + *(volatile TYPE *)atom = value; \ + } + +#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP) \ + TYPE __atomic_##NAME##_##MODE(_Atomic(TYPE) *atom, TYPE value) \ + { \ + TYPE xchg; \ + TYPE cmp = __atomic_load(atom, __ATOMIC_RELAXED); \ + do { \ + xchg = (OP); \ + } while (!__atomic_compare_exchange(atom, &cmp, xchg, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \ + return cmp; \ + } + +#define ATOMIC_EXCHANGE(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, exchange, value) +#define ATOMIC_FETCH_ADD(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, fetch_add, (cmp + value)) +#define ATOMIC_FETCH_SUB(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, fetch_sub, (cmp - value)) +#define ATOMIC_FETCH_AND(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, fetch_and, (cmp & value)) +#define ATOMIC_FETCH_OR(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, fetch_or, (cmp | value)) +#define ATOMIC_FETCH_XOR(TYPE, MODE) \ + ATOMIC_GEN_OP(TYPE, MODE, fetch_xor, (cmp ^ value)) + +ATOMIC_X86_STORE(uint8_t, 1) +ATOMIC_X86_STORE(uint16_t, 2) +ATOMIC_X86_STORE(uint32_t, 4) + +ATOMIC_X86_LOAD(uint8_t, 1) +ATOMIC_X86_LOAD(uint16_t, 2) +ATOMIC_X86_LOAD(uint32_t, 4) + +ATOMIC_X86_COMPARE_EXCHANGE(uint8_t, 1, "b") +ATOMIC_X86_COMPARE_EXCHANGE(uint16_t, 2, "w") +ATOMIC_X86_COMPARE_EXCHANGE(uint32_t, 4, "l") + +ATOMIC_EXCHANGE(uint8_t, 1) +ATOMIC_EXCHANGE(uint16_t, 2) +ATOMIC_EXCHANGE(uint32_t, 4) + +ATOMIC_FETCH_ADD(uint8_t, 1) +ATOMIC_FETCH_ADD(uint16_t, 2) +ATOMIC_FETCH_ADD(uint32_t, 4) + +ATOMIC_FETCH_SUB(uint8_t, 1) +ATOMIC_FETCH_SUB(uint16_t, 2) +ATOMIC_FETCH_SUB(uint32_t, 4) + +ATOMIC_FETCH_AND(uint8_t, 1) +ATOMIC_FETCH_AND(uint16_t, 2) +ATOMIC_FETCH_AND(uint32_t, 4) + +ATOMIC_FETCH_OR(uint8_t, 1) +ATOMIC_FETCH_OR(uint16_t, 2) +ATOMIC_FETCH_OR(uint32_t, 4) + +ATOMIC_FETCH_XOR(uint8_t, 1) +ATOMIC_FETCH_XOR(uint16_t, 2) +ATOMIC_FETCH_XOR(uint32_t, 4) + +#if defined __x86_64__ +ATOMIC_X86_STORE(uint64_t, 8) +ATOMIC_X86_LOAD(uint64_t, 8) +ATOMIC_X86_COMPARE_EXCHANGE(uint64_t, 8, "q") +ATOMIC_EXCHANGE(uint64_t, 8) +ATOMIC_FETCH_ADD(uint64_t, 8) +ATOMIC_FETCH_SUB(uint64_t, 8) +ATOMIC_FETCH_AND(uint64_t, 8) +ATOMIC_FETCH_OR(uint64_t, 8) +ATOMIC_FETCH_XOR(uint64_t, 8) +#endif diff --git a/tcc.h b/tcc.h index e97e4d0b..2e27850f 100644 --- a/tcc.h +++ b/tcc.h @@ -1049,7 +1049,6 @@ struct filespec { #define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION) #define VT_ATOMIC VT_VOLATILE -#define VT_MEMMODEL (VT_STATIC | VT_ENUM_VAL | VT_TYPEDEF) /* type mask (except storage) */ #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) @@ -1418,7 +1417,6 @@ ST_FUNC void tccpp_delete(TCCState *s); ST_FUNC int tcc_preprocess(TCCState *s1); ST_FUNC void skip(int c); ST_FUNC NORETURN void expect(const char *msg); -ST_FUNC NORETURN void expect_arg(const char *msg, size_t arg); /* space excluding newline */ static inline int is_space(int ch) { diff --git a/tccelf.c b/tccelf.c index da675f5e..ddbce88b 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1469,7 +1469,7 @@ static void tcc_tcov_add_file(TCCState *s1, const char *filename) cstr_printf (&cstr, "%s/%s.tcov", wd, filename); } ptr = section_ptr_add(tcov_section, cstr.size + 1); - strncpy((char *)ptr, cstr.data, cstr.size); + strcpy((char *)ptr, cstr.data); unlink((char *)ptr); #ifdef _WIN32 normalize_slashes((char *)ptr); @@ -2339,7 +2339,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, ehdr.e_shstrndx = shnum - 1; fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); - fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); + if (phdr) + fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); sort_syms(s1, symtab_section); diff --git a/tccgen.c b/tccgen.c index 8923913e..fe0c2137 100644 --- a/tccgen.c +++ b/tccgen.c @@ -849,7 +849,7 @@ static void tcc_tcov_block_begin(void) cstr_printf (&cstr, "%s/%s", wd, file->true_filename); } ptr = section_ptr_add(tcov_section, cstr.size + 1); - strncpy((char *)ptr, cstr.data, cstr.size); + strcpy((char *)ptr, cstr.data); #ifdef _WIN32 normalize_slashes((char *)ptr); #endif @@ -865,7 +865,7 @@ static void tcc_tcov_block_begin(void) tcov_data.last_func_name = tcov_section->data_offset; len = strlen (funcname); ptr = section_ptr_add(tcov_section, len + 1); - strncpy((char *)ptr, funcname, len); + strcpy((char *)ptr, funcname); section_ptr_add(tcov_section, -tcov_section->data_offset & 7); ptr = section_ptr_add(tcov_section, 8); write64le (ptr, file->line_num); @@ -5738,36 +5738,11 @@ static void parse_builtin_params(int nc, const char *args) nocode_wanted--; } -static inline int is_memory_model(const SValue *sv) -{ - /* - * FIXME - * The memory models should better be backed by an enumeration. - * - * const int t = sv->type.t; - * - * if (!IS_ENUM_VAL(t)) - * return 0; - * - * if (!(t & VT_STATIC)) - * return 0; - * - * Ideally we should check whether the model matches 1:1. - * If it is possible, we should check by the name of the value. - */ - return 1; -} - -#define ATOMIC_ID(ATOK) \ - (ATOK - TOK___atomic_store) - static void parse_atomic(int atok) { - int mode; - size_t arg; - SValue *call; - CType rv; - CType atom; + int size, align, arg; + CType *atom, *atom_ptr, ct = {0}; + char buf[40]; static const char *const templates[] = { /* * Each entry consists of callback and function template. @@ -5781,124 +5756,85 @@ static void parse_atomic(int atok) * v value * m memory model */ - [ATOMIC_ID(TOK___atomic_store)] = "avm?", - [ATOMIC_ID(TOK___atomic_load)] = "Amv", - [ATOMIC_ID(TOK___atomic_exchange)] = "avmv", - [ATOMIC_ID(TOK___atomic_compare_exchange)] = "apvbmmb", - [ATOMIC_ID(TOK___atomic_fetch_add)] = "avmv", - [ATOMIC_ID(TOK___atomic_fetch_sub)] = "avmv", - [ATOMIC_ID(TOK___atomic_fetch_or)] = "avmv", - [ATOMIC_ID(TOK___atomic_fetch_xor)] = "avmv", - [ATOMIC_ID(TOK___atomic_fetch_and)] = "avmv", + + /* keep in order of appearance in tcctok.h: */ + /* __atomic_store */ "avm.?", + /* __atomic_load */ "Am.v", + /* __atomic_exchange */ "avm.v", + /* __atomic_compare_exchange */ "apvbmm.b", + /* __atomic_fetch_add */ "avm.v", + /* __atomic_fetch_sub */ "avm.v", + /* __atomic_fetch_or */ "avm.v", + /* __atomic_fetch_xor */ "avm.v", + /* __atomic_fetch_and */ "avm.v" }; - const char *template = templates[ATOMIC_ID(atok)]; - const size_t argc = (strlen(template) - 1); + const char *template = templates[(atok - TOK___atomic_store)]; + atom = atom_ptr = NULL; + size = 0; /* pacify compiler */ next(); - - memset(&rv, 0, sizeof(rv)); - memset(&atom, 0, sizeof(atom)); - mode = 0; /* pacify compiler */ - vpush_helper_func(atok); - call = vtop; - skip('('); - if ((*template != 'a') && (*template != 'A')) - expect_arg("pointer to atomic", 0); - for (arg = 0; arg < argc; ++arg) { + for (arg = 0;;) { expr_eq(); - switch (template[arg]) { - case '?': - /* void makes sense only for return value. */ - if (arg != (argc - 1)) - tcc_error("illegal atomic built-in template"); - break; - - case 'b': - break; - case 'a': case 'A': - if ((vtop->type.t & VT_BTYPE) != VT_PTR) - expect_arg("pointer to atomic value", arg); - memcpy(&atom, pointed_type(&vtop->type), sizeof(CType)); - if (!(atom.t & VT_ATOMIC)) - expect_arg("qualified pointer to atomic value", arg); - if ((template[arg] == 'a') && (atom.t & VT_CONSTANT)) - expect_arg("pointer to writable atomic", arg); - switch (type_size(&atom, &(int){0})) { - case 8: mode = 4; break; - case 4: mode = 3; break; - case 2: mode = 2; break; - case 1: mode = 1; break; - default: tcc_error("only integer-sized types are supported"); - } + atom_ptr = &vtop->type; + if ((atom_ptr->t & VT_BTYPE) != VT_PTR) + expect("pointer"); + atom = pointed_type(atom_ptr); + size = type_size(atom, &align); + if (size > 8 + || (size & (size - 1)) + || (atok > TOK___atomic_compare_exchange + && (0 == btype_size(atom->t & VT_BTYPE) + || (atom->t & VT_BTYPE) == VT_PTR))) + expect("integral or integer-sized pointer target type"); + /* GCC does not care either: */ + /* if (!(atom->t & VT_ATOMIC)) + tcc_warning("pointer target declaration is missing '_Atomic'"); */ break; case 'p': - if (((vtop->type.t & VT_BTYPE) != VT_PTR) - || !is_compatible_unqualified_types(&atom, pointed_type(&vtop->type))) - expect_arg("pointer to compatible type", arg); + if ((vtop->type.t & VT_BTYPE) != VT_PTR + || type_size(pointed_type(&vtop->type), &align) != size) + tcc_error("pointer target type mismatch in argument %d", arg + 1); + gen_assign_cast(atom_ptr); break; - case 'v': - if (atom.ref && is_integer_btype(vtop->type.t & VT_BTYPE)) { - if ((tok != TOK___atomic_store) && - (tok != TOK___atomic_load) && - (tok != TOK___atomic_exchange) && - (tok != TOK___atomic_compare_exchange)) - expect_arg("integer type", arg); - } + gen_assign_cast(atom); break; - case 'm': - if (!is_memory_model(vtop)) - expect_arg("memory model", arg); - vtop->type.t &= ~VT_MEMMODEL; + gen_assign_cast(&int_type); + break; + case 'b': + ct.t = VT_BOOL; + gen_assign_cast(&ct); break; - - default: - tcc_error("unknown parameter type"); } - if (tok == ')') + if ('.' == template[++arg]) break; skip(','); } - if (arg < (argc - 1)) - expect("more parameters"); - if (arg > (argc - 1)) - expect("less parameters"); skip(')'); - call->sym = external_helper_sym(atok + mode); - gfunc_call(argc); - - switch (template[argc]) { + ct.t = VT_VOID; + switch (template[arg + 1]) { case 'b': - vpushi(0); - PUT_R_RET(vtop, VT_BOOL); + ct.t = VT_BOOL; break; - - case 'p': - vpushs(0); - PUT_R_RET(vtop, VT_SIZE_T); - break; - case 'v': - vpush(&atom); - PUT_R_RET(vtop, atom.t); + ct = *atom; break; - - case '?': - vpushi(0); - PUT_R_RET(vtop, VT_VOID); - break; - - default: - tcc_error("incorrect atomic template"); } - vtop->r2 = VT_CONST; + + sprintf(buf, "%s_%d", get_tok_str(atok, 0), size); + vpush_helper_func(tok_alloc_const(buf)); + vrott(arg + 1); + gfunc_call(arg); + + vpush(&ct); + PUT_R_RET(vtop, ct.t); } ST_FUNC void unary(void) diff --git a/tccpp.c b/tccpp.c index 46c5ece4..a72f29e5 100644 --- a/tccpp.c +++ b/tccpp.c @@ -107,11 +107,6 @@ ST_FUNC void expect(const char *msg) tcc_error("%s expected", msg); } -ST_FUNC void expect_arg(const char *msg, size_t arg) -{ - tcc_error("%s expected as arg #%zu", msg, arg); -} - /* ------------------------------------------------------------------------- */ /* Custom allocator for tiny objects */ diff --git a/tcctok.h b/tcctok.h index a5d893e1..87fb2c34 100644 --- a/tcctok.h +++ b/tcctok.h @@ -175,13 +175,7 @@ #endif /* atomic operations */ -#define DEF_ATOMIC(ID) \ - DEF(TOK_##__##ID, "__"#ID) \ - DEF(TOK_##__##ID##_1, "__"#ID"_1") \ - DEF(TOK_##__##ID##_2, "__"#ID"_2") \ - DEF(TOK_##__##ID##_4, "__"#ID"_4") \ - DEF(TOK_##__##ID##_8, "__"#ID"_8") - +#define DEF_ATOMIC(ID) DEF(TOK_##__##ID, "__"#ID) DEF_ATOMIC(atomic_store) DEF_ATOMIC(atomic_load) DEF_ATOMIC(atomic_exchange) @@ -192,8 +186,6 @@ DEF_ATOMIC(atomic_fetch_xor) DEF_ATOMIC(atomic_fetch_and) -#undef DEF_ATOMIC - /* pragma */ DEF(TOK_pack, "pack") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \ diff --git a/tests/tests2/125_atomic_misc.c b/tests/tests2/125_atomic_misc.c new file mode 100644 index 00000000..75cdba28 --- /dev/null +++ b/tests/tests2/125_atomic_misc.c @@ -0,0 +1,108 @@ +#include +int printf(const char*,...); + +#if defined test_atomic_compare_exchange +int main() +{ + _Atomic int a = 12; + int b = 77; + int r; + + atomic_store(&a, b + 0); + r = atomic_compare_exchange_strong(&a, &b, 99); + printf("%d %d %d\n", r, a, b); + + atomic_store(&a, b + 3); + r = atomic_compare_exchange_strong(&a, &b, 99); + printf("%d %d %d\n", r, a, b); + + return 0; +} + +#elif defined test_atomic_store +int main() +{ + int _Atomic i; + int r; + atomic_store(&i, 12); + r = atomic_fetch_add(&i, i); + printf("r = %d, i = %d\n", r, i); +} + +#elif defined test_atomic_store_pointer +typedef struct { char c[4]; } c4; +int main() +{ + int i = 1; + int _Atomic *p = &i; + int k = 2; + atomic_store(&p, &k); + printf("*p = %d\n", *p); +} + +#elif defined test_atomic_store_struct +typedef struct { char c[4]; } c4; +int main() +{ + c4 _Atomic p; + c4 v = { 1,2,3,4 }; + atomic_store(&p, v); + printf("%d %d %d %d\n", p.c[0], p.c[1], p.c[2], p.c[3]); +} + +#elif defined test_atomic_error_1 +int main() +{ + int _Atomic i; + atomic_load(i); +} + +#elif defined test_atomic_error_2 +int main() +{ + struct { char c[3]; } _Atomic c3; + atomic_load(&c3); +} + +#elif defined test_atomic_error_3 +int main() +{ + _Atomic int *p = 0; + atomic_fetch_add(&p, 1); +} + +#elif defined test_atomic_error_4 +int main() +{ + int _Atomic i = 1; + char c = 2; + atomic_compare_exchange_strong(&i, &c, 0); +} + +#elif defined test_atomic_warn_1 +int main() +{ + int _Atomic i = 1; + /* assignment to integer from pointer */ + atomic_store(&i, &i); +} + +#elif defined test_atomic_warn_2 +int main() +{ + int i = 1; + char c = 2; + int _Atomic *p = &i; + /* assignment from incompatible pointer */ + atomic_store(&p, &c); +} + +#elif defined test_atomic_warn_3 +int main() +{ + int const i = 1; + /* assignment to read-only -location */ + atomic_fetch_add(&i, 2); +} + +#endif diff --git a/tests/tests2/125_atomic_misc.expect b/tests/tests2/125_atomic_misc.expect new file mode 100644 index 00000000..7aa03eba --- /dev/null +++ b/tests/tests2/125_atomic_misc.expect @@ -0,0 +1,33 @@ +[test_atomic_compare_exchange] +1 99 77 +0 80 80 + +[test_atomic_store] +r = 12, i = 24 + +[test_atomic_store_pointer] +*p = 2 + +[test_atomic_store_struct] +1 2 3 4 + +[test_atomic_error_1] +125_atomic_misc.c:57: error: pointer expected + +[test_atomic_error_2] +125_atomic_misc.c:64: error: integral or integer-sized pointer target type expected + +[test_atomic_error_3] +125_atomic_misc.c:71: error: integral or integer-sized pointer target type expected + +[test_atomic_error_4] +125_atomic_misc.c:79: error: pointer target type mismatch in argument 2 + +[test_atomic_warn_1] +125_atomic_misc.c:87: warning: assignment makes integer from pointer without a cast + +[test_atomic_warn_2] +125_atomic_misc.c:97: warning: assignment from incompatible pointer type + +[test_atomic_warn_3] +125_atomic_misc.c:105: warning: assignment of read-only location diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index f21b9762..5f32cbcf 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -23,6 +23,8 @@ ifeq (,$(filter i386,$(ARCH))) endif ifeq (,$(filter i386 x86_64,$(ARCH))) SKIP += 85_asm-outside-function.test # x86 asm + SKIP += 124_atomic_counter.test + SKIP += 125_atomic_misc.test # currently only x86 supported endif ifeq ($(CONFIG_backtrace),no) SKIP += 112_backtrace.test @@ -47,6 +49,7 @@ endif ifeq (-$(CONFIG_WIN32)-,-yes-) SKIP += 106_versym.test # No pthread support SKIP += 114_bound_signal.test # No pthread support + SKIP += 124_atomic_counter.test # No pthread support endif ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS))) SKIP += 106_versym.test # no pthread_condattr_setpshared @@ -115,11 +118,7 @@ ifneq ($(CONFIG_bcheck),no) 121_struct_return.test: FLAGS += -b 122_vla_reuse.test: FLAGS += -b endif - -# this test needs pthread and is currently supported on x86 platforms -ifneq (,$(filter i386 x86_64,$(ARCH))) - SKIP += 124_atomic_counter.test -endif +125_atomic_misc.test: FLAGS += -dt 124_atomic_counter.test: FLAGS += -pthread # Filter source directory in warnings/errors (out-of-tree builds)