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
This commit is contained in:
grischka 2021-03-30 09:26:26 +02:00
parent 4bb3b3cec7
commit 48df89e10e
19 changed files with 334 additions and 294 deletions

View file

@ -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

View file

@ -15,6 +15,13 @@
#include <stddef.h>
#include <stdint.h>
#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,

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -1,19 +0,0 @@
#pragma once
#include <stdint.h>
#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"

View file

@ -1,31 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#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; \
}

View file

@ -1,12 +0,0 @@
#pragma once
#include <stdint.h>
#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"

View file

@ -1,39 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#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

113
lib/stdatomic.c Normal file
View file

@ -0,0 +1,113 @@
// for libtcc1, avoid including files that are not part of tcc
// #include <stdint.h>
#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

2
tcc.h
View file

@ -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) {

View file

@ -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);

178
tccgen.c
View file

@ -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)

View file

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

View file

@ -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) && \

View file

@ -0,0 +1,108 @@
#include <stdatomic.h>
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

View file

@ -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

View file

@ -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)