From: Dale Weiler Date: Tue, 3 Dec 2013 22:40:15 +0000 (-0500) Subject: Bitshifting operators <<, >>, and compound assignment versions now work in non-consta... X-Git-Tag: xonotic-v0.8.0~37 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=072bff44e6d574f5f32657875adcbe48fc27cb5b;p=xonotic%2Fgmqcc.git Bitshifting operators <<, >>, and compound assignment versions now work in non-constant expressions --- diff --git a/intrin.c b/intrin.c index 4df403b..f3ae818 100644 --- a/intrin.c +++ b/intrin.c @@ -1901,31 +1901,82 @@ static ast_expression *intrin_ln(intrin_t *intrin) { return (ast_expression*)value; } -#define LOG_VARIANT(NAME, BASE) \ -static ast_expression *intrin_##NAME(intrin_t *intrin) { \ - ast_value *value = NULL; \ - 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_block *body = ast_block_new(intrin_ctx(intrin)); \ - ast_function *func = intrin_value(intrin, &value, #NAME, TYPE_FLOAT); \ - 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(body->exprs, \ - (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; \ +static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) { + ast_value *value = NULL; + 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_block *body = ast_block_new(intrin_ctx(intrin)); + ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT); + + 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(body->exprs, + (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; +} + +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 @@ -1955,6 +2006,8 @@ static const intrin_func_t intrinsics[] = { {&intrin_log10, "__builtin_log10", "log10", 1}, {&intrin_log2, "__builtin_log2", "log2", 1}, {&intrin_logb, "__builtin_logb", "logb", 1}, + {&intrin_lshift, "__builtin_lshift", "", 2}, + {&intrin_rshift, "__builtin_rshift", "", 2}, {&intrin_epsilon, "__builtin_epsilon", "", 0}, {&intrin_nan, "__builtin_nan", "", 0}, {&intrin_inf, "__builtin_inf", "", 0}, diff --git a/lexer.c b/lexer.c index d153459..bfdc720 100644 --- a/lexer.c +++ b/lexer.c @@ -1233,12 +1233,16 @@ int lex_do(lex_file *lex) ch == '~' || ch == '^' /* ~=, ~, ^ */ ) { lex_tokench(lex, ch); - nextch = lex_getch(lex); - if ((nextch == '=' && ch != '<') || - (nextch == ch && ch != '!') || - (nextch == '<' && ch == '>')) { + + if ((nextch == '=' && ch != '<') || (nextch == '<' && ch == '>')) + 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 == '=') { lex_tokench(lex, nextch); if ((thirdch = lex_getch(lex)) == '>') diff --git a/parser.c b/parser.c index f3bfdfb..0e43f50 100644 --- a/parser.c +++ b/parser.c @@ -687,12 +687,44 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('<','<'): case opid2('>','>'): + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform shift 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 == 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(!(out = fold_op(parser->fold, op, exprs))) { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); + 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; case opid2('|','|'):