Merge branch 'cooking'

This commit is contained in:
Dale Weiler 2013-10-31 08:22:54 -04:00
commit 1d745fd1f9
16 changed files with 306 additions and 310 deletions

5
ansi.c
View file

@ -23,7 +23,6 @@
#define GMQCC_PLATFORM_HEADER
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "platform.h"
#include "gmqcc.h"
@ -48,10 +47,6 @@ char *platform_strncat(char *dest, const char *src, size_t num) {
return strncat(dest, src, num);
}
const char *platform_tmpnam(char *str) {
return tmpnam(str);
}
const char *platform_getenv(const char *var) {
return getenv(var);
}

13
ast.c
View file

@ -1207,9 +1207,6 @@ ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype
self->fixedparams = NULL;
self->return_value = NULL;
self->accumulate = NULL;
self->accumulation = 0;
return self;
cleanup:
@ -1867,16 +1864,6 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
}
}
/* generate the call for any accumulation */
if (self->accumulate) {
ast_call *call = ast_call_new(ast_ctx(self), (ast_expression*)self->accumulate->vtype);
for (i = 0; i < vec_size(ec->params); i++)
vec_push(call->params, (ast_expression*)ec->params[i]);
vec_push(vec_last(self->blocks)->exprs, (ast_expression*)call);
self->ir_func->flags |= IR_FLAG_ACCUMULATE;
}
for (i = 0; i < vec_size(self->blocks); ++i) {
cgen = self->blocks[i]->expression.codegen;
if (!(*cgen)((ast_expression*)self->blocks[i], self, false, &dummy))

53
ast.h
View file

@ -25,6 +25,8 @@
#define GMQCC_AST_HDR
#include "ir.h"
typedef uint16_t ast_flag_t;
/* Note: I will not be using a _t suffix for the
* "main" ast node types for now.
*/
@ -53,6 +55,28 @@ typedef struct ast_label_s ast_label;
typedef struct ast_goto_s ast_goto;
typedef struct ast_argpipe_s ast_argpipe;
enum {
AST_FLAG_VARIADIC = 1 << 0,
AST_FLAG_NORETURN = 1 << 1,
AST_FLAG_INLINE = 1 << 2,
AST_FLAG_INITIALIZED = 1 << 3,
AST_FLAG_DEPRECATED = 1 << 4,
AST_FLAG_INCLUDE_DEF = 1 << 5,
AST_FLAG_IS_VARARG = 1 << 6,
AST_FLAG_ALIAS = 1 << 7,
AST_FLAG_ERASEABLE = 1 << 8,
AST_FLAG_ACCUMULATE = 1 << 9,
/*
* An array declared as []
* so that the size is taken from the initializer
*/
AST_FLAG_ARRAY_INIT = 1 << 10,
AST_FLAG_LAST,
AST_FLAG_TYPE_MASK = (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
};
enum {
TYPE_ast_node, /* 0 */
TYPE_ast_expression, /* 1 */
@ -134,7 +158,7 @@ struct ast_expression_common
/* arrays get a member-count */
size_t count;
ast_value* *params;
uint32_t flags;
ast_flag_t flags;
/* void foo(string...) gets varparam set as a restriction
* for variadic parameters
*/
@ -147,22 +171,6 @@ struct ast_expression_common
ir_value *outl;
ir_value *outr;
};
#define AST_FLAG_VARIADIC (1<<0)
#define AST_FLAG_NORETURN (1<<1)
#define AST_FLAG_INLINE (1<<2)
#define AST_FLAG_INITIALIZED (1<<3)
#define AST_FLAG_DEPRECATED (1<<4)
#define AST_FLAG_INCLUDE_DEF (1<<5)
#define AST_FLAG_IS_VARARG (1<<6)
#define AST_FLAG_ALIAS (1<<7)
#define AST_FLAG_ERASEABLE (1<<8)
#define AST_FLAG_ACCUMULATE (1<<9)
/*
* An array declared as []
* so that the size is taken from the initializer
*/
#define AST_FLAG_ARRAY_INIT (1<<10)
#define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
/* Value
*
@ -617,10 +625,6 @@ struct ast_function_s
int builtin;
/* function accumulation */
ast_function *accumulate; /* pointer to the next function in the chain */
size_t accumulation; /* base functions # of accumulations */
ir_function *ir_func;
ir_block *curblock;
ir_block **breakblocks;
@ -660,4 +664,11 @@ const char* ast_function_label(ast_function*, const char *prefix);
bool ast_function_codegen(ast_function *self, ir_builder *builder);
bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir);
/*
* If the condition creates a situation where this becomes -1 size it means there are
* more AST_FLAGs than the type ast_flag_t is capable of holding. So either eliminate
* the AST flag count or change the ast_flag_t typedef to a type large enough to accomodate
* all the flags.
*/
typedef int static_assert_is_ast_flag_safe [((AST_FLAG_LAST) <= (ast_flag_t)(-1)) ? 1 : -1];
#endif

34
fold.c
View file

@ -773,18 +773,28 @@ ast_expression *fold_intrin(fold_t *fold, const char *intrin, ast_expression **a
#define fold_can_1(X) ((X)->hasvalue && (X)->cvq == CV_CONST)
/*#define fold_can_2(X,Y) (fold_can_1(X) && fold_can_1(Y))*/
ast_expression *fold_superfluous(ast_expression *left, ast_expression *right, int op) {
static ast_expression *fold_superfluous(ast_expression *left, ast_expression *right, int op) {
ast_expression *swapped = NULL; /* using this as bool */
ast_value *load;
if (!ast_istype(left, ast_value) || !fold_can_1((load = (ast_value*)right)))
if (!ast_istype(right, ast_value) || !fold_can_1((load = (ast_value*)right))) {
swapped = left;
left = right;
right = swapped;
}
if (!ast_istype(right, ast_value) || !fold_can_1((load = (ast_value*)right)))
return NULL;
switch (op) {
case INSTR_MUL_F:
case INSTR_DIV_F:
if (swapped)
return NULL;
case INSTR_MUL_F:
if (fold_immvalue_float(load) == 1.0f) {
++opts_optimizationcount[OPTIM_PEEPHOLE];
return (ast_expression*)left;
ast_unref(right);
return left;
}
break;
@ -793,14 +803,16 @@ ast_expression *fold_superfluous(ast_expression *left, ast_expression *right, in
case INSTR_SUB_F:
if (fold_immvalue_float(load) == 0.0f) {
++opts_optimizationcount[OPTIM_PEEPHOLE];
return (ast_expression*)left;
ast_unref(right);
return left;
}
break;
case INSTR_MUL_V:
if (vec3_cmp(fold_immvalue_vector(load), vec3_create(1, 1, 1))) {
++opts_optimizationcount[OPTIM_PEEPHOLE];
return (ast_expression*)left;
ast_unref(right);
return left;
}
break;
@ -808,7 +820,8 @@ ast_expression *fold_superfluous(ast_expression *left, ast_expression *right, in
case INSTR_SUB_V:
if (vec3_cmp(fold_immvalue_vector(load), vec3_create(0, 0, 0))) {
++opts_optimizationcount[OPTIM_PEEPHOLE];
return (ast_expression*)left;
ast_unref(right);
return left;
}
break;
}
@ -816,6 +829,13 @@ ast_expression *fold_superfluous(ast_expression *left, ast_expression *right, in
return NULL;
}
ast_expression *fold_binary(lex_ctx_t ctx, int op, ast_expression *left, ast_expression *right) {
ast_expression *ret = fold_superfluous(left, right, op);
if (ret)
return ret;
return (ast_expression*)ast_binary_new(ctx, op, left, right);
}
static GMQCC_INLINE int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) {
if (isfloat(condval) && fold_can_1(condval) && OPTS_OPTIMIZATION(OPTIM_CONST_FOLD_DCE)) {
ast_expression_codegen *cgen;

81
ftepp.c
View file

@ -74,17 +74,13 @@ typedef struct ftepp_s {
char *itemname;
char *includename;
bool in_macro;
uint32_t predef_countval;
uint32_t predef_randval;
} ftepp_t;
/*
* Implement the predef subsystem now. We can do this safely with the
* help of lexer contexts.
*/
static uint32_t ftepp_predef_countval = 0;
static uint32_t ftepp_predef_randval = 0;
/* __DATE__ */
static char *ftepp_predef_date(lex_file *context) {
static char *ftepp_predef_date(ftepp_t *context) {
const struct tm *itime = NULL;
char *value = (char*)mem_a(82);
time_t rtime;
@ -99,7 +95,7 @@ static char *ftepp_predef_date(lex_file *context) {
}
/* __TIME__ */
static char *ftepp_predef_time(lex_file *context) {
static char *ftepp_predef_time(ftepp_t *context) {
const struct tm *itime = NULL;
char *value = (char*)mem_a(82);
time_t rtime;
@ -114,61 +110,58 @@ static char *ftepp_predef_time(lex_file *context) {
}
/* __LINE__ */
static char *ftepp_predef_line(lex_file *context) {
char *value;
util_asprintf(&value, "%d", (int)context->line);
static char *ftepp_predef_line(ftepp_t *context) {
char *value;
util_asprintf(&value, "%d", (int)context->lex->line);
return value;
}
/* __FILE__ */
static char *ftepp_predef_file(lex_file *context) {
size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
char *value = (char*)mem_a(length);
util_snprintf(value, length, "\"%s\"", context->name);
static char *ftepp_predef_file(ftepp_t *context) {
size_t length = strlen(context->lex->name) + 3; /* two quotes and a terminator */
char *value = (char*)mem_a(length);
util_snprintf(value, length, "\"%s\"", context->lex->name);
return value;
}
/* __COUNTER_LAST__ */
static char *ftepp_predef_counterlast(lex_file *context) {
char *value;
util_asprintf(&value, "%u", ftepp_predef_countval);
(void)context;
static char *ftepp_predef_counterlast(ftepp_t *context) {
char *value;
util_asprintf(&value, "%u", context->predef_countval);
return value;
}
/* __COUNTER__ */
static char *ftepp_predef_counter(lex_file *context) {
char *value;
ftepp_predef_countval ++;
util_asprintf(&value, "%u", ftepp_predef_countval);
(void)context;
static char *ftepp_predef_counter(ftepp_t *context) {
char *value;
context->predef_countval ++;
util_asprintf(&value, "%u", context->predef_countval);
return value;
}
/* __RANDOM__ */
static char *ftepp_predef_random(lex_file *context) {
char *value;
ftepp_predef_randval = (util_rand() % 0xFF) + 1;
util_asprintf(&value, "%u", ftepp_predef_randval);
static char *ftepp_predef_random(ftepp_t *context) {
char *value;
(void)context;
context->predef_randval = (util_rand() % 0xFF) + 1;
util_asprintf(&value, "%u", context->predef_randval);
return value;
}
/* __RANDOM_LAST__ */
static char *ftepp_predef_randomlast(lex_file *context) {
char *value;
util_asprintf(&value, "%u", ftepp_predef_randval);
static char *ftepp_predef_randomlast(ftepp_t *context) {
char *value;
(void)context;
util_asprintf(&value, "%u", context->predef_randval);
return value;
}
/* __TIMESTAMP__ */
static char *ftepp_predef_timestamp(lex_file *context) {
static char *ftepp_predef_timestamp(ftepp_t *context) {
struct stat finfo;
const char *find;
char *value;
size_t size;
if (stat(context->name, &finfo))
if (stat(context->lex->name, &finfo))
return util_strdup("\"<failed to determine timestamp>\"");
find = util_ctime(&finfo.st_mtime);
@ -183,7 +176,7 @@ static char *ftepp_predef_timestamp(lex_file *context) {
typedef struct {
const char *name;
char *(*func)(lex_file *);
char *(*func)(ftepp_t *);
} ftepp_predef_t;
static const ftepp_predef_t ftepp_predefs[] = {
@ -213,7 +206,7 @@ bool ftepp_predef_exists(const char *name) {
}
/* singleton because we're allowed */
static GMQCC_INLINE char *(*ftepp_predef(const char *name))(lex_file *context) {
static GMQCC_INLINE char *(*ftepp_predef(const char *name))(ftepp_t *context) {
size_t i = ftepp_predef_index(name);
return (i != 0) ? ftepp_predefs[i-1].func : NULL;
}
@ -305,8 +298,10 @@ static ftepp_t* ftepp_new(void)
ftepp = (ftepp_t*)mem_a(sizeof(*ftepp));
memset(ftepp, 0, sizeof(*ftepp));
ftepp->macros = util_htnew(HT_MACROS);
ftepp->output_on = true;
ftepp->macros = util_htnew(HT_MACROS);
ftepp->output_on = true;
ftepp->predef_countval = 0;
ftepp->predef_randval = 0;
return ftepp;
}
@ -1686,9 +1681,9 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
case TOKEN_TYPENAME:
/* is it a predef? */
if (OPTS_FLAG(FTEPP_PREDEFS)) {
char *(*predef)(lex_file*) = ftepp_predef(ftepp_tokval(ftepp));
char *(*predef)(ftepp_t*) = ftepp_predef(ftepp_tokval(ftepp));
if (predef) {
expand = predef(ftepp->lex);
expand = predef(ftepp);
ftepp_out (ftepp, expand, false);
ftepp_next(ftepp);

View file

@ -315,7 +315,6 @@ const char *util_ctime (const time_t *timer);
typedef struct fs_file_s fs_file_t;
bool util_isatty(fs_file_t *);
const char *util_tmpnam(char *);
/*
* A flexible vector implementation: all vector pointers contain some

4
ir.c
View file

@ -1586,10 +1586,6 @@ bool ir_block_create_return(ir_block *self, lex_ctx_t ctx, ir_value *v)
self->final = true;
/* can eliminate the return instructions for accumulation */
if (self->owner->flags & IR_FLAG_ACCUMULATE)
return true;
self->is_return = true;
in = ir_instr_new(ctx, self, INSTR_RETURN);
if (!in)

201
ir.h
View file

@ -24,69 +24,86 @@
#define GMQCC_IR_HDR
#include "gmqcc.h"
typedef struct
{
/*
* Type large enough to hold all the possible IR flags. This should be
* changed if the static assertion at the end of this file fails.
*/
typedef uint8_t ir_flag_t;
typedef struct ir_value_s ir_value;
typedef struct ir_instr_s ir_instr;
typedef struct ir_block_s ir_block;
typedef struct ir_function_s ir_function;
typedef struct ir_builder_s ir_builder;
typedef struct {
/* both inclusive */
size_t start;
size_t end;
} ir_life_entry_t;
struct ir_function_s;
typedef struct ir_value_s {
char *name;
int vtype;
int store;
lex_ctx_t context;
/* even the IR knows the subtype of a field */
int fieldtype;
/* and the output type of a function */
int outtype;
/* 'const' vs 'var' qualifier */
int cvq;
uint32_t flags;
enum {
IR_FLAG_HAS_ARRAYS = 1 << 0,
IR_FLAG_HAS_UNINITIALIZED = 1 << 1,
IR_FLAG_HAS_GOTO = 1 << 2,
IR_FLAG_INCLUDE_DEF = 1 << 3,
IR_FLAG_ERASEABLE = 1 << 4,
struct ir_instr_s **reads;
struct ir_instr_s **writes;
IR_FLAG_LAST,
IR_FLAG_MASK_NO_OVERLAP = (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED),
IR_FLAG_MASK_NO_LOCAL_TEMPS = (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
};
struct ir_value_s {
char *name;
int vtype;
int store;
lex_ctx_t context;
int fieldtype; /* even the IR knows the subtype of a field */
int outtype; /* and the output type of a function */
int cvq; /* 'const' vs 'var' qualifier */
ir_flag_t flags;
ir_instr **reads;
ir_instr **writes;
/* constantvalues */
bool hasvalue;
union {
qcfloat_t vfloat;
int vint;
vec3_t vvec;
int32_t ivec[3];
char *vstring;
struct ir_value_s *vpointer;
struct ir_function_s *vfunc;
qcfloat_t vfloat;
int vint;
vec3_t vvec;
int32_t ivec[3];
char *vstring;
ir_value *vpointer;
ir_function *vfunc;
} constval;
struct {
int32_t globaladdr;
int32_t name;
/* filled by the local-allocator */
int32_t local;
/* added for members */
int32_t addroffset;
/* to generate field-addresses early */
int32_t fieldaddr;
int32_t local; /* filled by the local-allocator */
int32_t addroffset; /* added for members */
int32_t fieldaddr; /* to generate field-addresses early */
} code;
/* for acessing vectors */
struct ir_value_s *members[3];
struct ir_value_s *memberof;
ir_value *members[3];
ir_value *memberof;
/* arrays will never overlap with temps */
bool unique_life;
/* temps living during a CALL must be locked */
bool locked;
bool callparam;
/* For the temp allocator */
ir_life_entry_t *life;
} ir_value;
bool unique_life; /* arrays will never overlap with temps */
bool locked; /* temps living during a CALL must be locked */
bool callparam;
/* ir_value can be a variable, or created by an operation */
/* if a result of an operation: the function should store
ir_life_entry_t *life; /* For the temp allocator */
};
/*
* ir_value can be a variable, or created by an operation
* if a result of an operation: the function should store
* it to remember to delete it / garbage collect it
*/
void ir_value_delete(ir_value*);
@ -100,19 +117,17 @@ bool ir_value_lives(ir_value*, size_t);
void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...));
/* PHI data */
typedef struct ir_phi_entry_s
{
ir_value *value;
struct ir_block_s *from;
typedef struct ir_phi_entry_s {
ir_value *value;
ir_block *from;
} ir_phi_entry_t;
/* instruction */
typedef struct ir_instr_s
{
int opcode;
lex_ctx_t context;
struct ir_instr_s {
int opcode;
lex_ctx_t context;
ir_value* (_ops[3]);
struct ir_block_s* (bops[2]);
ir_block* (bops[2]);
ir_phi_entry_t *phi;
ir_value **params;
@ -123,31 +138,30 @@ typedef struct ir_instr_s
/* For IFs */
bool likely;
struct ir_block_s *owner;
} ir_instr;
ir_block *owner;
};
/* block */
typedef struct ir_block_s
{
struct ir_block_s {
char *label;
lex_ctx_t context;
lex_ctx_t context;
bool final; /* once a jump is added we're done */
ir_instr **instr;
struct ir_block_s **entries;
struct ir_block_s **exits;
ir_value **living;
ir_instr **instr;
ir_block **entries;
ir_block **exits;
ir_value **living;
/* For the temp-allocation */
size_t entry_id;
size_t eid;
bool is_return;
struct ir_function_s *owner;
ir_function *owner;
bool generated;
size_t code_start;
} ir_block;
};
ir_value* ir_block_create_binop(ir_block*, lex_ctx_t, const char *label, int op, ir_value *left, ir_value *right);
ir_value* ir_block_create_unary(ir_block*, lex_ctx_t, const char *label, int op, ir_value *operand);
@ -170,7 +184,8 @@ bool GMQCC_WARN ir_block_create_return(ir_block*, lex_ctx_t, ir_value *opt_value
bool GMQCC_WARN ir_block_create_if(ir_block*, lex_ctx_t, ir_value *cond,
ir_block *ontrue, ir_block *onfalse);
/* A 'goto' is an actual 'goto' coded in QC, whereas
/*
* A 'goto' is an actual 'goto' coded in QC, whereas
* a 'jump' is a virtual construct which simply names the
* next block to go to.
* A goto usually becomes an OP_GOTO in the resulting code,
@ -180,37 +195,33 @@ bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx_t, ir_block *to);
bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx_t, ir_block *to);
/* function */
typedef struct ir_function_s
{
struct ir_function_s {
char *name;
int outtype;
int *params;
ir_block **blocks;
ir_flag_t flags;
int builtin;
uint32_t flags;
int builtin;
ir_value *value;
/* values generated from operations
/*
* values generated from operations
* which might get optimized away, so anything
* in there needs to be deleted in the dtor.
*/
ir_value **values;
/* locally defined variables */
ir_value **locals;
ir_value **locals; /* locally defined variables */
ir_value *value;
size_t allocated_locals;
size_t globaltemps;
ir_block* first;
ir_block* last;
ir_block* first;
ir_block* last;
lex_ctx_t context;
lex_ctx_t context;
/* for prototypes - first we generate all the
/*
* for prototypes - first we generate all the
* globals, and we remember teh function-defs
* so we can later fill in the entry pos
*
@ -221,30 +232,22 @@ typedef struct ir_function_s
/* for temp allocation */
size_t run_id;
struct ir_builder_s *owner;
ir_builder *owner;
/* vararg support: */
size_t max_varargs;
} ir_function;
};
#define IR_FLAG_HAS_ARRAYS (1<<1)
#define IR_FLAG_HAS_UNINITIALIZED (1<<2)
#define IR_FLAG_HAS_GOTO (1<<3)
#define IR_FLAG_INCLUDE_DEF (1<<4)
#define IR_FLAG_ERASEABLE (1<<5)
#define IR_FLAG_ACCUMULATE (1<<6)
#define IR_FLAG_MASK_NO_OVERLAP (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
#define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param);
bool GMQCC_WARN ir_function_finalize(ir_function*);
ir_block* ir_function_create_block(lex_ctx_t ctx, ir_function*, const char *label);
/* builder */
#define IR_HT_SIZE 1024
#define IR_HT_SIZE 1024
#define IR_MAX_VINSTR_TEMPS 1
typedef struct ir_builder_s
{
struct ir_builder_s {
char *name;
ir_function **functions;
ir_value **globals;
@ -277,7 +280,7 @@ typedef struct ir_builder_s
/* code generator */
code_t *code;
} ir_builder;
};
ir_builder* ir_builder_new(const char *modulename);
void ir_builder_delete(ir_builder*);
@ -293,7 +296,15 @@ void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
* Blub: don't use extern here, it's annoying and shows up in nm
* for some reason :P
*/
typedef int static_assert_is_32bit_float [(sizeof(int32_t) == 4)?1:-1];
typedef int static_assert_is_32bit_integer[(sizeof(qcfloat_t) == 4)?1:-1];
typedef int static_assert_is_32bit_float [(sizeof(int32_t) == 4) ? 1 : -1];
typedef int static_assert_is_32bit_integer[(sizeof(qcfloat_t) == 4) ? 1 : -1];
/*
* If the condition creates a situation where this becomes -1 size it means there are
* more IR_FLAGs than the type ir_flag_t is capable of holding. So either eliminate
* the IR flag count or change the ir_flag_t typedef to a type large enough to accomodate
* all the flags.
*/
typedef int static_assert_is_ir_flag_safe [((IR_FLAG_LAST) <= (ir_flag_t)(-1)) ? 1 : -1];
#endif

4
msvc.c
View file

@ -76,10 +76,6 @@ char *platform_strncat(char *dest, const char *src, size_t num) {
return strncat_s(dest, num, src, _TRUNCATE);
}
const char *platform_tmpnam(char *str) {
return tmpnam_s(str, L_tmpnam);
}
const char *platform_getenv(const char *var) {
char *buffer = (char *)platform_mem_allocate(GETENV_BUFFER);
size_t size;

156
parser.c
View file

@ -44,7 +44,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname);
static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg);
static void parseerror(parser_t *parser, const char *fmt, ...)
{
@ -521,10 +521,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
if (!(out = fold_op(parser->fold, op, exprs))) {
switch (exprs[0]->vtype) {
case TYPE_FLOAT:
out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_ADD_F, exprs[0], exprs[1]);
break;
case TYPE_VECTOR:
out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_ADD_V, exprs[0], exprs[1]);
break;
default:
compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
@ -546,10 +546,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
if (!(out = fold_op(parser->fold, op, exprs))) {
switch (exprs[0]->vtype) {
case TYPE_FLOAT:
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_SUB_F, exprs[0], exprs[1]);
break;
case TYPE_VECTOR:
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_SUB_V, exprs[0], exprs[1]);
break;
default:
compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
@ -576,15 +576,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
switch (exprs[0]->vtype) {
case TYPE_FLOAT:
if (exprs[1]->vtype == TYPE_VECTOR)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_FV, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_MUL_FV, exprs[0], exprs[1]);
else
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_MUL_F, exprs[0], exprs[1]);
break;
case TYPE_VECTOR:
if (exprs[1]->vtype == TYPE_FLOAT)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_MUL_VF, exprs[0], exprs[1]);
else
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
break;
default:
compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
@ -604,7 +604,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!(out = fold_op(parser->fold, op, exprs))) {
if (exprs[0]->vtype == TYPE_FLOAT)
out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
else {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
@ -657,7 +657,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
* since scalar ^ vector is not allowed.
*/
if (exprs[0]->vtype == TYPE_FLOAT) {
out = (ast_expression*)ast_binary_new(ctx,
out = fold_binary(ctx,
(op->id == opid1('^') ? VINSTR_BITXOR : op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND),
exprs[0], exprs[1]);
} else {
@ -670,11 +670,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
* Bitop all the values of the vector components against the
* vectors components in question.
*/
out = (ast_expression*)ast_binary_new(ctx,
out = fold_binary(ctx,
(op->id == opid1('^') ? VINSTR_BITXOR_V : op->id == opid1('|') ? VINSTR_BITOR_V : VINSTR_BITAND_V),
exprs[0], exprs[1]);
} else {
out = (ast_expression*)ast_binary_new(ctx,
out = fold_binary(ctx,
(op->id == opid1('^') ? VINSTR_BITXOR_VF : op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF),
exprs[0], exprs[1]);
}
@ -727,7 +727,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
}
}
out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]);
out = fold_binary(ctx, generated_op, exprs[0], exprs[1]);
}
break;
@ -774,7 +774,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!(out = fold_op(parser->fold, op, exprs))) {
out = (ast_expression*)ast_binary_new(
out = fold_binary(
parser_ctx(parser),
VINSTR_CROSS,
exprs[0],
@ -795,6 +795,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!(out = fold_op(parser->fold, op, exprs))) {
/* This whole block is NOT fold_binary safe */
ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]);
eq->refs = AST_REF_NONE;
@ -835,7 +836,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
return false;
}
if (!(out = fold_op(parser->fold, op, exprs)))
out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]);
out = fold_binary(ctx, generated_op, exprs[0], exprs[1]);
break;
case opid2('!', '='):
if (exprs[0]->vtype != exprs[1]->vtype) {
@ -845,7 +846,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
return false;
}
if (!(out = fold_op(parser->fold, op, exprs)))
out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]);
out = fold_binary(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]);
break;
case opid2('=', '='):
if (exprs[0]->vtype != exprs[1]->vtype) {
@ -855,7 +856,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
return false;
}
if (!(out = fold_op(parser->fold, op, exprs)))
out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]);
out = fold_binary(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]);
break;
case opid1('='):
@ -969,9 +970,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!out)
return false;
out = (ast_expression*)ast_binary_new(ctx, subop,
out,
(ast_expression*)parser->fold->imm_float[1]);
out = fold_binary(ctx, subop,
out,
(ast_expression*)parser->fold->imm_float[1]);
break;
case opid2('+','='):
@ -1036,9 +1037,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
out = (ast_expression*)ast_binstore_new(ctx, assignop, INSTR_MUL_VF,
exprs[0], exprs[1]);
} else {
out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F,
(ast_expression*)parser->fold->imm_float[1],
exprs[1]);
out = fold_binary(ctx, INSTR_DIV_F,
(ast_expression*)parser->fold->imm_float[1],
exprs[1]);
if (!out) {
compile_error(ctx, "internal error: failed to generate division");
return false;
@ -1095,9 +1096,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
else
assignop = type_store_instr[exprs[0]->vtype];
if (exprs[0]->vtype == TYPE_FLOAT)
out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]);
out = fold_binary(ctx, INSTR_BITAND, exprs[0], exprs[1]);
else
out = (ast_expression*)ast_binary_new(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]);
out = fold_binary(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]);
if (!out)
return false;
(void)check_write_to(ctx, exprs[0]);
@ -1117,9 +1118,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
}
if (!(out = fold_op(parser->fold, op, exprs))) {
if (exprs[0]->vtype == TYPE_FLOAT) {
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]);
out = fold_binary(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]);
} else {
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, (ast_expression*)parser->fold->imm_vector[1], exprs[0]);
out = fold_binary(ctx, INSTR_SUB_V, (ast_expression*)parser->fold->imm_vector[1], exprs[0]);
}
}
break;
@ -1422,7 +1423,7 @@ static ast_expression* parse_vararg_do(parser_t *parser)
return NULL;
}
typevar = parse_typename(parser, NULL, NULL);
typevar = parse_typename(parser, NULL, NULL, NULL);
if (!typevar) {
ast_unref(idx);
return NULL;
@ -3984,59 +3985,28 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
}
}
if (var->hasvalue && !(var->expression.flags & AST_FLAG_ACCUMULATE)) {
parseerror(parser, "function `%s` declared with multiple bodies", var->name);
ast_block_delete(block);
goto enderr;
}
/* accumulation? */
if (var->hasvalue && var->expression.vtype == TYPE_FUNCTION) {
ast_value *accum = NULL;
ast_function *previous = NULL;
char acname[1024];
/* only void please */
if (var->expression.next->vtype != TYPE_VOID) {
parseerror(parser, "accumulated function `%s` declared with return type `%s` (accumulated functions must return void)",
var->name,
type_name[var->expression.next->vtype]
);
if (var->hasvalue) {
if (!(var->expression.flags & AST_FLAG_ACCUMULATE)) {
parseerror(parser, "function `%s` declared with multiple bodies", var->name);
ast_block_delete(block);
goto enderr;
}
func = var->constval.vfunc;
/* generate a new name increasing the accumulation count*/
util_snprintf(acname, sizeof(acname), "##ACCUMULATE_%s_%d", var->name, var->constval.vfunc->accumulation++);
accum = ast_value_new(parser_ctx(parser), acname, ((ast_expression*)var)->vtype);
if (!accum)
return false;
ast_type_adopt(accum, var);
func = ast_function_new(ast_ctx(var), NULL, accum);
if (!func)
return false;
parser_addglobal(parser, acname, (ast_expression*)accum);
vec_push(parser->functions, func);
/* update the previous calls accumulate pointer for the codegen */
previous = var->constval.vfunc;
while (previous->accumulate)
previous = previous->accumulate;
if (ast_istype(previous, ast_function))
previous->accumulate = func;
if (!func) {
parseerror(parser, "internal error: NULL function: `%s`", var->name);
ast_block_delete(block);
goto enderr;
}
} else {
func = ast_function_new(ast_ctx(var), var->name, var);
vec_push(parser->functions, func);
}
if (!func) {
parseerror(parser, "failed to allocate function for `%s`", var->name);
ast_block_delete(block);
goto enderr;
if (!func) {
parseerror(parser, "failed to allocate function for `%s`", var->name);
ast_block_delete(block);
goto enderr;
}
vec_push(parser->functions, func);
}
parser_enterblock(parser);
@ -4064,13 +4034,13 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
}
}
if (var->argcounter) {
if (var->argcounter && !func->argc) {
ast_value *argc = ast_value_new(ast_ctx(var), var->argcounter, TYPE_FLOAT);
parser_addlocal(parser, argc->name, (ast_expression*)argc);
func->argc = argc;
}
if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) {
if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC && !func->varargs) {
char name[1024];
ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY);
varargs->expression.flags |= AST_FLAG_IS_VARARG;
@ -4100,7 +4070,6 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
vec_push(func->blocks, block);
parser->function = old;
if (!parser_leaveblock(parser))
retval = false;
@ -4537,7 +4506,6 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const
return parser_create_array_getter_impl(parser, array);
}
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
{
lex_ctx_t ctx;
@ -4563,6 +4531,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
/* parse variables until we hit a closing paren */
while (parser->tok != ')') {
bool is_varargs = false;
if (!first) {
/* there must be commas between them */
if (parser->tok != ',') {
@ -4576,10 +4546,13 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
}
first = false;
if (parser->tok == TOKEN_DOTS) {
param = parse_typename(parser, NULL, NULL, &is_varargs);
if (!param && !is_varargs)
goto on_error;
if (is_varargs) {
/* '...' indicates a varargs function */
variadic = true;
if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) {
if (parser->tok != ')' && parser->tok != TOKEN_IDENT) {
parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
goto on_error;
}
@ -4590,13 +4563,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
goto on_error;
}
}
}
else
{
/* for anything else just parse a typename */
param = parse_typename(parser, NULL, NULL);
if (!param)
goto on_error;
} else {
vec_push(params, param);
if (param->expression.vtype >= TYPE_VARIANT) {
char tname[1024]; /* typename is reserved in C++ */
@ -4748,7 +4715,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var)
* void() foo(), bar
* then the type-information 'void()' can be stored in 'storebase'
*/
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef)
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg)
{
ast_value *var, *tmp;
lex_ctx_t ctx;
@ -4758,6 +4725,8 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
bool wasarray = false;
size_t morefields = 0;
bool vararg = (parser->tok == TOKEN_DOTS);
ctx = parser_ctx(parser);
/* types may start with a dot */
@ -4781,6 +4750,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
morefields += 3;
else
break;
vararg = false;
if (!parser_next(parser)) {
parseerror(parser, "expected typename for field definition");
return NULL;
@ -4790,6 +4760,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
if (parser->tok == TOKEN_IDENT)
cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0);
if (!cached_typedef && parser->tok != TOKEN_TYPENAME) {
if (vararg && is_vararg) {
*is_vararg = true;
return NULL;
}
parseerror(parser, "expected typename");
return NULL;
}
@ -4910,7 +4884,7 @@ static bool parse_typedef(parser_t *parser)
ast_value *typevar, *oldtype;
ast_expression *old;
typevar = parse_typename(parser, NULL, NULL);
typevar = parse_typename(parser, NULL, NULL, NULL);
if (!typevar)
return false;
@ -5080,7 +5054,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
parseerror(parser, "`static` qualifier is not supported in global scope");
/* get the first complete variable */
var = parse_typename(parser, &basetype, cached_typedef);
var = parse_typename(parser, &basetype, cached_typedef, NULL);
if (!var) {
if (basetype)
ast_delete(basetype);

View file

@ -134,7 +134,7 @@ bool fold_generate (fold_t *, ir_builder *);
ast_expression *fold_op (fold_t *, const oper_info *, ast_expression **);
ast_expression *fold_intrin (fold_t *, const char *, ast_expression **);
ast_expression *fold_superfluous (ast_expression *, ast_expression *, int);
ast_expression *fold_binary (lex_ctx_t ctx, int, ast_expression *, ast_expression *);
int fold_cond_ifthen (ir_value *, ast_function *, ast_ifthen *);
int fold_cond_ternary (ir_value *, ast_function *, ast_ternary *);

View file

@ -185,24 +185,6 @@ const char *platform_ctime(const time_t *timer);
*/
char *platform_strncat(char *dest, const char *src, size_t num);
/*
* Function: platform_tmpnam
* Generates names you can use to create temporary files.
*
* Parameters:
* str - Pointer that will hold the generated name and will be identical
* to the name returned by the function. This is a convenient way
* to save the generated name.
*
* Returns:
* Pointer to the name generate or *NULL* if there is a failure. Failure
* can occur if you attempt more than TMP_MAX calls.
*
* Remarks:
* Returns a name unique in the current workign directory.
*/
const char *platform_tmpnam(char *str);
/*
* Function: platform_getenv
* Get a value from the current enviroment.

4
test.c
View file

@ -163,8 +163,8 @@ static int task_pclose(fs_file_t **handles) {
char *cmd = NULL;
popen_t *open = (popen_t*)mem_a(sizeof(popen_t));
util_tmpnam(open->name_err);
util_tmpnam(open->name_out);
tmpnam(open->name_err);
tmpnam(open->name_out);
(void)mode; /* excluded */

27
tests/dots.qc Normal file
View file

@ -0,0 +1,27 @@
entity self;
.float f;
..float fp;
...float fpp;
void try(entity e, ...float pp) {
print("and: ", ftos( e.(e.(e.pp)) ), "\n");
}
typedef float Float;
void try2(entity e, ...Float pp) {
print("and: ", ftos( e.(e.(e.pp)) ), "\n");
}
// whereas the varargs are tested in vararg tests
void main() {
self = spawn();
self.f = 123;
self.fp = f;
self.fpp = fp;
print(ftos( self.(self.fp) ), "\n");
print(ftos( self.(self.(self.fpp)) ), "\n");
try(self, fpp);
try2(self, fpp);
}

8
tests/dots.tmpl Normal file
View file

@ -0,0 +1,8 @@
I: dots.qc
D: TOKEN_DOTS disambiguation
T: -execute
C: -std=fteqcc
M: 123
M: 123
M: and: 123
M: and: 123

5
util.c
View file

@ -281,11 +281,6 @@ bool util_isatty(fs_file_t *file) {
if (file == (fs_file_t*)stderr) return !!platform_isatty(STDERR_FILENO);
return false;
}
const char *util_tmpnam(char *str) {
return platform_tmpnam(str);
}
/*
* A small noncryptographic PRNG based on:
* http://burtleburtle.net/bob/rand/smallprng.html