Resolve undefined functions to compiler builtins if they exist.
authorDale Weiler <killfieldengine@gmail.com>
Sat, 23 Nov 2013 11:57:40 +0000 (06:57 -0500)
committerDale Weiler <killfieldengine@gmail.com>
Sat, 23 Nov 2013 11:57:40 +0000 (06:57 -0500)
doc/gmqcc.1
gmqcc.ini.example
opts.c
opts.def
parser.c

index 758e08d..2a205bb 100644 (file)
@@ -338,6 +338,12 @@ for QuakeWorld to compile it needs to be treated as a warning
 instead, as such this warning only works when -std=qcc.
 .It Fl W Ns Cm directive-inmacro
 Warn about the use of preprocessor directives inside macros.
+.It Fl W Ns Cm builtins
+When using a function that is not explicitly defined, the compiler
+will search its intrinsics table for something that matches that
+function name by appending "__builtin_" to it. This behaviour may
+be unexpected, so enabling this will produce a diagnostic when
+such a function is resolved to a builtin.
 .El
 .Sh COMPILE FLAGS
 .Bl -tag -width Ds
index acff3b3..0a263df 100644 (file)
     DIRECTIVE_INMACRO = true
 
 
+    #When using a function that is not explicitly defined, the compiler
+    #will search its intrinsics table for something that matches that
+    #function name by appending "__builtin_" to it. This behaviour may
+    #be unexpected, so enabling this will produce a diagnostic when
+    #such a function is resolved to a builtin.
+
+    BUILTINS = true
+
 
 [optimizations]
     #Some general peephole optimizations. For instance the code `a = b
diff --git a/opts.c b/opts.c
index e50bd74..e54ec57 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -92,6 +92,7 @@ static void opts_setdefault(void) {
     opts_set(opts.warn,  WARN_PARENTHESIS,               true);
     opts_set(opts.warn,  WARN_CONST_OVERWRITE,           true);
     opts_set(opts.warn,  WARN_DIRECTIVE_INMACRO,         true);
+    opts_set(opts.warn,  WARN_BUILTINS,                  true);
 
     /* flags */
     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,           true);
index 57625dd..b209988 100644 (file)
--- a/opts.def
+++ b/opts.def
@@ -96,6 +96,7 @@
     GMQCC_DEFINE_FLAG(BREAKDEF)
     GMQCC_DEFINE_FLAG(CONST_OVERWRITE)
     GMQCC_DEFINE_FLAG(DIRECTIVE_INMACRO)
+    GMQCC_DEFINE_FLAG(BUILTINS)
 #endif
 
 #ifdef GMQCC_TYPE_OPTIMIZATIONS
index f030572..bb860a4 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1575,6 +1575,8 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
         if (!var && !strcmp(parser_tokval(parser), "__FUNC__"))
             var = (ast_expression*)fold_constgen_string(parser->fold, parser->function->name, false);
         if (!var) {
+            char *tryintrinsic = NULL;
+
             /*
              * now we try for the real intrinsic hashtable. If the string
              * begins with __builtin, we simply skip past it, otherwise we
@@ -1584,6 +1586,26 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                 var = intrin_func(parser->intrin, parser_tokval(parser));
             }
 
+            /*
+             * Try it as an instruction by appending __builtin_ to the token
+             * and emit a warning if an intrinsic function matching that
+             * name exists.
+             */
+            if (!var) {
+                util_asprintf(&tryintrinsic, "__builtin_%s", parser_tokval(parser));
+                if ((var = intrin_func(parser->intrin, tryintrinsic))) {
+                    (void)!!compile_warning(
+                        parser_ctx(parser),
+                        WARN_BUILTINS,
+                        "using implicitly defined builtin `%s' for `%s'",
+                        tryintrinsic,
+                        parser_tokval(parser)
+                    );
+                }
+                mem_d(tryintrinsic);
+            }
+
+
             if (!var) {
                 char *correct = NULL;
                 size_t i;