| 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,8 +616,8 @@ pub const IntegerLiteral = opaque { |
| 616 | pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; | 616 | pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; |
| 617 | extern fn ZigClangIntegerLiteral_getBeginLoc(*const IntegerLiteral) SourceLocation; | 617 | extern fn ZigClangIntegerLiteral_getBeginLoc(*const IntegerLiteral) SourceLocation; |
| 618 | 618 | ||
| 619 | pub const isZero = ZigClangIntegerLiteral_isZero; | 619 | pub const getSignum = ZigClangIntegerLiteral_getSignum; |
| 620 | extern fn ZigClangIntegerLiteral_isZero(*const IntegerLiteral, *bool, *const ASTContext) bool; | 620 | extern fn ZigClangIntegerLiteral_getSignum(*const IntegerLiteral, *c_int, *const ASTContext) bool; |
| 621 | }; | 621 | }; |
| 622 | 622 | ||
| 623 | /// This is just used as a namespace for a static method on clang's Lexer class; we don't directly | 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,10 +1985,11 @@ fn transBoolExpr( |
| 1985 | used: ResultUsed, | 1985 | used: ResultUsed, |
| 1986 | ) TransError!Node { | 1986 | ) TransError!Node { |
| 1987 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { | 1987 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { |
| 1988 | var is_zero: bool = undefined; | 1988 | var signum: c_int = undefined; |
| 1989 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { | 1989 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).getSignum(&signum, c.clang_context))) { |
| 1990 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); | 1990 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); |
| 1991 | } | 1991 | } |
| 1992 | const is_zero = signum == 0; | ||
| 1992 | return Node{ .tag_if_small_enough = @enumToInt(([2]Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)]) }; | 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,6 +3361,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip |
| 3360 | const subscr_qt = getExprQualType(c, subscr_expr); | 3361 | const subscr_qt = getExprQualType(c, subscr_expr); |
| 3361 | const is_longlong = cIsLongLongInteger(subscr_qt); | 3362 | const is_longlong = cIsLongLongInteger(subscr_qt); |
| 3362 | const is_signed = cIsSignedInteger(subscr_qt); | 3363 | const is_signed = cIsSignedInteger(subscr_qt); |
| 3364 | const is_nonnegative_int_literal = cIsNonNegativeIntLiteral(c, subscr_expr); | ||
| 3363 | 3365 | ||
| 3364 | // Unwrap the base statement if it's an array decayed to a bare pointer type | 3366 | // Unwrap the base statement if it's an array decayed to a bare pointer type |
| 3365 | // so that we index the array itself | 3367 | // so that we index the array itself |
| ... | @@ -3374,7 +3376,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip | ... | @@ -3374,7 +3376,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip |
| 3374 | 3376 | ||
| 3375 | // Special case: actual pointer (not decayed array) and signed integer subscript | 3377 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3376 | // See discussion at https://github.com/ziglang/zig/pull/8589 | 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 | const container_node = try transExpr(c, scope, unwrapped_base, .used); | 3381 | const container_node = try transExpr(c, scope, unwrapped_base, .used); |
| 3380 | const rhs = if (is_longlong or is_signed) blk: { | 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,6 +4262,18 @@ fn cIntTypeCmp(a: clang.QualType, b: clang.QualType) math.Order { |
| 4260 | return math.order(a_index, b_index); | 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 | fn cIsSignedInteger(qt: clang.QualType) bool { | 4277 | fn cIsSignedInteger(qt: clang.QualType) bool { |
| 4264 | const c_type = qualTypeCanon(qt); | 4278 | const c_type = qualTypeCanon(qt); |
| 4265 | if (c_type.getTypeClass() != .Builtin) return false; | 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,7 +2754,7 @@ struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct Zi |
| 2754 | return bitcast(casted->getBeginLoc()); | 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 | auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self); | 2758 | auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self); |
| 2759 | auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx); | 2759 | auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx); |
| 2760 | clang::Expr::EvalResult eval_result; | 2760 | clang::Expr::EvalResult eval_result; |
| ... | @@ -2763,7 +2763,17 @@ bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bo | ... | @@ -2763,7 +2763,17 @@ bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bo |
| 2763 | } | 2763 | } |
| 2764 | const llvm::APSInt result_int = eval_result.Val.getInt(); | 2764 | const llvm::APSInt result_int = eval_result.Val.getInt(); |
| 2765 | const llvm::APSInt zero(result_int.getBitWidth(), result_int.isUnsigned()); | 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 | return true; | 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,7 +1222,7 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct |
| 1222 | 1222 | ||
| 1223 | ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *); | 1223 | ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *); |
| 1224 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *); | 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 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *); | 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,4 +3630,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3630 | , &[_][]const u8{ | 3630 | , &[_][]const u8{ |
| 3631 | \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX; | 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 | } |