mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-30 15:41:12 +00:00
Bitshifting operators <<, >>, and compound assignment versions now work in non-constant expressions
This commit is contained in:
parent
af53c0cb83
commit
072bff44e6
3 changed files with 121 additions and 32 deletions
101
intrin.c
101
intrin.c
|
@ -1901,31 +1901,82 @@ static ast_expression *intrin_ln(intrin_t *intrin) {
|
||||||
return (ast_expression*)value;
|
return (ast_expression*)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOG_VARIANT(NAME, BASE) \
|
static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) {
|
||||||
static ast_expression *intrin_##NAME(intrin_t *intrin) { \
|
ast_value *value = NULL;
|
||||||
ast_value *value = NULL; \
|
ast_call *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", name));
|
||||||
ast_call *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", #NAME)); \
|
ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
|
||||||
ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT); \
|
ast_block *body = ast_block_new(intrin_ctx(intrin));
|
||||||
ast_block *body = ast_block_new(intrin_ctx(intrin)); \
|
ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT);
|
||||||
ast_function *func = intrin_value(intrin, &value, #NAME, TYPE_FLOAT); \
|
|
||||||
vec_push(value->expression.params, arg1); \
|
vec_push(value->expression.params, arg1);
|
||||||
vec_push(callln->params, (ast_expression*)arg1); \
|
|
||||||
vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, BASE)); \
|
vec_push(callln->params, (ast_expression*)arg1);
|
||||||
vec_push(body->exprs, \
|
vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, base));
|
||||||
(ast_expression*)ast_return_new( \
|
|
||||||
intrin_ctx(intrin), \
|
vec_push(body->exprs,
|
||||||
(ast_expression*)callln \
|
(ast_expression*)ast_return_new(
|
||||||
) \
|
intrin_ctx(intrin),
|
||||||
); \
|
(ast_expression*)callln
|
||||||
vec_push(func->blocks, body); \
|
)
|
||||||
intrin_reg(intrin, value, func); \
|
);
|
||||||
return (ast_expression*)value; \
|
|
||||||
|
vec_push(func->blocks, body);
|
||||||
|
intrin_reg(intrin, value, func);
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_expression *intrin_log(intrin_t *intrin) {
|
||||||
|
return intrin_log_variant(intrin, "log", 2.7182818284590452354);
|
||||||
|
}
|
||||||
|
static ast_expression *intrin_log10(intrin_t *intrin) {
|
||||||
|
return intrin_log_variant(intrin, "log10", 10);
|
||||||
|
}
|
||||||
|
static ast_expression *intrin_log2(intrin_t *intrin) {
|
||||||
|
return intrin_log_variant(intrin, "log2", 2);
|
||||||
|
}
|
||||||
|
static ast_expression *intrin_logb(intrin_t *intrin) {
|
||||||
|
/* FLT_RADIX == 2 for now */
|
||||||
|
return intrin_log_variant(intrin, "log2", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) {
|
||||||
|
ast_value *value = NULL;
|
||||||
|
ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
|
||||||
|
ast_value *a = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
|
||||||
|
ast_value *b = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
|
||||||
|
ast_block *body = ast_block_new(intrin_ctx(intrin));
|
||||||
|
ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT);
|
||||||
|
|
||||||
|
vec_push(value->expression.params, a);
|
||||||
|
vec_push(value->expression.params, b);
|
||||||
|
|
||||||
|
vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
|
||||||
|
vec_push(callpow->params, (ast_expression*)b);
|
||||||
|
|
||||||
|
vec_push(body->exprs,
|
||||||
|
(ast_expression*)ast_return_new(
|
||||||
|
intrin_ctx(intrin),
|
||||||
|
(ast_expression*)ast_binary_new(
|
||||||
|
intrin_ctx(intrin),
|
||||||
|
instr,
|
||||||
|
(ast_expression*)a,
|
||||||
|
(ast_expression*)callpow
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_push(func->blocks, body);
|
||||||
|
intrin_reg(intrin, value, func);
|
||||||
|
return (ast_expression*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_expression *intrin_lshift(intrin_t *intrin) {
|
||||||
|
return intrin_shift_variant(intrin, "lshift", INSTR_MUL_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_expression *intrin_rshift(intrin_t *intrin) {
|
||||||
|
return intrin_shift_variant(intrin, "rshift", INSTR_DIV_F);
|
||||||
}
|
}
|
||||||
LOG_VARIANT(log, 2.7182818284590452354)
|
|
||||||
LOG_VARIANT(log10, 10)
|
|
||||||
LOG_VARIANT(log2, 2)
|
|
||||||
LOG_VARIANT(logb, 2) /* FLT_RADIX == 2 for now */
|
|
||||||
#undef LOG_VARIANT
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: make static (and handle ast_type_string) here for the builtin
|
* TODO: make static (and handle ast_type_string) here for the builtin
|
||||||
|
@ -1955,6 +2006,8 @@ static const intrin_func_t intrinsics[] = {
|
||||||
{&intrin_log10, "__builtin_log10", "log10", 1},
|
{&intrin_log10, "__builtin_log10", "log10", 1},
|
||||||
{&intrin_log2, "__builtin_log2", "log2", 1},
|
{&intrin_log2, "__builtin_log2", "log2", 1},
|
||||||
{&intrin_logb, "__builtin_logb", "logb", 1},
|
{&intrin_logb, "__builtin_logb", "logb", 1},
|
||||||
|
{&intrin_lshift, "__builtin_lshift", "", 2},
|
||||||
|
{&intrin_rshift, "__builtin_rshift", "", 2},
|
||||||
{&intrin_epsilon, "__builtin_epsilon", "", 0},
|
{&intrin_epsilon, "__builtin_epsilon", "", 0},
|
||||||
{&intrin_nan, "__builtin_nan", "", 0},
|
{&intrin_nan, "__builtin_nan", "", 0},
|
||||||
{&intrin_inf, "__builtin_inf", "", 0},
|
{&intrin_inf, "__builtin_inf", "", 0},
|
||||||
|
|
12
lexer.c
12
lexer.c
|
@ -1233,12 +1233,16 @@ int lex_do(lex_file *lex)
|
||||||
ch == '~' || ch == '^' /* ~=, ~, ^ */
|
ch == '~' || ch == '^' /* ~=, ~, ^ */
|
||||||
) {
|
) {
|
||||||
lex_tokench(lex, ch);
|
lex_tokench(lex, ch);
|
||||||
|
|
||||||
nextch = lex_getch(lex);
|
nextch = lex_getch(lex);
|
||||||
if ((nextch == '=' && ch != '<') ||
|
|
||||||
(nextch == ch && ch != '!') ||
|
if ((nextch == '=' && ch != '<') || (nextch == '<' && ch == '>'))
|
||||||
(nextch == '<' && ch == '>')) {
|
|
||||||
lex_tokench(lex, nextch);
|
lex_tokench(lex, nextch);
|
||||||
|
else if (nextch == ch && ch != '!') {
|
||||||
|
lex_tokench(lex, nextch);
|
||||||
|
if ((thirdch = lex_getch(lex)) == '=')
|
||||||
|
lex_tokench(lex, thirdch);
|
||||||
|
else
|
||||||
|
lex_ungetch(lex, thirdch);
|
||||||
} else if (ch == '<' && nextch == '=') {
|
} else if (ch == '<' && nextch == '=') {
|
||||||
lex_tokench(lex, nextch);
|
lex_tokench(lex, nextch);
|
||||||
if ((thirdch = lex_getch(lex)) == '>')
|
if ((thirdch = lex_getch(lex)) == '>')
|
||||||
|
|
40
parser.c
40
parser.c
|
@ -687,12 +687,44 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
|
||||||
|
|
||||||
case opid2('<','<'):
|
case opid2('<','<'):
|
||||||
case opid2('>','>'):
|
case opid2('>','>'):
|
||||||
case opid3('<','<','='):
|
if (NotSameType(TYPE_FLOAT)) {
|
||||||
case opid3('>','>','='):
|
compile_error(ctx, "invalid types used in expression: cannot perform shift between types %s and %s",
|
||||||
if(!(out = fold_op(parser->fold, op, exprs))) {
|
type_name[exprs[0]->vtype],
|
||||||
compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts");
|
type_name[exprs[1]->vtype]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(out = fold_op(parser->fold, op, exprs))) {
|
||||||
|
ast_expression *shift = intrin_func(parser->intrin, (op->id == opid2('<','<')) ? "__builtin_lshift" : "__builtin_rshift");
|
||||||
|
ast_call *call = ast_call_new(parser_ctx(parser), shift);
|
||||||
|
vec_push(call->params, exprs[0]);
|
||||||
|
vec_push(call->params, exprs[1]);
|
||||||
|
out = (ast_expression*)call;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case opid3('<','<','='):
|
||||||
|
case opid3('>','>','='):
|
||||||
|
if (NotSameType(TYPE_FLOAT)) {
|
||||||
|
compile_error(ctx, "invalid types used in expression: cannot perform shift operation between types %s and %s",
|
||||||
|
type_name[exprs[0]->vtype],
|
||||||
|
type_name[exprs[1]->vtype]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(out = fold_op(parser->fold, op, exprs))) {
|
||||||
|
ast_expression *shift = intrin_func(parser->intrin, (op->id == opid3('<','<','=')) ? "__builtin_lshift" : "__builtin_rshift");
|
||||||
|
ast_call *call = ast_call_new(parser_ctx(parser), shift);
|
||||||
|
vec_push(call->params, exprs[0]);
|
||||||
|
vec_push(call->params, exprs[1]);
|
||||||
|
out = (ast_expression*)ast_store_new(
|
||||||
|
parser_ctx(parser),
|
||||||
|
INSTR_STORE_F,
|
||||||
|
exprs[0],
|
||||||
|
(ast_expression*)call
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case opid2('|','|'):
|
case opid2('|','|'):
|
||||||
|
|
Loading…
Reference in a new issue