Re: [Tinycc-devel] [Patch] Implement __has_* operators
Hello, > I guess that patch is two patches actually, one for the feature and > one to obfuscate tcctok.h a little bit plus adding a new file to the > project with some cryptic name plus showing a rather sophisticated > method to count tokens to everybody. s/not great/horrible/g; Yes, that's exactly what I meant, sorry about that. > So, would you think we can avoid the unnecessary and let tcctok.h stay > as is, at least for now? And approach the feature in a somehow less > spectacular way, such as with: [...]? Sure, I was trying to reduce the code duplication a bit, but probably simpler and less verbose code is better. I have attached a modified version of the patch with your suggested changes. diff --git a/tccpp.c b/tccpp.c index 897ef15..ad87cf0 100644 --- a/tccpp.c +++ b/tccpp.c @@ -93,6 +93,12 @@ static const unsigned char tok_two_chars[] = 0 }; +static int supported_arr[4][2] = { +SUPPORTED_ATTRIBUTES, SUPPORTED_BUILTINS, +/* We have only one profile, so __has_extension == __has_feature */ +SUPPORTED_FEATURES, SUPPORTED_FEATURES +}; + static void next_nomacro(void); ST_FUNC void skip(int c) @@ -1410,6 +1416,23 @@ ST_FUNC void free_defines(Sym *b) } } +ST_INLN int supported_check(int t, int type) +{ +int* arr = supported_arr[type]; + +if (t >= arr[0] && t <= arr[0] + arr[1]) +{ +return 1; +} +return 0; +} + +ST_INLN int defined_check(int t) +{ +/* Ignore __has_include because it's a dummy implementation */ +return !!define_find(t) || (t >= TOK___HAS_ATTRIBUTE && t <= TOK___HAS_FEATURE); +} + /* label lookup */ ST_FUNC Sym *label_find(int v) { @@ -1502,7 +1525,7 @@ static int expr_preprocess(void) expect("identifier"); if (tcc_state->run_test) maybe_run_test(tcc_state); -c = define_find(tok) != 0; +c = defined_check(tok); if (t == '(') { next_nomacro(); if (tok != ')') @@ -1510,7 +1533,7 @@ static int expr_preprocess(void) } tok = TOK_CINT; tokc.i = c; -} else if (1 && tok == TOK___HAS_INCLUDE) { +} else if (tok == TOK___HAS_INCLUDE) { next(); /* XXX check if correct to use expansion */ skip('('); while (tok != ')' && tok != TOK_EOF) @@ -1519,6 +1542,18 @@ static int expr_preprocess(void) expect("')'"); tok = TOK_CINT; tokc.i = 0; +} else if (tok >= TOK___HAS_ATTRIBUTE && tok <= TOK___HAS_FEATURE) { +t = tok; +next(); +skip('('); +if (tok < TOK_IDENT) +expect("identifier"); +c = supported_check(tok, t - TOK___HAS_ATTRIBUTE); +next(); +if (tok != ')') + expect("')'"); +tok = TOK_CINT; +tokc.i = c; } else if (tok >= TOK_IDENT) { /* if undefined macro, replace with zero, check for func-like */ t = tok; @@ -1965,7 +2000,7 @@ include_done: file->ifndef_macro = tok; } } -c = (define_find(tok) != 0) ^ c; +c = defined_check(tok) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); diff --git a/tcctok.h b/tcctok.h index d4c1ef5..1b89868 100644 --- a/tcctok.h +++ b/tcctok.h @@ -93,6 +93,10 @@ DEF(TOK___FUNCTION__, "__FUNCTION__") DEF(TOK___VA_ARGS__, "__VA_ARGS__") DEF(TOK___COUNTER__, "__COUNTER__") + DEF(TOK___HAS_ATTRIBUTE, "__has_attribute") + DEF(TOK___HAS_BUILTIN, "__has_builtin") + DEF(TOK___HAS_FEATURE, "__has_feature") + DEF(TOK___HAS_EXTENSION, "__has_extension") DEF(TOK___HAS_INCLUDE, "__has_include") /* special identifiers */ @@ -109,6 +113,7 @@ /* attribute identifiers */ /* XXX: handle all tokens generically since speed is not critical */ +#define SUPPORTED_ATTRIBUTES {TOK_SECTION1, TOK_MODE} DEF(TOK_SECTION1, "section") DEF(TOK_SECTION2, "__section__") DEF(TOK_ALIGNED1, "aligned") @@ -157,6 +162,7 @@ DEF(TOK_VISIBILITY1, "visibility") DEF(TOK_VISIBILITY2, "__visibility__") +#define SUPPORTED_BUILTINS {TOK_builtin_types_compatible_p, LAST_BUILTIN} DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p") DEF(TOK_builtin_choose_expr, "__builtin_choose_expr") DEF(TOK_builtin_constant_p, "__builtin_constant_p") @@ -164,17 +170,27 @@ DEF(TOK_builtin_return_address, "__builtin_return_address") DEF(TOK_builtin_expect, "__builtin_expect") /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ +#define LAST_BUILTIN TOK_builtin_va_start #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 DEF(TOK_builtin_va_start, "__builtin_va_start") #elif defined TCC_TARGET_X86_64 +#undef LAST_BUILTIN +#define LAST_BUILTIN TOK_builtin_va_arg_types DEF(T
Re: [Tinycc-devel] [Patch] Implement __has_* operators
Alvarito050506 wrote: The patch isn't great (it abuses macros, for example) so suggestions, criticism, and feedback in general would be appreciated. I guess that patch is two patches actually, one for the feature and one to obfuscate tcctok.h a little bit plus adding a new file to the project with some cryptic name plus showing a rather sophisticated method to count tokens to everybody. And that while I just recently could happily remove 5 files, sigh... So, would you think we can avoid the unnecessary and let tcctok.h stay as is, at least for now? And approach the feature in a somehow less spectacular way, such as with: /* first and last of supported attributes */ #define SUPPORTED_ATTRIBUTES { TOK_SECTION1, TOK_MODE } to be used like: static int const supported_arr[4][2] = { SUPPORTED_ATTRIBUTES, ... ? --- gr Thanks, Álvaro. ___ Tinycc-devel mailing list Tinycc-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Re: [Tinycc-devel] [Patch] Implement __has_* operators
I just realized that version of the patch has a typo, sorry. Here's the fixed version. diff --git a/tccabf.h b/tccabf.h new file mode 100644 index 000..e410726 --- /dev/null +++ b/tccabf.h @@ -0,0 +1,74 @@ +/* Attributes, builtins, and features/extensions */ +/* XXX: handle all tokens generically since speed is not critical */ + +#define DEF_ATTR0(ID) DEF(TOK_##ID, #ID) +#define DEF_ATTR2(ID) DEF(TOK_##ID##1, #ID) DEF(TOK_##ID##2, "__" #ID "__") +#define DEF_ATTR3(ID, N3) DEF_ATTR2(ID) DEF(TOK_##ID##3, N3) +#define DEF_BUILTIN(ID) DEF(TOK_builtin_##ID, "__builtin_" #ID) +#define DEF_FEATURE(ID) DEF(TOK_FEATURE_##ID, "c_" #ID) + +#ifdef DEF_SUPPORTED +static int supported_attrs[] = { +#else +#define DEF_FIRST(ID) +#endif + DEF_FIRST(TOK_section1) + DEF_ATTR2(section) + DEF_ATTR2(aligned) + DEF_ATTR2(packed) + DEF_ATTR2(weak) + DEF_ATTR2(alias) + DEF_ATTR2(unused) + DEF_ATTR3(cdecl, "__cdecl") + DEF_ATTR3(stdcall, "__stdcall") + DEF_ATTR3(fastcall, "__fastcall") + DEF_ATTR2(regparm) + DEF_ATTR2(cleanup) + DEF_ATTR2(constructor) + DEF_ATTR2(destructor) + DEF_ATTR2(always_inline) + DEF_ATTR0(dllexport) + DEF_ATTR0(dllimport) + DEF_ATTR0(nodecorate) + DEF_ATTR3(noreturn, "_Noreturn") + DEF_ATTR2(visibility) + DEF_ATTR0(__mode__) +#ifdef DEF_SUPPORTED +}; static int supported_builtins[] = { +#endif + DEF_FIRST(TOK_builtin_types_compatible_p) + DEF_BUILTIN(types_compatible_p) + DEF_BUILTIN(choose_expr) + DEF_BUILTIN(constant_p) + DEF_BUILTIN(frame_address) + DEF_BUILTIN(return_address) + DEF_BUILTIN(expect) + /*DEF_BUILTIN(VA_LIST, "va_list")*/ +#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 || \ +defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 + DEF_BUILTIN(va_start) +#endif +#if defined TCC_TARGET_X86_64 + DEF_BUILTIN(va_arg_types) +#endif +#if defined TCC_TARGET_ARM64 + DEF_BUILTIN(va_arg) +#endif +#ifdef DEF_SUPPORTED +}; static int supported_features[] = { +#endif + DEF_FIRST(TOK_FEATURE_alignas) + DEF_FEATURE(alignas) + DEF_FEATURE(alignof) + DEF_FEATURE(atomic) + DEF_FEATURE(generic_selections) + DEF_FEATURE(static_assert) +#ifdef DEF_SUPPORTED +}; +#endif +#undef DEF_ATTR0 +#undef DEF_ATTR2 +#undef DEF_ATTR3 +#undef DEF_BUILTIN +#undef DEF_FEATURE +#undef DEF_FIRST diff --git a/tccgen.c b/tccgen.c index e0b5fd6..ab13d32 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4335,8 +4335,8 @@ redo: t = tok; next(); switch(t) { - case TOK_CLEANUP1: - case TOK_CLEANUP2: + case TOK_cleanup1: + case TOK_cleanup2: { Sym *s; @@ -4353,28 +4353,28 @@ redo: skip(')'); break; } -case TOK_CONSTRUCTOR1: -case TOK_CONSTRUCTOR2: +case TOK_constructor1: +case TOK_constructor2: ad->f.func_ctor = 1; break; -case TOK_DESTRUCTOR1: -case TOK_DESTRUCTOR2: +case TOK_destructor1: +case TOK_destructor2: ad->f.func_dtor = 1; break; -case TOK_ALWAYS_INLINE1: -case TOK_ALWAYS_INLINE2: +case TOK_always_inline1: +case TOK_always_inline2: ad->f.func_alwinl = 1; break; -case TOK_SECTION1: -case TOK_SECTION2: +case TOK_section1: +case TOK_section2: skip('('); parse_mult_str(&astr, "section name"); ad->section = find_section(tcc_state, (char *)astr.data); skip(')'); cstr_free(&astr); break; -case TOK_ALIAS1: -case TOK_ALIAS2: +case TOK_alias1: +case TOK_alias2: skip('('); parse_mult_str(&astr, "alias(\"target\")"); ad->alias_target = /* save string as token, for later */ @@ -4382,8 +4382,8 @@ redo: skip(')'); cstr_free(&astr); break; - case TOK_VISIBILITY1: - case TOK_VISIBILITY2: + case TOK_visibility1: + case TOK_visibility2: skip('('); parse_mult_str(&astr, "visibility(\"default|hidden|internal|protected\")"); @@ -4400,8 +4400,8 @@ redo: skip(')'); cstr_free(&astr); break; -case TOK_ALIGNED1: -case TOK_ALIGNED2: +case TOK_aligned1: +case TOK_aligned2: if (tok == '(') { next(); n = expr_const(); @@ -4415,36 +4415,36 @@ redo: if (n != 1 << (ad->a.aligned - 1)) tcc_error("alignment of %d is larger than implemented", n); break; -case TOK_PACKED1: -case TOK_PACKED2: +case TOK_packed1: +case TOK_packed2: ad->a.packed = 1; break; -case TOK_WEAK1: -case TOK_WEAK2: +case TOK_weak1: +case TOK_weak2: ad->a.weak = 1; break; -case TOK_UNUSED1: -case TOK_UNUSED2: +case TOK_unus
[Tinycc-devel] [Patch] Implement __has_* operators
Hello, In a previous thread [1], it was discussed the possibility to implement __has_attribute/builtin (GCC, Clang) and __has_feature/extension (Clang only), since it's a relatively standardized way to check for features that are implemented by some modern compilers. This patch implements them trying to respect their behavior in GCC/Clang [2][3][4]: + `#ifdef __has_*` and `defined(__has_*)` are evaluated to 1. + `#if __has_*(operand)` is evaluated to 1 if `operand` is implemented, and to 0 otherwise. + `#if __has_*` is invalid. + `__has_builtin` detects only builtin "pseudo-functions", not macros. + `__has_*` is not expanded in any other context. The main difference is in __has_feature/extension, since Clang has multiple profiles, but TCC has only one, so passing any of the available features as operands to any of these operators will evaluate to 1. The other difference is that unprefixed feature detection (`alignas` instead of `c_alignas`, etc.) is not implemented, because it has been deprecated in Clang a while ago, so it has no real use nowadays. (This last part could be easily changed though) About the missing __has_include/next_include, there seems to be a dummy implementation of the first, and I'm working on a patch to correctly implement them, but it might take a while because I'm still trying to familiarize myself with the source code. The patch isn't great (it abuses macros, for example) so suggestions, criticism, and feedback in general would be appreciated. Thanks, Álvaro. [1]: https://lists.nongnu.org/archive/html/tinycc-devel/2021-08/msg8.html [2]: https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html [3]: https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fbuiltin.html [4]: https://clang.llvm.org/docs/LanguageExtensions.html diff --git a/tccabf.h b/tccabf.h new file mode 100644 index 000..808485c --- /dev/null +++ b/tccabf.h @@ -0,0 +1,74 @@ +/* Attributes, built-ins, and features/extensions */ +/* XXX: handle all tokens generically since speed is not critical */ + +#define DEF_ATTR0(ID) DEF(TOK_##ID, #ID) +#define DEF_ATTR2(ID) DEF(TOK_##ID##1, #ID) DEF(TOK_##ID##2, "__" #ID "__") +#define DEF_ATTR3(ID, N3) DEF_ATTR2(ID) DEF(TOK_##ID##3, N3) +#define DEF_BUILTIN(ID) DEF(TOK_builtin_##ID, "__builtin_" #ID) +#define DEF_FEATURE(ID) DEF(TOK_FEATURE_##ID, "c_" #ID) + +#ifdef DEF_SUPPORTED +static int supported_attrs[] = { +#else +#define DEF_FIRST(ID) +#endif + DEF_FIRST(TOK_section1) + DEF_ATTR2(section) + DEF_ATTR2(aligned) + DEF_ATTR2(packed) + DEF_ATTR2(weak) + DEF_ATTR2(alias) + DEF_ATTR2(unused) + DEF_ATTR3(cdecl, "__cdecl") + DEF_ATTR3(stdcall, "__stdcall") + DEF_ATTR3(fastcall, "__fastcall") + DEF_ATTR2(regparm) + DEF_ATTR2(cleanup) + DEF_ATTR2(constructor) + DEF_ATTR2(destructor) + DEF_ATTR2(always_inline) + DEF_ATTR0(dllexport) + DEF_ATTR0(dllimport) + DEF_ATTR0(nodecorate) + DEF_ATTR3(noreturn, "_Noreturn") + DEF_ATTR2(visibility) + DEF_ATTR0(__mode__) +#ifdef DEF_SUPPORTED +}; static int supported_builtins[] = { +#endif + DEF_FIRST(TOK_BUILTIN_types_compatible_p) + DEF_BUILTIN(types_compatible_p) + DEF_BUILTIN(choose_expr) + DEF_BUILTIN(constant_p) + DEF_BUILTIN(frame_address) + DEF_BUILTIN(return_address) + DEF_BUILTIN(expect) + /*DEF_BUILTIN(VA_LIST, "va_list")*/ +#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 || \ +defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 + DEF_BUILTIN(va_start) +#endif +#if defined TCC_TARGET_X86_64 + DEF_BUILTIN(va_arg_types) +#endif +#if defined TCC_TARGET_ARM64 + DEF_BUILTIN(va_arg) +#endif +#ifdef DEF_SUPPORTED +}; static int supported_features[] = { +#endif + DEF_FIRST(TOK_FEATURE_alignas) + DEF_FEATURE(alignas) + DEF_FEATURE(alignof) + DEF_FEATURE(atomic) + DEF_FEATURE(generic_selections) + DEF_FEATURE(static_assert) +#ifdef DEF_SUPPORTED +}; +#endif +#undef DEF_ATTR0 +#undef DEF_ATTR2 +#undef DEF_ATTR3 +#undef DEF_BUILTIN +#undef DEF_FEATURE +#undef DEF_FIRST diff --git a/tccgen.c b/tccgen.c index e0b5fd6..ab13d32 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4335,8 +4335,8 @@ redo: t = tok; next(); switch(t) { - case TOK_CLEANUP1: - case TOK_CLEANUP2: + case TOK_cleanup1: + case TOK_cleanup2: { Sym *s; @@ -4353,28 +4353,28 @@ redo: skip(')'); break; } -case TOK_CONSTRUCTOR1: -case TOK_CONSTRUCTOR2: +case TOK_constructor1: +case TOK_constructor2: ad->f.func_ctor = 1; break; -case TOK_DESTRUCTOR1: -case TOK_DESTRUCTOR2: +case TOK_destructor1: +case TOK_destructor2: ad->f.func_dtor = 1; break; -case TOK_ALWAYS_INLINE1: -case TOK_ALWAYS_INLINE2: +case TOK_always_inline1: +case TOK_always_inline2: ad->f.func_alwinl = 1; break; -