From 0981d76cc73005a535645dc7313b9be88ba75574 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 6 Dec 2023 12:47:03 +0300 Subject: [PATCH] iImproved LLVM export (builtin function support) --- ir.g | 3 + ir_emit_llvm.c | 80 ++++++++++++++---------- ir_load.c | 161 ++++++++++++++++++++++++++++--------------------- ir_load_llvm.c | 15 +---- ir_main.c | 2 + ir_save.c | 2 + 6 files changed, 151 insertions(+), 112 deletions(-) diff --git a/ir.g b/ir.g index 94d124d..a222519 100644 --- a/ir.g +++ b/ir.g @@ -344,6 +344,9 @@ ir_func_proto(ir_parser_ctx *p, uint32_t *flags, uint8_t *ret_type, uint32_t *pa ( "__fastcall" {*flags |= IR_FASTCALL_FUNC;} + | + "__builtin" + {*flags |= IR_BUILTIN_FUNC;} )? {*params_count = n;} ; diff --git a/ir_emit_llvm.c b/ir_emit_llvm.c index 36c4cfa..f1d03c3 100644 --- a/ir_emit_llvm.c +++ b/ir_emit_llvm.c @@ -73,8 +73,8 @@ static const char *ir_type_llvm_name[IR_LAST_LLVM_TYPE] = { _("expf", EXP_F32) \ _("floor", FLOOR_F64) \ _("floorf", FLOOR_F32) \ - _("frexp", FREXP_F64) \ - _("frexpf", FREXP_F32) \ + _("isnan", ISNAN_F64) \ + _("isnanf", ISNAN_F32) \ _("ldexp", LDEXP_F64) \ _("ldexpf", LDEXP_F32) \ _("log", LOG_F64) \ @@ -211,8 +211,8 @@ static const char *ir_type_llvm_name[IR_LAST_LLVM_TYPE] = { _(TRUNC_F32, "llvm.trunc.f32", F32, 1, F32, ___, ___, ___) \ _(ROUND_F64, "llvm.round.f64", F64, 1, F64, ___, ___, ___) \ _(ROUND_F32, "llvm.round.f32", F32, 1, F32, ___, ___, ___) \ - _(FREXP_F64, "llvm.frexp.f64", F64I, 1, F64, ___, ___, ___) \ - _(FREXP_F32, "llvm.frexp.f32", F32I, 1, F32, ___, ___, ___) \ + _(ISNAN_F64, "fcmp uno double", /* fake */ F64I, 1, F64, ___, ___, ___) \ + _(ISNAN_F32, "fcmp uno float", /* fake */ F32I, 1, F32, ___, ___, ___) \ #define IR____ 0 #define IR_LLVM_INTRINSIC_ID(id, name, ret, num, arg1, arg2, arg3, arg4) \ @@ -688,16 +688,17 @@ static int ir_builtin_func(const char *name) int l = 0; int r = sizeof(ir_llvm_builtin_map) / sizeof(ir_llvm_builtin_map[0]); - while (l >= r) { + while (l <= r) { int n = (l + r) / 2; int ret = strcmp(name, ir_llvm_builtin_map[n].name); - if (ret < 0) { + if (ret > 0) { l = n + 1; - } else if (ret > 0) { + } else if (ret < 0) { r = n - 1; + } else { + return n; } - return n; } return -1; } @@ -706,6 +707,39 @@ static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn, ir_bit { int j, k, n; ir_ref last_arg = IR_UNUSED; + const char *name = NULL; + + if (IR_IS_CONST_REF(insn->op2)) { + const ir_insn *func = &ctx->ir_base[insn->op2]; + + IR_ASSERT(func->op == IR_FUNC); + name = ir_get_str(ctx, func->val.name); + if (func->proto) { + const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func->proto); + + if (proto->flags & IR_BUILTIN_FUNC) { + int n = ir_builtin_func(name); + if (n >= 0) { + ir_llvm_intrinsic_id id = ir_llvm_builtin_map[n].id; + + if (id == IR_LLVM_INTR_MEMSET + || id == IR_LLVM_INTR_MEMCPY + || id == IR_LLVM_INTR_MEMMOVE) { + last_arg = IR_FALSE; + } else if (id == IR_LLVM_INTR_ISNAN_F64 + || id == IR_LLVM_INTR_ISNAN_F32) { + ir_emit_def_ref(ctx, f, def); + fprintf(f, "%s ", ir_llvm_intrinsic_desc[id].name); + ir_emit_ref(ctx, f, insn->op3); + fprintf(f, ", 0.0\n"); + return; + } + ir_bitset_incl(used_intrinsics, id); + name = ir_llvm_intrinsic_desc[id].name; + } + } + } + } if (insn->type != IR_VOID) { ir_emit_def_ref(ctx, f, def); @@ -727,29 +761,6 @@ static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn, ir_bit // TODO: function prototype ??? if (IR_IS_CONST_REF(insn->op2)) { - const ir_insn *func = &ctx->ir_base[insn->op2]; - const char *name; - - IR_ASSERT(func->op == IR_FUNC); - name = ir_get_str(ctx, func->val.name); - if (func->proto) { - const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func->proto); - - if (proto->flags & IR_BUILTIN_FUNC) { - int n = ir_builtin_func(name); - if (n >= 0) { - ir_llvm_intrinsic_id id = ir_llvm_builtin_map[n].id; - - if (id == IR_LLVM_INTR_MEMSET - || id == IR_LLVM_INTR_MEMCPY - || id == IR_LLVM_INTR_MEMMOVE) { - last_arg = IR_FALSE; - } - ir_bitset_incl(used_intrinsics, ir_llvm_builtin_map[n].id); - name = ir_llvm_builtin_map[n].name; - } - } - } fprintf(f, "@%s", name); } else { ir_emit_ref(ctx, f, insn->op2); @@ -1217,7 +1228,12 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f) if (proto->flags & IR_BUILTIN_FUNC) { n = ir_builtin_func(name); if (n >= 0) { - name = ir_llvm_builtin_map[n].name; + ir_llvm_intrinsic_id id = ir_llvm_builtin_map[n].id; + if (id == IR_LLVM_INTR_ISNAN_F64 + || id == IR_LLVM_INTR_ISNAN_F32) { + continue; + } + name = ir_llvm_intrinsic_desc[id].name; } } if (!ctx->loader || !ctx->loader->has_sym || !ctx->loader->has_sym(ctx->loader, name)) { diff --git a/ir_load.c b/ir_load.c index 5114e3a..e0dc331 100644 --- a/ir_load.c +++ b/ir_load.c @@ -127,22 +127,23 @@ static void yy_error_str(const char *msg, const char *str); #define YY__POINT_POINT_POINT 17 #define YY__COLON 18 #define YY___FASTCALL 19 -#define YY__STAR 20 -#define YY__SLASH 21 -#define YY_NULL 22 -#define YY_INF 23 -#define YY_NAN 24 -#define YY__MINUS 25 -#define YY_ID 26 -#define YY_DECNUMBER 27 -#define YY_HEXNUMBER 28 -#define YY_FLOATNUMBER 29 -#define YY_CHARACTER 30 -#define YY_STRING 31 -#define YY_EOL 32 -#define YY_WS 33 -#define YY_ONE_LINE_COMMENT 34 -#define YY_COMMENT 35 +#define YY___BUILTIN 20 +#define YY__STAR 21 +#define YY__SLASH 22 +#define YY_NULL 23 +#define YY_INF 24 +#define YY_NAN 25 +#define YY__MINUS 26 +#define YY_ID 27 +#define YY_DECNUMBER 28 +#define YY_HEXNUMBER 29 +#define YY_FLOATNUMBER 30 +#define YY_CHARACTER 31 +#define YY_STRING 32 +#define YY_EOL 33 +#define YY_WS 34 +#define YY_ONE_LINE_COMMENT 35 +#define YY_COMMENT 36 static const char * sym_name[] = { "", @@ -165,6 +166,7 @@ static const char * sym_name[] = { "...", ":", "__fastcall", + "__builtin", "*", "/", "null", @@ -293,21 +295,21 @@ _yy_state_start: ch = *++YYPOS; if (ch != 'n') goto _yy_tunnel_4; ret = YY_EXTERN; - goto _yy_state_109; + goto _yy_state_116; case 'v': ch = *++YYPOS; if (ch == 'a') { ch = *++YYPOS; if (ch != 'r') goto _yy_tunnel_4; ret = YY_VAR; - goto _yy_state_109; + goto _yy_state_116; } else if (ch == 'o') { ch = *++YYPOS; if (ch != 'i') goto _yy_tunnel_4; ch = *++YYPOS; if (ch != 'd') goto _yy_tunnel_4; ret = YY_VOID; - goto _yy_state_109; + goto _yy_state_116; } else { goto _yy_tunnel_4; } @@ -321,7 +323,7 @@ _yy_state_start: ch = *++YYPOS; if (ch != 't') goto _yy_tunnel_4; ret = YY_CONST; - goto _yy_state_109; + goto _yy_state_116; case 'A': case 'B': case 'C': @@ -376,28 +378,28 @@ _yy_state_start: ch = *++YYPOS; if (ch != 'c') goto _yy_tunnel_4; ret = YY_FUNC; - goto _yy_state_109; + goto _yy_state_116; case 'i': ch = *++YYPOS; if (ch != 'n') goto _yy_tunnel_4; ch = *++YYPOS; if (ch != 'f') goto _yy_tunnel_4; ret = YY_INF; - goto _yy_state_109; + goto _yy_state_116; case 'n': ch = *++YYPOS; if (ch == 'a') { ch = *++YYPOS; if (ch != 'n') goto _yy_tunnel_4; ret = YY_NAN; - goto _yy_state_109; + goto _yy_state_116; } else if (ch == 'u') { ch = *++YYPOS; if (ch != 'l') goto _yy_tunnel_4; ch = *++YYPOS; if (ch != 'l') goto _yy_tunnel_4; ret = YY_NULL; - goto _yy_state_109; + goto _yy_state_116; } else { goto _yy_tunnel_4; } @@ -413,12 +415,12 @@ _yy_state_start: ch = *++YYPOS; if (ch != 'c') goto _yy_tunnel_4; ret = YY_STATIC; - goto _yy_state_109; + goto _yy_state_116; } else if (ch == 'y') { ch = *++YYPOS; if (ch != 'm') goto _yy_tunnel_4; ret = YY_SYM; - goto _yy_state_109; + goto _yy_state_116; } else { goto _yy_tunnel_4; } @@ -426,23 +428,41 @@ _yy_state_start: ch = *++YYPOS; if (ch != '_') goto _yy_tunnel_4; ch = *++YYPOS; - if (ch != 'f') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 'a') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 's') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 't') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 'c') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 'a') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 'l') goto _yy_tunnel_4; - ch = *++YYPOS; - if (ch != 'l') goto _yy_tunnel_4; - ret = YY___FASTCALL; - goto _yy_state_109; + if (ch == 'b') { + ch = *++YYPOS; + if (ch != 'u') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'i') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'l') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 't') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'i') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'n') goto _yy_tunnel_4; + ret = YY___BUILTIN; + goto _yy_state_116; + } else if (ch == 'f') { + ch = *++YYPOS; + if (ch != 'a') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 's') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 't') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'c') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'a') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'l') goto _yy_tunnel_4; + ch = *++YYPOS; + if (ch != 'l') goto _yy_tunnel_4; + ret = YY___FASTCALL; + goto _yy_state_116; + } else { + goto _yy_tunnel_4; + } case ';': YYPOS++; ret = YY__SEMICOLON; @@ -505,7 +525,7 @@ _yy_state_start: if (ch != 'x') goto _yy_tunnel_19; ch = *++YYPOS; if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) { - goto _yy_state_76; + goto _yy_state_77; } else { goto _yy_state_error; } @@ -706,12 +726,12 @@ _yy_state_50: if (ch == '+' || ch == '-') { ch = *++YYPOS; if ((ch >= '0' && ch <= '9')) { - goto _yy_state_79; + goto _yy_state_80; } else { goto _yy_state_error; } } else if ((ch >= '0' && ch <= '9')) { - goto _yy_state_79; + goto _yy_state_80; } else { goto _yy_state_error; } @@ -732,23 +752,23 @@ _yy_tunnel_58: } else { goto _yy_state_error; } -_yy_state_76: +_yy_state_77: ch = *++YYPOS; if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) { - goto _yy_state_76; + goto _yy_state_77; } else { ret = YY_HEXNUMBER; goto _yy_fin; } -_yy_state_79: +_yy_state_80: ch = *++YYPOS; if ((ch >= '0' && ch <= '9')) { - goto _yy_state_79; + goto _yy_state_80; } else { ret = YY_FLOATNUMBER; goto _yy_fin; } -_yy_state_109: +_yy_state_116: ch = *++YYPOS; if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= 'a' && ch <= 'z')) { goto _yy_state_4; @@ -1061,7 +1081,7 @@ static int parse_ir_sym_data(int sym, ir_loader *loader) { yy_error("sym_data_ref error"); } } - } else if (YY_IN_SET(sym, (YY_DECNUMBER,YY_HEXNUMBER,YY_FLOATNUMBER,YY_CHARACTER,YY_INF,YY_NAN,YY__MINUS), "\000\000\200\173\000")) { + } else if (YY_IN_SET(sym, (YY_DECNUMBER,YY_HEXNUMBER,YY_FLOATNUMBER,YY_CHARACTER,YY_INF,YY_NAN,YY__MINUS), "\000\000\000\367\000")) { sym = parse_const(sym, t, &val); if (loader->sym_data) { switch (ir_type_size[t]) { @@ -1204,9 +1224,14 @@ _yy_state_63: } else { yy_error_sym("unexpected", sym); } - if (sym == YY___FASTCALL) { - sym = get_sym(); - *flags |= IR_FASTCALL_FUNC; + if (sym == YY___FASTCALL || sym == YY___BUILTIN) { + if (sym == YY___FASTCALL) { + sym = get_sym(); + *flags |= IR_FASTCALL_FUNC; + } else { + sym = get_sym(); + *flags |= IR_BUILTIN_FUNC; + } } *params_count = n; return sym; @@ -1217,7 +1242,7 @@ static int parse_ir_insn(int sym, ir_parser_ctx *p) { const unsigned char *save_pos; const unsigned char *save_text; int save_line; - int alt73; + int alt74; const char *str, *str2 = NULL, *func; size_t len, len2 = 0, func_len; uint8_t op; @@ -1236,36 +1261,36 @@ static int parse_ir_insn(int sym, ir_parser_ctx *p) { save_pos = yy_pos; save_text = yy_text; save_line = yy_line; - alt73 = -2; + alt74 = -2; sym2 = sym; if (sym2 == YY_ID) { sym2 = get_sym(); - goto _yy_state_73_1; + goto _yy_state_74_1; } else { yy_error_sym("unexpected", sym2); } -_yy_state_73_1: +_yy_state_74_1: if (sym2 == YY_ID) { - alt73 = 74; - goto _yy_state_73; + alt74 = 75; + goto _yy_state_74; } else if (sym2 == YY__EQUAL) { - alt73 = 78; - goto _yy_state_73; + alt74 = 79; + goto _yy_state_74; } else { yy_error_sym("unexpected", sym2); } -_yy_state_73: +_yy_state_74: yy_pos = save_pos; yy_text = save_text; yy_line = save_line; - if (alt73 == 74) { + if (alt74 == 75) { sym = parse_type(sym, &t); sym = parse_ID(sym, &str, &len); if (sym == YY__COMMA) { sym = get_sym(); sym = parse_ID(sym, &str2, &len2); } - } else if (alt73 == 78) { + } else if (alt74 == 79) { sym = parse_ID(sym, &str, &len); } else { yy_error_sym("unexpected", sym); @@ -1339,7 +1364,7 @@ _yy_state_73: ref = ir_emit_N(p->ctx, IR_OPT(op, t), count.i32); if (sym == YY__LPAREN) { sym = get_sym(); - if (YY_IN_SET(sym, (YY_ID,YY_STRING,YY_DECNUMBER,YY_NULL,YY_FUNC), "\000\200\100\214\000")) { + if (YY_IN_SET(sym, (YY_ID,YY_STRING,YY_DECNUMBER,YY_NULL,YY_FUNC), "\000\200\200\030\001")) { sym = parse_val(sym, p, op, 1, &op1); n = 1; if (n > count.i32) yy_error("too many operands"); @@ -1361,7 +1386,7 @@ _yy_state_73: n = 0; if (sym == YY__LPAREN) { sym = get_sym(); - if (YY_IN_SET(sym, (YY_ID,YY_STRING,YY_DECNUMBER,YY_NULL,YY_FUNC), "\000\200\100\214\000")) { + if (YY_IN_SET(sym, (YY_ID,YY_STRING,YY_DECNUMBER,YY_NULL,YY_FUNC), "\000\200\200\030\001")) { sym = parse_val(sym, p, op, 1, &op1); n = 1; if (sym == YY__COMMA) { diff --git a/ir_load_llvm.c b/ir_load_llvm.c index 09eb518..5594b14 100644 --- a/ir_load_llvm.c +++ b/ir_load_llvm.c @@ -343,7 +343,9 @@ static ir_ref llvm2ir_fcmp_op_isnan(ir_ctx *ctx, LLVMValueRef expr, ir_type type } else { func = BUILTIN_FUNC_1("isnanf", IR_BOOL, IR_FLOAT); } - if (LLVMGetValueKind(op1) == LLVMConstantIntValueKind) { + if (LLVMGetValueKind(op0) == LLVMConstantFPValueKind) { + ref = ir_CALL_1(IR_BOOL, func, llvm2ir_op(ctx, op1, type)); + } else if (LLVMGetValueKind(op1) == LLVMConstantFPValueKind) { ref = ir_CALL_1(IR_BOOL, func, llvm2ir_op(ctx, op0, type)); } else { ref = ir_OR_B( @@ -926,17 +928,6 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp } return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type), llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_I32)); - } else if (STR_START(name, name_len, "llvm.frexp.")) { - IR_ASSERT(count == 2); - type = llvm2ir_type(LLVMGetReturnType(ftype)); - IR_ASSERT(IR_IS_TYPE_FP(type)); - if (type == IR_DOUBLE) { - func = BUILTIN_FUNC_2("frexp", IR_DOUBLE, IR_DOUBLE, IR_ADDR); - } else { - func = BUILTIN_FUNC_2("frexpf", IR_FLOAT, IR_FLOAT, IR_ADDR); - } - return ir_CALL_2(type, func, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type), - llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR)); } else if (STR_START(name, name_len, "llvm.log.")) { IR_ASSERT(count == 1); type = llvm2ir_type(LLVMGetReturnType(ftype)); diff --git a/ir_main.c b/ir_main.c index 2f94b14..25ed633 100644 --- a/ir_main.c +++ b/ir_main.c @@ -355,6 +355,8 @@ static void ir_dump_func_dcl(const char *name, uint32_t flags, ir_type ret_type, fprintf(f, "): %s", ir_type_cname[ret_type]); if (flags & IR_FASTCALL_FUNC) { fprintf(f, " __fastcall"); + } else if (flags & IR_BUILTIN_FUNC) { + fprintf(f, " __builtin"); } fprintf(f, ";\n"); } diff --git a/ir_save.c b/ir_save.c index 049e583..ab0bfb8 100644 --- a/ir_save.c +++ b/ir_save.c @@ -30,6 +30,8 @@ void ir_print_proto(const ir_ctx *ctx, ir_ref func_proto, FILE *f) fprintf(f, "): %s", ir_type_cname[proto->ret_type]); if (proto->flags & IR_FASTCALL_FUNC) { fprintf(f, " __fastcall"); + } else if (proto->flags & IR_BUILTIN_FUNC) { + fprintf(f, " __builtin"); } } else { fprintf(f, "(): int32_t");