mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-19 06:40:49 +00:00
Merge branch 'master' into blub/bc3
This commit is contained in:
commit
22e6b8558b
4 changed files with 156 additions and 4 deletions
81
ast.c
81
ast.c
|
@ -193,6 +193,43 @@ void ast_binary_delete(ast_binary *self)
|
|||
mem_d(self);
|
||||
}
|
||||
|
||||
ast_unary* ast_unary_new(lex_ctx ctx, int op,
|
||||
ast_expression *expr)
|
||||
{
|
||||
ast_instantiate(ast_unary, ctx, ast_unary_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen);
|
||||
|
||||
self->op = op;
|
||||
self->operand = expr;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void ast_unary_delete(ast_unary *self)
|
||||
{
|
||||
ast_unref(self->operand);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
mem_d(self);
|
||||
}
|
||||
|
||||
ast_return* ast_return_new(lex_ctx ctx, int op,
|
||||
ast_expression *expr)
|
||||
{
|
||||
ast_instantiate(ast_return, ctx, ast_return_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_return_codegen);
|
||||
|
||||
self->operand = expr;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void ast_return_delete(ast_return *self)
|
||||
{
|
||||
ast_unref(self->operand);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
mem_d(self);
|
||||
}
|
||||
|
||||
ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
|
||||
{
|
||||
const ast_expression *outtype;
|
||||
|
@ -765,6 +802,50 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_value **out)
|
||||
{
|
||||
ast_expression_codegen *cgen;
|
||||
ir_value *operand;
|
||||
|
||||
/* In the context of a unary operation, we can disregard
|
||||
* the lvalue flag.
|
||||
*/
|
||||
(void)lvalue;
|
||||
|
||||
cgen = self->operand->expression.codegen;
|
||||
/* lvalue! */
|
||||
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
|
||||
return false;
|
||||
|
||||
*out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
|
||||
self->op, operand);
|
||||
if (!*out)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_value **out)
|
||||
{
|
||||
ast_expression_codegen *cgen;
|
||||
ir_value *operand;
|
||||
|
||||
/* In the context of a return operation, we can disregard
|
||||
* the lvalue flag.
|
||||
*/
|
||||
(void)lvalue;
|
||||
|
||||
cgen = self->operand->expression.codegen;
|
||||
/* lvalue! */
|
||||
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
|
||||
return false;
|
||||
|
||||
if (!ir_block_create_return(func->curblock, operand))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, ir_value **out)
|
||||
{
|
||||
ast_expression_codegen *cgen;
|
||||
|
|
38
ast.h
38
ast.h
|
@ -41,6 +41,8 @@ typedef struct ast_ifthen_s ast_ifthen;
|
|||
typedef struct ast_ternary_s ast_ternary;
|
||||
typedef struct ast_loop_s ast_loop;
|
||||
typedef struct ast_call_s ast_call;
|
||||
typedef struct ast_unary_s ast_unary;
|
||||
typedef struct ast_return_s ast_return;
|
||||
|
||||
/* Node interface with common components
|
||||
*/
|
||||
|
@ -150,6 +152,42 @@ void ast_binary_delete(ast_binary*);
|
|||
|
||||
bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
|
||||
|
||||
/* Unary
|
||||
*
|
||||
* Regular unary expressions: not,neg
|
||||
*/
|
||||
struct ast_unary_s
|
||||
{
|
||||
ast_expression_common expression;
|
||||
|
||||
int op;
|
||||
ast_expression *operand;
|
||||
};
|
||||
ast_unary* ast_unary_new(lex_ctx ctx,
|
||||
int op,
|
||||
ast_expression *expr);
|
||||
void ast_unary_delete(ast_unary*);
|
||||
|
||||
bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**);
|
||||
|
||||
/* Return
|
||||
*
|
||||
* Make sure 'return' only happens at the end of a block, otherwise the IR
|
||||
* will refuse to create further instructions.
|
||||
* This should be honored by the parser.
|
||||
*/
|
||||
struct ast_return_s
|
||||
{
|
||||
ast_expression_common expression;
|
||||
ast_expression *operand;
|
||||
};
|
||||
ast_return* ast_return_new(lex_ctx ctx,
|
||||
int op,
|
||||
ast_expression *expr);
|
||||
void ast_return_delete(ast_return*);
|
||||
|
||||
bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**);
|
||||
|
||||
/* Entity-field
|
||||
*
|
||||
* This must do 2 things:
|
||||
|
|
39
ir.c
39
ir.c
|
@ -1216,6 +1216,39 @@ ir_value* ir_block_create_binop(ir_block *self,
|
|||
return ir_block_create_general_instr(self, label, opcode, left, right, ot);
|
||||
}
|
||||
|
||||
ir_value* ir_block_create_unary(ir_block *self,
|
||||
const char *label, int opcode,
|
||||
ir_value *operand)
|
||||
{
|
||||
int ot = TYPE_FLOAT;
|
||||
switch (opcode) {
|
||||
case INSTR_NOT_F:
|
||||
case INSTR_NOT_V:
|
||||
case INSTR_NOT_S:
|
||||
case INSTR_NOT_ENT:
|
||||
case INSTR_NOT_FNC:
|
||||
#if 0
|
||||
case INSTR_NOT_I:
|
||||
#endif
|
||||
ot = TYPE_FLOAT;
|
||||
break;
|
||||
/* QC doesn't have other unary operations. We expect extensions to fill
|
||||
* the above list, otherwise we assume out-type = in-type, eg for an
|
||||
* unary minus
|
||||
*/
|
||||
default:
|
||||
ot = operand->vtype;
|
||||
break;
|
||||
};
|
||||
if (ot == TYPE_VOID) {
|
||||
/* The AST or parser were supposed to check this! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* let's use the general instruction creator and pass NULL for OPB */
|
||||
return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
|
||||
}
|
||||
|
||||
ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
|
||||
int op, ir_value *a, ir_value *b, int outype)
|
||||
{
|
||||
|
@ -2313,10 +2346,8 @@ tailcall:
|
|||
stmt.o1.u1 = stmt.o3.u1;
|
||||
stmt.o3.u1 = 0;
|
||||
}
|
||||
else if ((stmt.opcode >= INSTR_STORE_F &&
|
||||
stmt.opcode <= INSTR_STORE_FNC) ||
|
||||
(stmt.opcode >= INSTR_NOT_F &&
|
||||
stmt.opcode <= INSTR_NOT_FNC))
|
||||
else if (stmt.opcode >= INSTR_STORE_F &&
|
||||
stmt.opcode <= INSTR_STORE_FNC)
|
||||
{
|
||||
/* 2-operand instructions with A -> B */
|
||||
stmt.o2.u1 = stmt.o3.u1;
|
||||
|
|
2
ir.h
2
ir.h
|
@ -181,6 +181,8 @@ MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, entries);
|
|||
|
||||
ir_value* ir_block_create_binop(ir_block*, const char *label, int op,
|
||||
ir_value *left, ir_value *right);
|
||||
ir_value* ir_block_create_unary(ir_block*, const char *label, int op,
|
||||
ir_value *operand);
|
||||
bool GMQCC_WARN ir_block_create_store_op(ir_block*, int op, ir_value *target, ir_value *what);
|
||||
bool GMQCC_WARN ir_block_create_store(ir_block*, ir_value *target, ir_value *what);
|
||||
bool GMQCC_WARN ir_block_create_storep(ir_block*, ir_value *target, ir_value *what);
|
||||
|
|
Loading…
Reference in a new issue