Made intrinsics seperate from the parser.

This commit is contained in:
Dale Weiler 2013-08-14 06:02:15 +00:00
parent 85ee52128c
commit 73d9aa29c4
5 changed files with 151 additions and 139 deletions

View file

@ -150,7 +150,7 @@ stat.o: gmqcc.h opts.def
test.o: gmqcc.h opts.def
main.o: gmqcc.h opts.def lexer.h
lexer.o: gmqcc.h opts.def lexer.h
parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h intrin.h
parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
code.o: gmqcc.h opts.def
ast.o: gmqcc.h opts.def ast.h ir.h parser.h lexer.h
ir.o: gmqcc.h opts.def ir.h

View file

@ -14,7 +14,7 @@ LDFLAGS +=
LIBS += -lm
#objects
OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o fold.o
OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o fold.o intrin.o
OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o
OBJ_T = test.o util.o opts.o conout.o fs.o stat.o
OBJ_X = exec-standalone.o util.o opts.o conout.o fs.o stat.o

View file

@ -20,6 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <string.h>
#include "parser.h"
/*
* Provides all the "intrinsics" / "builtins" for GMQCC. These can do
@ -30,49 +32,34 @@
* is entered when -fintrin is used (causing all existing builtins to
* be ignored by the compiler and instead interface through here.
*/
typedef struct {
ast_expression *(*intrin)(parser_t *);
const char *name;
const char *alias;
} intrin_t;
static ht intrin_intrinsics(void) {
static ht intrinsics = NULL;
if (!intrinsics)
intrinsics = util_htnew(PARSER_HT_SIZE);
return intrinsics;
}
#define INTRIN_VAL(VALUE, NAME, FUNC, STYPE, VTYPE) \
do { \
(VALUE) = ast_value_new ( \
parser_ctx(parser), \
"__builtin_" NAME, \
TYPE_FUNCTION \
); \
(VALUE)->expression.next = (ast_expression*)ast_value_new ( \
parser_ctx(parser), \
STYPE, \
VTYPE \
); \
(FUNC) = ast_function_new ( \
parser_ctx(parser), \
"__builtin_" NAME, \
(VALUE) \
); \
#define INTRIN_VAL(VALUE, NAME, FUNC, STYPE, VTYPE) \
do { \
(VALUE) = ast_value_new ( \
parser_ctx(intrin->parser), \
"__builtin_" NAME, \
TYPE_FUNCTION \
); \
(VALUE)->expression.next = (ast_expression*)ast_value_new ( \
parser_ctx(intrin->parser), \
STYPE, \
VTYPE \
); \
(FUNC) = ast_function_new ( \
parser_ctx(intrin->parser), \
"__builtin_" NAME, \
(VALUE) \
); \
} while (0)
#define INTRIN_REG(FUNC, VALUE) \
do { \
vec_push(parser->functions, (FUNC)); \
vec_push(parser->globals, (ast_expression*)(VALUE)); \
#define INTRIN_REG(FUNC, VALUE) \
do { \
vec_push(intrin->parser->functions, (FUNC)); \
vec_push(intrin->parser->globals, (ast_expression*)(VALUE)); \
} while (0)
#define QC_M_E 2.71828182845905
static ast_expression *intrin_func(parser_t *parser, const char *name);
static ast_expression *intrin_pow (parser_t *parser) {
static ast_expression *intrin_pow (intrin_t *intrin) {
/*
* float pow(float x, float y) {
* float local = 1.0f;
@ -90,12 +77,12 @@ static ast_expression *intrin_pow (parser_t *parser) {
static ast_value *value = NULL;
if (!value) {
ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
ast_value *local = ast_value_new(parser_ctx(parser), "local", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(parser));
ast_block *l1b = ast_block_new(parser_ctx(parser)); /* loop 1 body */
ast_block *l2b = ast_block_new(parser_ctx(parser)); /* looo 2 body */
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_value *arg2 = ast_value_new(parser_ctx(intrin->parser), "y", TYPE_FLOAT);
ast_value *local = ast_value_new(parser_ctx(intrin->parser), "local", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
ast_block *l1b = ast_block_new(parser_ctx(intrin->parser)); /* loop 1 body */
ast_block *l2b = ast_block_new(parser_ctx(intrin->parser)); /* loop 2 body */
ast_loop *loop1 = NULL;
ast_loop *loop2 = NULL;
ast_function *func = NULL;
@ -112,28 +99,28 @@ static ast_expression *intrin_pow (parser_t *parser) {
/* assignment to local of value 1.0f */
vec_push(body->exprs,
(ast_expression*)ast_store_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
(ast_expression*)local,
(ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */
(ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
)
);
/* y >>= 2 */
vec_push(l2b->exprs,
(ast_expression*)ast_binstore_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
INSTR_MUL_F,
(ast_expression*)arg2,
(ast_expression*)fold_constgen_float(parser->fold, 0.25f)
(ast_expression*)fold_constgen_float(intrin->parser->fold, 0.25f)
)
);
/* x *= x */
vec_push(l2b->exprs,
(ast_expression*)ast_binstore_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
INSTR_MUL_F,
(ast_expression*)arg1,
@ -143,13 +130,13 @@ static ast_expression *intrin_pow (parser_t *parser) {
/* while (!(y&1)) */
loop2 = ast_loop_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
NULL,
(ast_expression*)ast_binary_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_AND,
(ast_expression*)arg2,
(ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */
(ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
),
true, /* ! not */
NULL,
@ -164,17 +151,17 @@ static ast_expression *intrin_pow (parser_t *parser) {
/* y-- */
vec_push(l1b->exprs,
(ast_expression*)ast_binstore_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
INSTR_SUB_F,
(ast_expression*)arg2,
(ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */
(ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
)
);
/* local *= x */
vec_push(l1b->exprs,
(ast_expression*)ast_binstore_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
INSTR_MUL_F,
(ast_expression*)local,
@ -184,13 +171,13 @@ static ast_expression *intrin_pow (parser_t *parser) {
/* while (y > 0) */
loop1 = ast_loop_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
NULL,
(ast_expression*)ast_binary_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_GT,
(ast_expression*)arg2,
(ast_expression*)parser->fold->imm_float[0] /* 0 == 0.0f */
(ast_expression*)intrin->fold->imm_float[0] /* 0 == 0.0f */
),
false,
NULL,
@ -205,7 +192,7 @@ static ast_expression *intrin_pow (parser_t *parser) {
/* return local; */
vec_push(body->exprs,
(ast_expression*)ast_return_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
(ast_expression*)local
)
);
@ -219,7 +206,7 @@ static ast_expression *intrin_pow (parser_t *parser) {
return (ast_expression*)value;
}
static ast_expression *intrin_mod(parser_t *parser) {
static ast_expression *intrin_mod(intrin_t *intrin) {
/*
* float mod(float x, float y) {
* return x - y * floor(x / y);
@ -228,10 +215,10 @@ static ast_expression *intrin_mod(parser_t *parser) {
static ast_value *value = NULL;
if (!value) {
ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "floor"));
ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(parser));
ast_call *call = ast_call_new (parser_ctx(intrin->parser), intrin_func(intrin, "floor"));
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_value *arg2 = ast_value_new(parser_ctx(intrin->parser), "y", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
ast_function *func = NULL;
INTRIN_VAL(value, "mod", func, "<float>", TYPE_FLOAT);
@ -239,7 +226,7 @@ static ast_expression *intrin_mod(parser_t *parser) {
/* floor(x/y) */
vec_push(call->params,
(ast_expression*)ast_binary_new (
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_DIV_F,
(ast_expression*)arg1,
(ast_expression*)arg2
@ -248,13 +235,13 @@ static ast_expression *intrin_mod(parser_t *parser) {
vec_push(body->exprs,
(ast_expression*)ast_return_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
(ast_expression*)ast_binary_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_SUB_F,
(ast_expression*)arg1,
(ast_expression*)ast_binary_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_MUL_F,
(ast_expression*)arg2,
(ast_expression*)call
@ -266,7 +253,7 @@ static ast_expression *intrin_mod(parser_t *parser) {
vec_push(value->expression.params, arg1); /* float x (for param) */
vec_push(value->expression.params, arg2); /* float y (for param) */
vec_push(func->blocks, body); /* {{{ body }}} */
vec_push(func->blocks, body); /* {{{ body }}} */
INTRIN_REG(func, value);
}
@ -274,7 +261,7 @@ static ast_expression *intrin_mod(parser_t *parser) {
return (ast_expression*)value;
}
static ast_expression *intrin_exp(parser_t *parser) {
static ast_expression *intrin_exp(intrin_t *intrin) {
/*
* float exp(float x) {
* return pow(QC_M_E, x);
@ -283,21 +270,21 @@ static ast_expression *intrin_exp(parser_t *parser) {
static ast_value *value = NULL;
if (!value) {
ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "pow"));
ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
ast_block *body = ast_block_new (parser_ctx(parser));
ast_call *call = ast_call_new (parser_ctx(intrin->parser), intrin_func(intrin, "pow"));
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
ast_function *func = NULL;
INTRIN_VAL(value, "exp", func, "<float>", TYPE_FLOAT);
/* push arguments for params to call */
vec_push(call->params, (ast_expression*)fold_constgen_float(parser->fold, QC_M_E));
vec_push(call->params, (ast_expression*)fold_constgen_float(intrin->fold, QC_M_E));
vec_push(call->params, (ast_expression*)arg1);
/* return pow(QC_M_E, x) */
vec_push(body->exprs,
(ast_expression*)ast_return_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
(ast_expression*)call
)
);
@ -312,7 +299,7 @@ static ast_expression *intrin_exp(parser_t *parser) {
return (ast_expression*)value;
}
static ast_expression *intrin_isnan(parser_t *parser) {
static ast_expression *intrin_isnan(intrin_t *intrin) {
/*
* float isnan(float x) {
* float local;
@ -324,9 +311,9 @@ static ast_expression *intrin_isnan(parser_t *parser) {
static ast_value *value = NULL;
if (!value) {
ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
ast_value *local = ast_value_new (parser_ctx(parser), "local", TYPE_FLOAT);
ast_block *body = ast_block_new (parser_ctx(parser));
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_value *local = ast_value_new(parser_ctx(intrin->parser), "local", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
ast_function *func = NULL;
INTRIN_VAL(value, "isnan", func, "<float>", TYPE_FLOAT);
@ -334,7 +321,7 @@ static ast_expression *intrin_isnan(parser_t *parser) {
vec_push(body->locals, local);
vec_push(body->exprs,
(ast_expression*)ast_store_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_STORE_F,
(ast_expression*)local,
(ast_expression*)arg1
@ -343,9 +330,9 @@ static ast_expression *intrin_isnan(parser_t *parser) {
vec_push(body->exprs,
(ast_expression*)ast_return_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
(ast_expression*)ast_binary_new(
parser_ctx(parser),
parser_ctx(intrin->parser),
INSTR_NE_F,
(ast_expression*)arg1,
(ast_expression*)local
@ -354,7 +341,6 @@ static ast_expression *intrin_isnan(parser_t *parser) {
);
vec_push(value->expression.params, arg1);
vec_push(func->blocks, body);
INTRIN_REG(func, value);
@ -362,13 +348,19 @@ static ast_expression *intrin_isnan(parser_t *parser) {
return (ast_expression*)value;
}
#undef INTRIN_REG
#undef INTRIN_VAL
static ast_expression *intrin_debug_typestring(parser_t *parser) {
(void)parser;
/*
* TODO: make static (and handle ast_type_string) here for the builtin
* instead of in SYA parse close.
*/
ast_expression *intrin_debug_typestring(intrin_t *intrin) {
(void)intrin;
return (ast_expression*)0x1;
}
static intrin_t intrinsics[] = {
static const intrin_func_t intrinsics[] = {
{&intrin_exp, "__builtin_exp", "exp"},
{&intrin_mod, "__builtin_mod", "mod"},
{&intrin_pow, "__builtin_pow", "pow"},
@ -376,50 +368,48 @@ static intrin_t intrinsics[] = {
{&intrin_debug_typestring, "__builtin_debug_typestring", ""}
};
void intrin_intrinsics_destroy(parser_t *parser) {
/*size_t i;*/
(void)parser;
util_htdel(intrin_intrinsics());
static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
va_end(ap);
}
/* exposed */
intrin_t *intrin_init(parser_t *parser) {
intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
intrin->parser = parser;
intrin->fold = parser->fold;
intrin->intrinsics = NULL;
static ast_expression *intrin_func(parser_t *parser, const char *name) {
static bool init = false;
vec_append(intrin->intrinsics, sizeof(intrinsics)/sizeof(*intrinsics), intrinsics);
return intrin;
}
void intrin_cleanup(intrin_t *intrin) {
vec_free(intrin->intrinsics);
mem_d(intrin);
}
ast_expression *intrin_func(intrin_t *intrin, const char *name) {
size_t i = 0;
void *find;
/* register the intrinsics in the hashtable for O(1) lookup */
if (!init) {
for (i = 0; i < sizeof(intrinsics)/sizeof(*intrinsics); i++)
util_htset(intrin_intrinsics(), intrinsics[i].name, &intrinsics[i]);
init = true; /* only once */
}
/*
* jesus fucking christ, Blub design something less fucking
* impossible to use, like a ast_is_builtin(ast_expression *), also
* use a hashtable :P
*/
if ((find = (void*)parser_find_global(parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
for (i = 0; i < vec_size(parser->functions); ++i)
if (((ast_value*)find)->name && !strcmp(parser->functions[i]->name, ((ast_value*)find)->name) && parser->functions[i]->builtin < 0)
/* try current first */
if ((find = (void*)parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
for (i = 0; i < vec_size(intrin->parser->functions); ++i)
if (((ast_value*)find)->name && !strcmp(intrin->parser->functions[i]->name, ((ast_value*)find)->name) && intrin->parser->functions[i]->builtin < 0)
return (ast_expression*)find;
/* try name second */
for (i = 0; i < vec_size(intrin->intrinsics); i++)
if (!strcmp(intrin->intrinsics[i].name, name))
return intrin->intrinsics[i].intrin(intrin);
/* try alias third */
for (i = 0; i < vec_size(intrin->intrinsics); i++)
if (!strcmp(intrin->intrinsics[i].alias, name))
return intrin->intrinsics[i].intrin(intrin);
if ((find = util_htget(intrin_intrinsics(), name))) {
/* intrinsic is in table. This will "generate the function" so
* to speak (if it's not already generated).
*/
return ((intrin_t*)find)->intrin(parser);
}
/*
* check aliases now to see if there is an implementation of it.
*/
for (i = 0; i < sizeof(intrinsics) / sizeof(*intrinsics); i++)
if (!strcmp(intrinsics[i].alias, name))
return intrinsics[i].intrin(parser);
parseerror(parser, "need function: `%s` compiler depends on it", name);
intrin_error(intrin, "need function: `%s` compiler depends on it", name);
return NULL;
}

View file

@ -109,7 +109,7 @@ static ast_expression* parser_find_label(parser_t *parser, const char *name)
return NULL;
}
static ast_expression* parser_find_global(parser_t *parser, const char *name)
ast_expression* parser_find_global(parser_t *parser, const char *name)
{
ast_expression *var = (ast_expression*)util_htget(parser->aliases, parser_tokval(parser));
if (var)
@ -171,9 +171,6 @@ static ast_value* parser_find_typedef(parser_t *parser, const char *name, size_t
return NULL;
}
/* include intrinsics */
#include "intrin.h"
typedef struct
{
size_t etype; /* 0 = expression, others are operators */
@ -608,7 +605,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
return false;
} else if (!(out = fold_op(parser->fold, op, exprs))) {
/* generate a call to __builtin_mod */
ast_expression *mod = intrin_func(parser, "mod");
ast_expression *mod = intrin_func(parser->intrin, "mod");
ast_call *call = NULL;
if (!mod) return false; /* can return null for missing floor */
@ -810,7 +807,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!(out = fold_op(parser->fold, op, exprs))) {
ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow"));
ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser->intrin, "pow"));
vec_push(gencall->params, exprs[0]);
vec_push(gencall->params, exprs[1]);
out = (ast_expression*)gencall;
@ -1199,7 +1196,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
* TODO handle this at the intrinsic level with an ast_intrinsic
* node and codegen.
*/
if ((fun = sy->out[fid].out) == intrin_debug_typestring(parser)) {
if ((fun = sy->out[fid].out) == intrin_debug_typestring(parser->intrin)) {
char ty[1024];
if (fid+2 != vec_size(sy->out) ||
vec_last(sy->out).block)
@ -1561,7 +1558,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
* use the identifier as is.
*/
if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
var = intrin_func(parser, parser_tokval(parser));
var = intrin_func(parser->intrin, parser_tokval(parser));
}
if (!var) {
@ -5868,7 +5865,8 @@ parser_t *parser_create()
parser->reserved_version = NULL;
}
parser->fold = fold_init(parser);
parser->fold = fold_init (parser);
parser->intrin = intrin_init(parser);
return parser;
}
@ -5986,9 +5984,9 @@ static void parser_remove_ast(parser_t *parser)
if (parser->reserved_version)
ast_value_delete(parser->reserved_version);
util_htdel(parser->aliases);
intrin_intrinsics_destroy(parser);
util_htdel(parser->aliases);
fold_cleanup(parser->fold);
intrin_cleanup(parser->intrin);
}
void parser_cleanup(parser_t *parser)

View file

@ -27,6 +27,9 @@
#include "lexer.h"
#include "ast.h"
typedef struct intrin_s intrin_t;
typedef struct parser_s parser_t;
typedef struct {
struct parser_s *parser;
ast_value **imm_float; /* vector<ast_value*> */
@ -36,9 +39,21 @@ typedef struct {
hash_table_t *imm_string_dotranslate; /* map<string, ast_value*> */
} fold_t;
typedef struct {
ast_expression *(*intrin)(intrin_t *);
const char *name;
const char *alias;
} intrin_func_t;
struct intrin_s {
intrin_func_t *intrinsics; /* vector<intrin_func_t> */
parser_t *parser;
fold_t *fold;
};
#define parser_ctx(p) ((p)->lex->tok.ctx)
typedef struct parser_s {
struct parser_s {
lex_file *lex;
int tok;
@ -98,11 +113,14 @@ typedef struct parser_s {
/* collected information */
size_t max_param_count;
fold_t *fold;
} parser_t;
fold_t *fold;
intrin_t *intrin;
};
char *parser_strdup(const char *str);
/* parser.c */
char *parser_strdup (const char *str);
ast_expression *parser_find_global(parser_t *parser, const char *name);
/* fold.c */
fold_t *fold_init (parser_t *);
@ -115,4 +133,10 @@ ast_expression *fold_op (fold_t *, const oper_info *, ast_expression
int fold_cond (ir_value *, ast_function *, ast_ifthen *);
/* intrin.c */
intrin_t *intrin_init (parser_t *parser);
void intrin_cleanup (intrin_t *intrin);
ast_expression *intrin_func (intrin_t *intrin, const char *name);
ast_expression *intrin_debug_typestring(intrin_t *intrin);
#endif