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:
parent
4bb3b3cec7
commit
48df89e10e
19 changed files with 334 additions and 294 deletions
13
Makefile
13
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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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"
|
|
@ -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; \
|
||||
}
|
|
@ -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"
|
39
lib/atomic.h
39
lib/atomic.h
|
@ -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
113
lib/stdatomic.c
Normal 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
2
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) {
|
||||
|
|
5
tccelf.c
5
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);
|
||||
|
|
178
tccgen.c
178
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)
|
||||
|
|
5
tccpp.c
5
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 */
|
||||
|
||||
|
|
10
tcctok.h
10
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) && \
|
||||
|
|
108
tests/tests2/125_atomic_misc.c
Normal file
108
tests/tests2/125_atomic_misc.c
Normal 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
|
33
tests/tests2/125_atomic_misc.expect
Normal file
33
tests/tests2/125_atomic_misc.expect
Normal 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
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue