From 1fda44cbc85a61da048017b0820ab82d1a9817df Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 16:57:49 +0200 Subject: [PATCH 01/10] translate-c: support conversion to/from fp types --- src/translate_c.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 43783cf1c0f4..e466e9d56e6b 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1915,17 +1915,29 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralToBoolean"); return nullptr; case ZigClangCK_IntegralToFloating: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralToFloating"); - return nullptr; + case ZigClangCK_FloatingToIntegral: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + const bool int_to_float = (ZigClangCK)stmt->getCastKind() == ZigClangCK_IntegralToFloating; + const char *fn = int_to_float ? "intToFloat" : "floatToInt"; + AstNode *node = trans_create_node_builtin_fn_call_str(c, fn); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(target_node); + return maybe_suppress_result(c, result_used, node); + } case ZigClangCK_FixedPointCast: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FixedPointCast"); return nullptr; case ZigClangCK_FixedPointToBoolean: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FixedPointToBoolean"); return nullptr; - case ZigClangCK_FloatingToIntegral: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingToIntegral"); - return nullptr; case ZigClangCK_FloatingToBoolean: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_FloatingToBoolean"); return nullptr; From 6d95c5d15c93faf1ac2bed4059b9278f5a997654 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 20:43:08 +0200 Subject: [PATCH 02/10] translate-c: Parse float/double literals --- src/translate_c.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index e466e9d56e6b..b6841cbada32 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -522,7 +522,18 @@ static AstNode *trans_create_node_apint(Context *c, const ZigClangAPSInt *aps_in ZigClangAPSInt_getNumWords(negated), true); ZigClangAPSInt_free(negated); return node; +} +static AstNode *trans_create_node_apfloat(Context *c, const llvm::APFloat &ap_float) { + uint8_t buf[128]; + size_t written = ap_float.convertToHexString((char *)buf, 0, false, + llvm::APFloat::rmNearestTiesToEven); + AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); + node->data.float_literal.bigfloat = allocate(1); + if (bigfloat_init_buf(node->data.float_literal.bigfloat, buf, written)) { + node->data.float_literal.overflow = true; + } + return node; } static const ZigClangType *qual_type_canon(ZigClangQualType qt) { @@ -1313,6 +1324,16 @@ static AstNode *trans_integer_literal(Context *c, ResultUsed result_used, const return maybe_suppress_result(c, result_used, node); } +static AstNode *trans_floating_literal(Context *c, ResultUsed result_used, const clang::FloatingLiteral *stmt) { + llvm::APFloat result{0.0f}; + if (!stmt->EvaluateAsFloat(result, *reinterpret_cast(c->ctx))) { + emit_warning(c, bitcast(stmt->getBeginLoc()), "invalid floating literal"); + return nullptr; + } + AstNode *node = trans_create_node_apfloat(c, result); + return maybe_suppress_result(c, result_used, node); +} + static AstNode *trans_constant_expr(Context *c, ResultUsed result_used, const clang::ConstantExpr *expr) { clang::Expr::EvalResult result; if (!expr->EvaluateAsConstantExpr(result, clang::Expr::EvaluateForCodeGen, @@ -3549,8 +3570,8 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *s emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FixedPointLiteralClass"); return ErrorUnexpected; case ZigClangStmt_FloatingLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FloatingLiteralClass"); - return ErrorUnexpected; + return wrap_stmt(out_node, out_child_scope, scope, + trans_floating_literal(c, result_used, (const clang::FloatingLiteral *)stmt)); case ZigClangStmt_ExprWithCleanupsClass: emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExprWithCleanupsClass"); return ErrorUnexpected; From 19b8278f91caaa25f05fe4dd7f51fdd1f0780e1e Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 20:59:48 +0200 Subject: [PATCH 03/10] translate-c: Convert char literals --- src/translate_c.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index b6841cbada32..c0e7848c094a 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1334,6 +1334,17 @@ static AstNode *trans_floating_literal(Context *c, ResultUsed result_used, const return maybe_suppress_result(c, result_used, node); } +static AstNode *trans_character_literal(Context *c, ResultUsed result_used, const clang::CharacterLiteral *stmt) { + clang::Expr::EvalResult result; + if (!stmt->EvaluateAsInt(result, *reinterpret_cast(c->ctx))) { + emit_warning(c, bitcast(stmt->getBeginLoc()), "invalid character literal"); + return nullptr; + } + AstNode *node = trans_create_node(c, NodeTypeCharLiteral); + node->data.char_literal.value = result.Val.getInt().getExtValue(); + return maybe_suppress_result(c, result_used, node); +} + static AstNode *trans_constant_expr(Context *c, ResultUsed result_used, const clang::ConstantExpr *expr) { clang::Expr::EvalResult result; if (!expr->EvaluateAsConstantExpr(result, clang::Expr::EvaluateForCodeGen, @@ -3531,7 +3542,8 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *s emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBridgedCastExprClass"); return ErrorUnexpected; case ZigClangStmt_CharacterLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CharacterLiteralClass"); + return wrap_stmt(out_node, out_child_scope, scope, + trans_character_literal(c, result_used, (const clang::CharacterLiteral *)stmt)); return ErrorUnexpected; case ZigClangStmt_ChooseExprClass: emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ChooseExprClass"); From d3dd49c403fb42d003dd2ee6d7917d9ebb7c2569 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 23:09:46 +0200 Subject: [PATCH 04/10] translate-c: Support for integer to boolean conversions --- src/translate_c.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index c0e7848c094a..35e868143215 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1944,8 +1944,23 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_VectorSplat"); return nullptr; case ZigClangCK_IntegralToBoolean: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralToBoolean"); - return nullptr; + { + const clang::Expr *expr = stmt->getSubExpr(); + + bool expr_val; + if (expr->EvaluateAsBooleanCondition(expr_val, *reinterpret_cast(c->ctx))) { + return trans_create_node_bool(c, expr_val); + } + + AstNode *val = trans_expr(c, ResultUsedYes, scope, bitcast(expr), TransRValue); + if (val == nullptr) + return nullptr; + + AstNode *zero = trans_create_node_unsigned(c, 0); + + // Translate as val != 0 + return trans_create_node_bin_op(c, val, BinOpTypeCmpNotEq, zero); + } case ZigClangCK_IntegralToFloating: case ZigClangCK_FloatingToIntegral: { From 69bc5fd04ddcd7772852d21c0172c24ac81ebe5c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 23:23:31 +0200 Subject: [PATCH 05/10] translate-c: Pointer to/from integral conversion --- src/translate_c.cpp | 46 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 35e868143215..d2cf423c09bd 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1928,12 +1928,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra case ZigClangCK_ConstructorConversion: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ConstructorConversion"); return nullptr; - case ZigClangCK_IntegralToPointer: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_IntegralToPointer"); - return nullptr; - case ZigClangCK_PointerToIntegral: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_PointerToIntegral"); - return nullptr; case ZigClangCK_PointerToBoolean: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_PointerToBoolean"); return nullptr; @@ -1961,6 +1955,41 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra // Translate as val != 0 return trans_create_node_bin_op(c, val, BinOpTypeCmpNotEq, zero); } + case ZigClangCK_PointerToIntegral: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + AstNode *val_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + val_node->data.fn_call_expr.params.append(target_node); + // @ptrToInt always returns a usize + AstNode *node = trans_create_node_builtin_fn_call_str(c, "intCast"); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(val_node); + + return maybe_suppress_result(c, result_used, node); + } + case ZigClangCK_IntegralToPointer: + { + AstNode *target_node = trans_expr(c, ResultUsedYes, scope, bitcast(stmt->getSubExpr()), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); + if (dest_type_node == nullptr) + return nullptr; + + AstNode *node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); + node->data.fn_call_expr.params.append(dest_type_node); + node->data.fn_call_expr.params.append(target_node); + + return maybe_suppress_result(c, result_used, node); + } case ZigClangCK_IntegralToFloating: case ZigClangCK_FloatingToIntegral: { @@ -1972,11 +2001,12 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra if (dest_type_node == nullptr) return nullptr; - const bool int_to_float = (ZigClangCK)stmt->getCastKind() == ZigClangCK_IntegralToFloating; - const char *fn = int_to_float ? "intToFloat" : "floatToInt"; + char const *fn = (ZigClangCK)stmt->getCastKind() == ZigClangCK_IntegralToFloating ? + "intToFloat" : "floatToInt"; AstNode *node = trans_create_node_builtin_fn_call_str(c, fn); node->data.fn_call_expr.params.append(dest_type_node); node->data.fn_call_expr.params.append(target_node); + return maybe_suppress_result(c, result_used, node); } case ZigClangCK_FixedPointCast: From ab424bbb35616500b8621fd72562a38ddc824add Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 16 Apr 2019 23:30:51 +0200 Subject: [PATCH 06/10] translate-c: Add test for implicit casts --- test/translate_c.zig | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/translate_c.zig b/test/translate_c.zig index cd8e7cb6d031..7c0331fe3568 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1553,6 +1553,61 @@ pub fn addCases(cases: *tests.TranslateCContext) void { "pub const NOT_ZERO = ~c_uint(0);", ); + cases.addC("implicit casts", + \\#include + \\ + \\void fn_int(int x); + \\void fn_f32(float x); + \\void fn_f64(double x); + \\void fn_char(char x); + \\void fn_bool(bool x); + \\void fn_ptr(void *x); + \\ + \\void call(int q) { + \\ fn_int(3.0f); + \\ fn_int(3.0); + \\ fn_int(3.0L); + \\ fn_int('ABCD'); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_char('3'); + \\ fn_char('\x1'); + \\ fn_char(0); + \\ fn_f32(3.0f); + \\ fn_f64(3.0); + \\ fn_bool(123); + \\ fn_bool(0); + \\ fn_bool(&fn_int); + \\ fn_int(&fn_int); + \\ fn_ptr(42); + \\} + , + \\pub extern fn fn_int(x: c_int) void; + \\pub extern fn fn_f32(x: f32) void; + \\pub extern fn fn_f64(x: f64) void; + \\pub extern fn fn_char(x: u8) void; + \\pub extern fn fn_bool(x: bool) void; + \\pub extern fn fn_ptr(x: ?*c_void) void; + \\pub export fn call(q: c_int) void { + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(1094861636); + \\ fn_f32(@intToFloat(f32, 3)); + \\ fn_f64(@intToFloat(f64, 3)); + \\ fn_char(u8('3')); + \\ fn_char(u8('\x01')); + \\ fn_char(u8(0)); + \\ fn_f32(3.000000); + \\ fn_f64(3.000000); + \\ fn_bool(true); + \\ fn_bool(false); + \\ fn_bool(@ptrToInt(&fn_int) != 0); + \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); + \\ fn_ptr(@intToPtr(?*c_void, 42)); + \\} + ); + // cases.add("empty array with initializer", // "int a[4] = {};" // , From 8d05330cf7451066e01700140dcab692624a17bf Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 20 Apr 2019 11:25:57 +0200 Subject: [PATCH 07/10] More precise translation of char literals --- src/translate_c.cpp | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index d2cf423c09bd..298039bce6ea 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1335,14 +1335,33 @@ static AstNode *trans_floating_literal(Context *c, ResultUsed result_used, const } static AstNode *trans_character_literal(Context *c, ResultUsed result_used, const clang::CharacterLiteral *stmt) { - clang::Expr::EvalResult result; - if (!stmt->EvaluateAsInt(result, *reinterpret_cast(c->ctx))) { - emit_warning(c, bitcast(stmt->getBeginLoc()), "invalid character literal"); - return nullptr; + switch (stmt->getKind()) { + case clang::CharacterLiteral::CharacterKind::Ascii: + { + unsigned val = stmt->getValue(); + // C has a somewhat obscure feature called multi-character character + // constant + if (val > 255) + return trans_create_node_unsigned(c, val); + } + // fallthrough + case clang::CharacterLiteral::CharacterKind::UTF8: + { + AstNode *node = trans_create_node(c, NodeTypeCharLiteral); + node->data.char_literal.value = stmt->getValue(); + return maybe_suppress_result(c, result_used, node); + } + case clang::CharacterLiteral::CharacterKind::UTF16: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF16 character literals"); + return nullptr; + case clang::CharacterLiteral::CharacterKind::UTF32: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support UTF32 character literals"); + return nullptr; + case clang::CharacterLiteral::CharacterKind::Wide: + emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO support wide character literals"); + return nullptr; } - AstNode *node = trans_create_node(c, NodeTypeCharLiteral); - node->data.char_literal.value = result.Val.getInt().getExtValue(); - return maybe_suppress_result(c, result_used, node); + zig_unreachable(); } static AstNode *trans_constant_expr(Context *c, ResultUsed result_used, const clang::ConstantExpr *expr) { From 9ea600b6349a9e1c0b2f2ea6a97a9a0de20d28b3 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 20 Apr 2019 11:29:10 +0200 Subject: [PATCH 08/10] Correct rendering of AST Char literals --- src/ast_render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 16f2aafa78b2..f66a47600e0a 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -633,7 +633,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { if (is_printable(c)) { fprintf(ar->f, "'%c'", c); } else { - fprintf(ar->f, "'\\x%x'", (int)c); + fprintf(ar->f, "'\\x%02x'", (int)c); } break; } From a44ad08954d9646f9fb1db6f1c167dd966b196a2 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 20 Apr 2019 11:41:38 +0200 Subject: [PATCH 09/10] Add some zig_panic for 80-bit float codepaths --- src/ir.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index a3d08b532791..71f39d7f9089 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8100,6 +8100,8 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) { case 64: dest_val->data.x_f64 = bigfloat_to_f64(bigfloat); break; + case 80: + zig_panic("TODO"); case 128: dest_val->data.x_f128 = bigfloat_to_f128(bigfloat); break; @@ -9961,6 +9963,8 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ case 64: const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat); break; + case 80: + zig_panic("TODO"); case 128: const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat); break; @@ -9990,6 +9994,8 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ case 64: const_val->data.x_f64 = bigfloat_to_f64(&bigfloat); break; + case 80: + zig_panic("TODO"); case 128: const_val->data.x_f128 = bigfloat_to_f128(&bigfloat); break; From 70c2e86da36abdd56fd61b77682643129fcf6371 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 20 Apr 2019 11:42:07 +0200 Subject: [PATCH 10/10] Add translation from pointer to boolean --- src/translate_c.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 298039bce6ea..f4f1055ed981 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1948,8 +1948,20 @@ static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, Tra emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ConstructorConversion"); return nullptr; case ZigClangCK_PointerToBoolean: - emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_PointerToBoolean"); - return nullptr; + { + const clang::Expr *expr = stmt->getSubExpr(); + AstNode *val = trans_expr(c, ResultUsedYes, scope, bitcast(expr), TransRValue); + if (val == nullptr) + return nullptr; + + AstNode *val_ptr = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + val_ptr->data.fn_call_expr.params.append(val); + + AstNode *zero = trans_create_node_unsigned(c, 0); + + // Translate as @ptrToInt((&val) != 0) + return trans_create_node_bin_op(c, val_ptr, BinOpTypeCmpNotEq, zero); + } case ZigClangCK_ToVoid: emit_warning(c, bitcast(stmt->getBeginLoc()), "TODO handle C CK_ToVoid"); return nullptr;