Re: [Tinycc-devel] [Patch] Implement __has_* operators

2021-08-11 Thread Alvarito050506
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

2021-08-11 Thread grischka

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

2021-08-11 Thread Alvarito050506
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

2021-08-11 Thread Alvarito050506
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;
-