Commit 9a826ccbe0

Veikka Tuominen <git@vexu.eu>
2021-02-16 15:34:37
translate-c: elide some unecessary casts of literals
1 parent 74e9d4c
src/clang.zig
@@ -127,6 +127,9 @@ pub const APSInt = opaque {
 
     pub const getNumWords = ZigClangAPSInt_getNumWords;
     extern fn ZigClangAPSInt_getNumWords(*const APSInt) c_uint;
+
+    pub const lessThanEqual = ZigClangAPSInt_lessThanEqual;
+    extern fn ZigClangAPSInt_lessThanEqual(*const APSInt, rhs: u64) bool;
 };
 
 pub const ASTContext = opaque {
@@ -407,7 +410,7 @@ pub const Expr = opaque {
     pub const getBeginLoc = ZigClangExpr_getBeginLoc;
     extern fn ZigClangExpr_getBeginLoc(*const Expr) SourceLocation;
 
-    pub const EvaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
+    pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
     extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstExprUsage, *const ASTContext) bool;
 };
 
src/translate_c.zig
@@ -1820,11 +1820,55 @@ fn transExprCoercing(c: *Context, scope: *Scope, expr: *const clang.Expr, used:
                 return transExprCoercing(c, scope, un_expr.getSubExpr(), used);
             }
         },
+        .ImplicitCastExprClass => {
+            const cast_expr = @ptrCast(*const clang.ImplicitCastExpr, expr);
+            const sub_expr = cast_expr.getSubExpr();
+            switch (@ptrCast(*const clang.Stmt, sub_expr).getStmtClass()) {
+                .IntegerLiteralClass, .CharacterLiteralClass => switch (cast_expr.getCastKind()) {
+                    .IntegralToFloating => return transExprCoercing(c, scope, sub_expr, used),
+                    .IntegralCast => {
+                        const dest_type = getExprQualType(c, expr);
+                        if (literalFitsInType(c, sub_expr, dest_type))
+                            return transExprCoercing(c, scope, sub_expr, used);
+                    },
+                    else => {},
+                },
+                else => {},
+            }
+        },
         else => {},
     }
     return transExpr(c, scope, expr, .used);
 }
 
+fn literalFitsInType(c: *Context, expr: *const clang.Expr, qt: clang.QualType) bool {
+    var width = qualTypeIntBitWidth(c, qt) catch 8;
+    if (width == 0) width = 8; // Byte is the smallest type.
+    const is_signed = cIsSignedInteger(qt);
+    const width_max_int= (@as(u64, 1) << math.lossyCast(u6, width - @boolToInt(is_signed))) - 1;
+
+    switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
+        .CharacterLiteralClass => {
+            const char_lit = @ptrCast(*const clang.CharacterLiteral, expr);
+            const val = char_lit.getValue();
+            // If the val is less than the max int then it fits.
+            return val <= width_max_int;
+        },
+        .IntegerLiteralClass => {
+            const int_lit = @ptrCast(*const clang.IntegerLiteral, expr);
+            var eval_result: clang.ExprEvalResult = undefined;
+            if (!int_lit.EvaluateAsInt(&eval_result, c.clang_context)) {
+                return false;
+            }
+
+            const int = eval_result.Val.getInt();
+            return int.lessThanEqual(width_max_int);
+        },
+        else => unreachable,
+    }
+
+}
+
 fn transInitListExprRecord(
     c: *Context,
     scope: *Scope,
@@ -2331,7 +2375,7 @@ fn transDefault(
 
 fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
     var result: clang.ExprEvalResult = undefined;
-    if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context))
+    if (!expr.evaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context))
         return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});
 
     switch (result.Val.getKind()) {
@@ -3171,7 +3215,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool {
     return qualTypeCanon(qt).isBooleanType();
 }
 
-fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 {
+fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType) !u32 {
     const ty = qt.getTypePtr();
 
     switch (ty.getTypeClass()) {
@@ -3211,12 +3255,10 @@ fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.Source
         },
         else => return 0,
     }
-
-    unreachable;
 }
 
 fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
-    const int_bit_width = try qualTypeIntBitWidth(c, qt, source_loc);
+    const int_bit_width = try qualTypeIntBitWidth(c, qt);
 
     if (int_bit_width != 0) {
         // we can perform the log2 now.
src/zig_clang.cpp
@@ -2244,6 +2244,11 @@ unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) {
     return casted->getNumWords();
 }
 
+bool ZigClangAPSInt_lessThanEqual(const ZigClangAPSInt *self, uint64_t rhs) {
+    auto casted = reinterpret_cast<const llvm::APSInt *>(self);
+    return casted->ule(rhs);
+}
+
 uint64_t ZigClangAPInt_getLimitedValue(const ZigClangAPInt *self, uint64_t limit) {
     auto casted = reinterpret_cast<const llvm::APInt *>(self);
     return casted->getLimitedValue(limit);
src/zig_clang.h
@@ -1097,6 +1097,7 @@ ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct Zig
 ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self);
 ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self);
 ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self);
+ZIG_EXTERN_C bool ZigClangAPSInt_lessThanEqual(const struct ZigClangAPSInt *self, uint64_t rhs);
 
 ZIG_EXTERN_C uint64_t ZigClangAPInt_getLimitedValue(const struct ZigClangAPInt *self, uint64_t limit);
 
test/translate_c.zig
@@ -313,22 +313,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub const uuid_t = [16]u8;
         \\pub const UUID_NULL: uuid_t = [16]u8{
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
-        \\    @bitCast(u8, @truncate(i8, @as(c_int, 0))),
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
+        \\    0,
         \\};
     });
 
@@ -382,10 +382,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
         \\pub export var ub: union_unnamed_1 = union_unnamed_1{
         \\    .c = [4]u8{
-        \\        @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),
-        \\        @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),
-        \\        @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),
-        \\        @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),
+        \\        'a',
+        \\        'b',
+        \\        'b',
+        \\        'a',
         \\    },
         \\};
     });
@@ -512,7 +512,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: c_int = undefined;
-        \\    var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
+        \\    var b: u8 = 123;
         \\    const c: c_int = undefined;
         \\    const d: c_uint = @bitCast(c_uint, @as(c_int, 440));
         \\    var e: c_int = 10;
@@ -1468,7 +1468,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub fn foo() callconv(.C) void {
         \\    var arr: [10]u8 = [1]u8{
-        \\        @bitCast(u8, @truncate(i8, @as(c_int, 1))),
+        \\        1,
         \\    } ++ [1]u8{0} ** 9;
         \\    var arr1: [10][*c]u8 = [1][*c]u8{
         \\        null,
@@ -1721,13 +1721,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    unsigned d = 440;
         \\}
     , &[_][]const u8{
-        \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
-        \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
+        \\pub var a: c_long = 2;
+        \\pub var b: c_long = 2;
         \\pub var c: c_int = 4;
         \\pub export fn foo(arg_c_1: u8) void {
         \\    var c_1 = arg_c_1;
         \\    var a_2: c_int = undefined;
-        \\    var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
+        \\    var b_3: u8 = 123;
         \\    b_3 = @bitCast(u8, @truncate(i8, a_2));
         \\    {
         \\        var d: c_int = 5;
@@ -1838,7 +1838,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\            };
         \\        }
         \\    }
-        \\    var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
+        \\    var i: u8 = 2;
         \\}
     });
 
@@ -1846,7 +1846,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\unsigned anyerror = 2;
         \\#define noreturn _Noreturn
     , &[_][]const u8{
-        \\pub export var anyerror_1: c_uint = @bitCast(c_uint, @as(c_int, 2));
+        \\pub export var anyerror_1: c_uint = 2;
         ,
         \\pub const noreturn_2 = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn");
     });
@@ -1860,7 +1860,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub export var a: f32 = @floatCast(f32, 3.1415);
         \\pub export var b: f64 = 3.1415;
         \\pub export var c: c_int = @floatToInt(c_int, 3.1415);
-        \\pub export var d: f64 = @intToFloat(f64, @as(c_int, 3));
+        \\pub export var d: f64 = 3;
     });
 
     cases.add("conditional operator",
@@ -2009,7 +2009,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    // TODO translate-c should in theory be able to figure out to drop all these casts
     cases.add("escape sequences",
         \\const char *escapes() {
         \\char a = '\'',
@@ -2028,17 +2027,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\
     , &[_][]const u8{
         \\pub export fn escapes() [*c]const u8 {
-        \\    var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));
-        \\    var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));
-        \\    var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));
-        \\    var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));
-        \\    var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));
-        \\    var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));
-        \\    var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));
-        \\    var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));
-        \\    var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));
-        \\    var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));
-        \\    var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));
+        \\    var a: u8 = '\'';
+        \\    var b: u8 = '\\';
+        \\    var c: u8 = '\x07';
+        \\    var d: u8 = '\x08';
+        \\    var e: u8 = '\x0c';
+        \\    var f: u8 = '\n';
+        \\    var g: u8 = '\r';
+        \\    var h: u8 = '\t';
+        \\    var i: u8 = '\x0b';
+        \\    var j: u8 = '\x00';
+        \\    var k: u8 = '\"';
         \\    return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
         \\}
     });
@@ -2308,8 +2307,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: [10]c_longlong = undefined;
-        \\    var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
-        \\    a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
+        \\    var i: c_longlong = 0;
+        \\    a[@intCast(usize, i)] = 0;
         \\}
     });
 
@@ -2321,8 +2320,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: [10]c_uint = undefined;
-        \\    var i: c_uint = @bitCast(c_uint, @as(c_int, 0));
-        \\    a[i] = @bitCast(c_uint, @as(c_int, 0));
+        \\    var i: c_uint = 0;
+        \\    a[i] = 0;
         \\}
     });
 
@@ -2527,7 +2526,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var i: c_int = 0;
-        \\    var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
+        \\    var u: c_uint = 0;
         \\    i += 1;
         \\    i -= 1;
         \\    u +%= 1;
@@ -2614,7 +2613,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: c_int = 0;
-        \\    var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
+        \\    var b: c_uint = 0;
         \\    a += blk: {
         \\        const ref = &a;
         \\        ref.* += @as(c_int, 1);
@@ -2692,7 +2691,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     , &[_][]const u8{
         \\pub export fn foo() void {
-        \\    var a: c_uint = @bitCast(c_uint, @as(c_int, 0));
+        \\    var a: c_uint = 0;
         \\    a +%= blk: {
         \\        const ref = &a;
         \\        ref.* +%= @bitCast(c_uint, @as(c_int, 1));
@@ -2752,7 +2751,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var i: c_int = 0;
-        \\    var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
+        \\    var u: c_uint = 0;
         \\    i += 1;
         \\    i -= 1;
         \\    u +%= 1;