mirror of
https://github.com/ziglang/zig.git
synced 2026-01-27 09:45:27 +00:00
Add bit shift binary ops in translate-c-2
This commit is contained in:
parent
c8c89648b0
commit
acff2d407b
@ -575,6 +575,45 @@ fn transStmt(
|
||||
}
|
||||
}
|
||||
|
||||
fn transCreateNodeShiftOp(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
stmt: *const ZigClangBinaryOperator,
|
||||
comptime op: ast.Node.InfixOp.Op,
|
||||
comptime op_tok_id: std.zig.Token.Id,
|
||||
comptime bytes: []const u8,
|
||||
) !*ast.Node {
|
||||
if (!(op == .BitShiftLeft or op == .BitShiftRight)) {
|
||||
@compileError("op must be either .BitShiftLeft or .BitShiftRight");
|
||||
}
|
||||
|
||||
const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
|
||||
const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
|
||||
const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
|
||||
// lhs >> u5(rh)
|
||||
|
||||
const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
|
||||
const op_token = try appendToken(rp.c, op_tok_id, bytes);
|
||||
|
||||
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
|
||||
try as_node.params.push(rhs_type);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
const rhs = try transExpr(rp, scope, rhs_expr, .used, .l_value);
|
||||
try as_node.params.push(rhs.node);
|
||||
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
const node = try rp.c.a().create(ast.Node.InfixOp);
|
||||
node.* = ast.Node.InfixOp{
|
||||
.op_token = op_token,
|
||||
.lhs = lhs.node,
|
||||
.op = op,
|
||||
.rhs = &as_node.base,
|
||||
};
|
||||
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
fn transBinaryOperator(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
@ -679,15 +718,22 @@ fn transBinaryOperator(
|
||||
});
|
||||
}
|
||||
},
|
||||
.Shl,
|
||||
.Shr,
|
||||
=> return revertAndWarn(
|
||||
rp,
|
||||
error.UnsupportedTranslation,
|
||||
ZigClangBinaryOperator_getBeginLoc(stmt),
|
||||
"TODO: handle more C binary operators: {}",
|
||||
.{op},
|
||||
),
|
||||
.Shl => {
|
||||
const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
|
||||
return maybeSuppressResult(rp, scope, result_used, TransResult{
|
||||
.node = node,
|
||||
.child_scope = scope,
|
||||
.node_scope = scope,
|
||||
});
|
||||
},
|
||||
.Shr => {
|
||||
const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
|
||||
return maybeSuppressResult(rp, scope, result_used, TransResult{
|
||||
.node = node,
|
||||
.child_scope = scope,
|
||||
.node_scope = scope,
|
||||
});
|
||||
},
|
||||
.LT => {
|
||||
const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessThan, .AngleBracketLeft, "<", true);
|
||||
return maybeSuppressResult(rp, scope, result_used, TransResult{
|
||||
@ -1664,6 +1710,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
|
||||
return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
|
||||
}
|
||||
|
||||
fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 {
|
||||
const ty = ZigClangQualType_getTypePtr(qt);
|
||||
|
||||
switch (ZigClangType_getTypeClass(ty)) {
|
||||
.Builtin => {
|
||||
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
|
||||
|
||||
switch (ZigClangBuiltinType_getKind(builtin_ty)) {
|
||||
.Char_U,
|
||||
.UChar,
|
||||
.Char_S,
|
||||
.SChar,
|
||||
=> return 8,
|
||||
.UInt128,
|
||||
.Int128,
|
||||
=> return 128,
|
||||
else => return 0,
|
||||
}
|
||||
|
||||
unreachable;
|
||||
},
|
||||
.Typedef => {
|
||||
const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
|
||||
const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
|
||||
const type_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
|
||||
|
||||
if (std.mem.eql(u8, type_name, "uint8_t") or std.mem.eql(u8, type_name, "int8_t")) {
|
||||
return 8;
|
||||
} else if (std.mem.eql(u8, type_name, "uint16_t") or std.mem.eql(u8, type_name, "int16_t")) {
|
||||
return 16;
|
||||
} else if (std.mem.eql(u8, type_name, "uint32_t") or std.mem.eql(u8, type_name, "int32_t")) {
|
||||
return 32;
|
||||
} else if (std.mem.eql(u8, type_name, "uint64_t") or std.mem.eql(u8, type_name, "int64_t")) {
|
||||
return 64;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
else => return 0,
|
||||
}
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
|
||||
const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
|
||||
|
||||
if (int_bit_width != 0) {
|
||||
// we can perform the log2 now.
|
||||
const cast_bit_width = std.math.log2_int(u64, int_bit_width);
|
||||
const node = try rp.c.a().create(ast.Node.IntegerLiteral);
|
||||
node.* = ast.Node.IntegerLiteral{
|
||||
.token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
const zig_type_node = try transQualType(rp, qt, source_loc);
|
||||
|
||||
// @import("std").math.Log2Int(c_long);
|
||||
//
|
||||
// FnCall
|
||||
// FieldAccess
|
||||
// FieldAccess
|
||||
// FnCall (.builtin = true)
|
||||
// Symbol "import"
|
||||
// StringLiteral "std"
|
||||
// Symbol "math"
|
||||
// Symbol "Log2Int"
|
||||
// Symbol <zig_type_node> (var from above)
|
||||
|
||||
const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import");
|
||||
const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
|
||||
const std_node = try rp.c.a().create(ast.Node.StringLiteral);
|
||||
std_node.* = ast.Node.StringLiteral{
|
||||
.token = std_token,
|
||||
};
|
||||
try import_fn_call.params.push(&std_node.base);
|
||||
import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
|
||||
const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int");
|
||||
const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base);
|
||||
try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node);
|
||||
log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
return &log2int_fn_call.base;
|
||||
}
|
||||
|
||||
fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
|
||||
const ty = ZigClangQualType_getTypePtr(qt);
|
||||
|
||||
@ -1827,7 +1962,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
|
||||
_ = try appendToken(c, .LParen, "(");
|
||||
const node = try c.a().create(ast.Node.SuffixOp);
|
||||
node.* = ast.Node.SuffixOp{
|
||||
.lhs = fn_expr,
|
||||
.lhs = .{ .node = fn_expr },
|
||||
.op = ast.Node.SuffixOp.Op{
|
||||
.Call = ast.Node.SuffixOp.Op.Call{
|
||||
.params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
|
||||
@ -1839,6 +1974,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
|
||||
return node;
|
||||
}
|
||||
|
||||
fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp {
|
||||
const field_access_node = try c.a().create(ast.Node.InfixOp);
|
||||
field_access_node.* = .{
|
||||
.op_token = try appendToken(c, .Period, "."),
|
||||
.lhs = container,
|
||||
.op = .Period,
|
||||
.rhs = try transCreateNodeIdentifier(c, field_name),
|
||||
};
|
||||
return field_access_node;
|
||||
}
|
||||
|
||||
fn transCreateNodePrefixOp(
|
||||
c: *Context,
|
||||
op: ast.Node.PrefixOp.Op,
|
||||
|
||||
@ -1023,6 +1023,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add_2("shift right with a fixed size type, no while", // TODO can fold this into "shift right assign with a fixed size type" once `while` and `>>=` and `uint32_t` are handled in translate-c-2
|
||||
\\#include <stdint.h>
|
||||
\\uint32_t some_func(uint32_t a) {
|
||||
\\ uint32_t b = a >> 1;
|
||||
\\ return b;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn some_func(a: uint32_t) uint32_t {
|
||||
\\ var b: uint32_t = a >> @as(u5, 1);
|
||||
\\ return b;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("anonymous enum",
|
||||
\\enum {
|
||||
\\ One,
|
||||
@ -1199,6 +1212,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add_2("bitshift, no parens", // TODO can fold this into "bitshift" once parens are preserved correctly in translate-c-2
|
||||
\\int foo(void) {
|
||||
\\ int a = (1 << 2);
|
||||
\\ return a >> 1;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ var a: c_int = 1 << @as(@import("std").math.Log2Int(c_int), 2);
|
||||
\\ return a >> @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("compound assignment operators",
|
||||
\\void foo(void) {
|
||||
\\ int a = 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user