| author | |
| committer | |
| log | bc18e93825f1f3703b97590cc0e963b3faa8cd3e |
| tree | d4a2776c0b1f9bf65b135aa6a203ea28b32d195e |
| parent | 41d7787b69a437e21351d103353fc2eefafb5d17 |
#8589 introduced correct handling of signed (possibly negative) array access
of pointers. Since unadorned integer literals in C are signed, this resulted
in inefficient generated code when indexing a pointer by a non-negative
integer literal.5 files changed, 43 insertions(+), 8 deletions(-)
src/clang.zig+2-2| ... | ... | @@ -616,8 +616,8 @@ pub const IntegerLiteral = opaque { |
| 616 | 616 | pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; |
| 617 | 617 | extern fn ZigClangIntegerLiteral_getBeginLoc(*const IntegerLiteral) SourceLocation; |
| 618 | 618 | |
| 619 | pub const isZero = ZigClangIntegerLiteral_isZero; | |
| 620 | extern fn ZigClangIntegerLiteral_isZero(*const IntegerLiteral, *bool, *const ASTContext) bool; | |
| 619 | pub const getSignum = ZigClangIntegerLiteral_getSignum; | |
| 620 | extern fn ZigClangIntegerLiteral_getSignum(*const IntegerLiteral, *c_int, *const ASTContext) bool; | |
| 621 | 621 | }; |
| 622 | 622 | |
| 623 | 623 | /// This is just used as a namespace for a static method on clang's Lexer class; we don't directly |
src/translate_c.zig+17-3| ... | ... | @@ -1985,10 +1985,11 @@ fn transBoolExpr( |
| 1985 | 1985 | used: ResultUsed, |
| 1986 | 1986 | ) TransError!Node { |
| 1987 | 1987 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { |
| 1988 | var is_zero: bool = undefined; | |
| 1989 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { | |
| 1988 | var signum: c_int = undefined; | |
| 1989 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).getSignum(&signum, c.clang_context))) { | |
| 1990 | 1990 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); |
| 1991 | 1991 | } |
| 1992 | const is_zero = signum == 0; | |
| 1992 | 1993 | return Node{ .tag_if_small_enough = @enumToInt(([2]Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)]) }; |
| 1993 | 1994 | } |
| 1994 | 1995 | |
| ... | ... | @@ -3360,6 +3361,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip |
| 3360 | 3361 | const subscr_qt = getExprQualType(c, subscr_expr); |
| 3361 | 3362 | const is_longlong = cIsLongLongInteger(subscr_qt); |
| 3362 | 3363 | const is_signed = cIsSignedInteger(subscr_qt); |
| 3364 | const is_nonnegative_int_literal = cIsNonNegativeIntLiteral(c, subscr_expr); | |
| 3363 | 3365 | |
| 3364 | 3366 | // Unwrap the base statement if it's an array decayed to a bare pointer type |
| 3365 | 3367 | // so that we index the array itself |
| ... | ... | @@ -3374,7 +3376,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip |
| 3374 | 3376 | |
| 3375 | 3377 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3376 | 3378 | // See discussion at https://github.com/ziglang/zig/pull/8589 |
| 3377 | if (is_signed and (base_stmt == unwrapped_base) and !is_vector) return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); | |
| 3379 | if (is_signed and (base_stmt == unwrapped_base) and !is_vector and !is_nonnegative_int_literal) return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); | |
| 3378 | 3380 | |
| 3379 | 3381 | const container_node = try transExpr(c, scope, unwrapped_base, .used); |
| 3380 | 3382 | const rhs = if (is_longlong or is_signed) blk: { |
| ... | ... | @@ -4260,6 +4262,18 @@ fn cIntTypeCmp(a: clang.QualType, b: clang.QualType) math.Order { |
| 4260 | 4262 | return math.order(a_index, b_index); |
| 4261 | 4263 | } |
| 4262 | 4264 | |
| 4265 | /// Checks if expr is an integer literal >= 0 | |
| 4266 | fn cIsNonNegativeIntLiteral(c: *Context, expr: *const clang.Expr) bool { | |
| 4267 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { | |
| 4268 | var signum: c_int = undefined; | |
| 4269 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).getSignum(&signum, c.clang_context))) { | |
| 4270 | return false; | |
| 4271 | } | |
| 4272 | return signum >= 0; | |
| 4273 | } | |
| 4274 | return false; | |
| 4275 | } | |
| 4276 | ||
| 4263 | 4277 | fn cIsSignedInteger(qt: clang.QualType) bool { |
| 4264 | 4278 | const c_type = qualTypeCanon(qt); |
| 4265 | 4279 | if (c_type.getTypeClass() != .Builtin) return false; |
src/zig_clang.cpp+12-2| ... | ... | @@ -2754,7 +2754,7 @@ struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct Zi |
| 2754 | 2754 | return bitcast(casted->getBeginLoc()); |
| 2755 | 2755 | } |
| 2756 | 2756 | |
| 2757 | bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bool *result, const struct ZigClangASTContext *ctx) { | |
| 2757 | bool ZigClangIntegerLiteral_getSignum(const struct ZigClangIntegerLiteral *self, int *result, const struct ZigClangASTContext *ctx) { | |
| 2758 | 2758 | auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self); |
| 2759 | 2759 | auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx); |
| 2760 | 2760 | clang::Expr::EvalResult eval_result; |
| ... | ... | @@ -2763,7 +2763,17 @@ bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bo |
| 2763 | 2763 | } |
| 2764 | 2764 | const llvm::APSInt result_int = eval_result.Val.getInt(); |
| 2765 | 2765 | const llvm::APSInt zero(result_int.getBitWidth(), result_int.isUnsigned()); |
| 2766 | *result = zero == result_int; | |
| 2766 | ||
| 2767 | if (zero == result_int) { | |
| 2768 | *result = 0; | |
| 2769 | } else if (result_int < zero) { | |
| 2770 | *result = -1; | |
| 2771 | } else if (result_int > zero) { | |
| 2772 | *result = 1; | |
| 2773 | } else { | |
| 2774 | return false; | |
| 2775 | } | |
| 2776 | ||
| 2767 | 2777 | return true; |
| 2768 | 2778 | } |
| 2769 | 2779 |
src/zig_clang.h+1-1| ... | ... | @@ -1222,7 +1222,7 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct |
| 1222 | 1222 | |
| 1223 | 1223 | ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *); |
| 1224 | 1224 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *); |
| 1225 | ZIG_EXTERN_C bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *, bool *, const struct ZigClangASTContext *); | |
| 1225 | ZIG_EXTERN_C bool ZigClangIntegerLiteral_getSignum(const struct ZigClangIntegerLiteral *, int *, const struct ZigClangASTContext *); | |
| 1226 | 1226 | |
| 1227 | 1227 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *); |
| 1228 | 1228 |
test/translate_c.zig+11| ... | ... | @@ -3630,4 +3630,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3630 | 3630 | , &[_][]const u8{ |
| 3631 | 3631 | \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX; |
| 3632 | 3632 | }); |
| 3633 | ||
| 3634 | cases.add("Simple array access of pointer with non-negative integer constant", | |
| 3635 | \\void foo(int *p) { | |
| 3636 | \\ p[0]; | |
| 3637 | \\ p[1]; | |
| 3638 | \\} | |
| 3639 | , &[_][]const u8{ | |
| 3640 | \\_ = p[@intCast(c_uint, @as(c_int, 0))]; | |
| 3641 | , | |
| 3642 | \\_ = p[@intCast(c_uint, @as(c_int, 1))]; | |
| 3643 | }); | |
| 3633 | 3644 | } |