iImproved LLVM export (builtin function support)

This commit is contained in:
Dmitry Stogov 2023-12-06 12:47:03 +03:00
parent 9a7318e621
commit 0981d76cc7
6 changed files with 151 additions and 112 deletions

3
ir.g
View File

@ -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;}
;

View File

@ -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)) {

161
ir_load.c
View File

@ -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[] = {
"<EOF>",
@ -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) {

View File

@ -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));

View File

@ -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");
}

View File

@ -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");