2 * Copyright (C) 2012, 2013
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Provides all the "intrinsics" / "builtins" for GMQCC. These can do
28 * a few things, they can provide fall back implementations for math
29 * functions if the definitions don't exist for some given engine. Or
30 * then can determine definitions for existing builtins, and simply
31 * wrap back to them instead. This is like a "portable" intrface that
32 * is entered when -fintrin is used (causing all existing builtins to
33 * be ignored by the compiler and instead interface through here.
36 ast_expression (*intrin)(parser_t *);
43 * Some helper macros for generating def, doing ast_value from func, with
44 * assignment, and a nice aggregate builder for generating the intrinsic
45 * table at the bottom of this file, and for registering functions and
46 * globals with the parser (so that they can be codegen'ed)
48 #define INTRIN_IMP(NAME) \
49 ast_expression intrin_##NAME (parser_t *parser)
52 * For intrinsics that are not to take precedence over a builtin, leave
53 * ALIAS as an empty string.
55 #define INTRIN_DEF(NAME, ALIAS) \
56 { &intrin_##NAME, #NAME, ALIAS }
59 #define INTRIN_VAL(NAME, FUNC, STYPE, VTYPE) \
61 (NAME) = ast_value_new ( \
66 (NAME)->expression.next = (ast_expression*)ast_value_new ( \
71 (FUNC) = ast_function_new ( \
78 #define INTRIN_REG(FUNC, VALUE) \
80 vec_push(parser->functions, (FUNC)); \
81 vec_push(parser->globals, (ast_expression*)(VALUE)); \
96 * Implementation of intrinsics. Each new intrinsic needs to be added
97 * to the intrinsic table below.
101 * float isnan(float x) {
111 * float isinf(float x) {
112 * return (x != 0) && (x + x == x);
117 INTRIN_IMP(fpclassify) {
119 * float __builtin_fpclassify(float x) {
124 * return QC_FP_INFINITE;
129 * return QC_FP_NORMAL;
138 * float __builtin_exp(float x) {
139 * return __builtin_pow(QC_M_E, x);
142 static ast_value *value = NULL;
145 ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "pow"));
146 ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
147 ast_block *body = ast_block_new (parser_ctx(parser));
148 ast_function *func = NULL;
150 INTRIN_VAL("exp", func, "<float>", TYPE_FLOAT);
152 /* push arguments for params to call */
153 vec_push(call->params, (ast_expression*)parser_const_float(parser, QC_M_E));
154 vec_push(call->params, (ast_expression*)arg1);
156 /* return pow(QC_M_E, x) */
157 vec_push(body->exprs,
158 (ast_expression*)ast_return_new(
160 (ast_expression*)call
164 vec_push(value->expressions.param, arg1); /* float x (for param) */
165 vec_push(func ->blocks, body); /* {{{ body }}} */
167 INTRIN_REG(func, value);
170 return (ast_expression*)value;
176 * float __builtin_exp2(float x) {
177 * return __builin_pow(2, x);
184 * float __builtin_expm1(float x) {
185 * return __builtin_exp(x) - 1;
191 intrin_t intrin_intrinsics[] = {
192 INTRIN_DEF(exp, "exp")