authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-08-02 08:15:59-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-08-03 08:38:15+03:00
logbc18e93825f1f3703b97590cc0e963b3faa8cd3e
treed4a2776c0b1f9bf65b135aa6a203ea28b32d195e
parent41d7787b69a437e21351d103353fc2eefafb5d17

translate-c: better codegen for pointer index by int literal

#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 {
616616 pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc;
617617 extern fn ZigClangIntegerLiteral_getBeginLoc(*const IntegerLiteral) SourceLocation;
618618
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;
621621};
622622
623623/// 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(
19851985 used: ResultUsed,
19861986) TransError!Node {
19871987 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))) {
19901990 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
19911991 }
1992 const is_zero = signum == 0;
19921993 return Node{ .tag_if_small_enough = @enumToInt(([2]Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)]) };
19931994 }
19941995
......@@ -3360,6 +3361,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
33603361 const subscr_qt = getExprQualType(c, subscr_expr);
33613362 const is_longlong = cIsLongLongInteger(subscr_qt);
33623363 const is_signed = cIsSignedInteger(subscr_qt);
3364 const is_nonnegative_int_literal = cIsNonNegativeIntLiteral(c, subscr_expr);
33633365
33643366 // Unwrap the base statement if it's an array decayed to a bare pointer type
33653367 // so that we index the array itself
......@@ -3374,7 +3376,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
33743376
33753377 // Special case: actual pointer (not decayed array) and signed integer subscript
33763378 // 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);
33783380
33793381 const container_node = try transExpr(c, scope, unwrapped_base, .used);
33803382 const rhs = if (is_longlong or is_signed) blk: {
......@@ -4260,6 +4262,18 @@ fn cIntTypeCmp(a: clang.QualType, b: clang.QualType) math.Order {
42604262 return math.order(a_index, b_index);
42614263}
42624264
4265/// Checks if expr is an integer literal >= 0
4266fn 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
42634277fn cIsSignedInteger(qt: clang.QualType) bool {
42644278 const c_type = qualTypeCanon(qt);
42654279 if (c_type.getTypeClass() != .Builtin) return false;
src/zig_clang.cpp+12-2
......@@ -2754,7 +2754,7 @@ struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct Zi
27542754 return bitcast(casted->getBeginLoc());
27552755}
27562756
2757bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bool *result, const struct ZigClangASTContext *ctx) {
2757bool ZigClangIntegerLiteral_getSignum(const struct ZigClangIntegerLiteral *self, int *result, const struct ZigClangASTContext *ctx) {
27582758 auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self);
27592759 auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
27602760 clang::Expr::EvalResult eval_result;
......@@ -2763,7 +2763,17 @@ bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *self, bo
27632763 }
27642764 const llvm::APSInt result_int = eval_result.Val.getInt();
27652765 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
27672777 return true;
27682778}
27692779
src/zig_clang.h+1-1
......@@ -1222,7 +1222,7 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct
12221222
12231223ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *);
12241224ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *);
1225ZIG_EXTERN_C bool ZigClangIntegerLiteral_isZero(const struct ZigClangIntegerLiteral *, bool *, const struct ZigClangASTContext *);
1225ZIG_EXTERN_C bool ZigClangIntegerLiteral_getSignum(const struct ZigClangIntegerLiteral *, int *, const struct ZigClangASTContext *);
12261226
12271227ZIG_EXTERN_C const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *);
12281228
test/translate_c.zig+11
......@@ -3630,4 +3630,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
36303630 , &[_][]const u8{
36313631 \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX;
36323632 });
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 });
36333644}