mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
translate-c: enable pointer arithmetic with signed integer operand
Given a pointer operand `ptr` and a signed integer operand `idx` `ptr + idx` and `idx + ptr` -> ptr + @bitCast(usize, @intCast(isize, idx)) `ptr - idx` -> ptr - @bitCast(usize, @intCast(isize, idx)) Thanks @LemonBoy for pointing out that we can take advantage of wraparound to dramatically simplify the code.
This commit is contained in:
parent
02737d535a
commit
291edafa1b
@ -1127,6 +1127,44 @@ fn transOffsetOfExpr(
|
||||
return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});
|
||||
}
|
||||
|
||||
/// Translate an arithmetic expression with a pointer operand and a signed-integer operand.
|
||||
/// Zig requires a usize argument for pointer arithmetic, so we intCast to isize and then
|
||||
/// bitcast to usize; pointer wraparound make the math work.
|
||||
/// Zig pointer addition is not commutative (unlike C); the pointer operand needs to be on the left.
|
||||
/// The + operator in C is not a sequence point so it should be safe to switch the order if necessary.
|
||||
fn transCreatePointerArithmeticSignedOp(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
stmt: *const clang.BinaryOperator,
|
||||
result_used: ResultUsed,
|
||||
) TransError!Node {
|
||||
const is_add = stmt.getOpcode() == .Add;
|
||||
const lhs = stmt.getLHS();
|
||||
const rhs = stmt.getRHS();
|
||||
const swap_operands = is_add and cIsSignedInteger(getExprQualType(c, lhs));
|
||||
|
||||
const swizzled_lhs = if (swap_operands) rhs else lhs;
|
||||
const swizzled_rhs = if (swap_operands) lhs else rhs;
|
||||
|
||||
const lhs_node = try transExpr(c, scope, swizzled_lhs, .used);
|
||||
const rhs_node = try transExpr(c, scope, swizzled_rhs, .used);
|
||||
|
||||
const intcast_node = try Tag.int_cast.create(c.arena, .{
|
||||
.lhs = try Tag.identifier.create(c.arena, "isize"),
|
||||
.rhs = rhs_node,
|
||||
});
|
||||
|
||||
const bitcast_node = try Tag.bit_cast.create(c.arena, .{
|
||||
.lhs = try Tag.identifier.create(c.arena, "usize"),
|
||||
.rhs = intcast_node,
|
||||
});
|
||||
|
||||
const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node };
|
||||
const arith_node = try if (is_add) Tag.add.create(c.arena, arith_args) else Tag.sub.create(c.arena, arith_args);
|
||||
|
||||
return maybeSuppressResult(c, scope, result_used, arith_node);
|
||||
}
|
||||
|
||||
fn transBinaryOperator(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
@ -1184,6 +1222,12 @@ fn transBinaryOperator(
|
||||
.LOr => {
|
||||
return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used);
|
||||
},
|
||||
.Add, .Sub => {
|
||||
// `ptr + idx` and `idx + ptr` -> ptr + @bitCast(usize, @intCast(isize, idx))
|
||||
// `ptr - idx` -> ptr - @bitCast(usize, @intCast(isize, idx))
|
||||
if (qualTypeIsPtr(qt) and (cIsSignedInteger(getExprQualType(c, stmt.getLHS())) or
|
||||
cIsSignedInteger(getExprQualType(c, stmt.getRHS())))) return transCreatePointerArithmeticSignedOp(c, scope, stmt, result_used);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
var op_id: Tag = undefined;
|
||||
|
||||
@ -1131,4 +1131,30 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("pointer arithmetic with signed operand",
|
||||
\\#include <stdlib.h>
|
||||
\\int main() {
|
||||
\\ int array[10];
|
||||
\\ int *x = &array[5];
|
||||
\\ int *y;
|
||||
\\ int idx = 0;
|
||||
\\ y = x + ++idx;
|
||||
\\ if (y != x + 1 || y != &array[6]) abort();
|
||||
\\ y = idx + x;
|
||||
\\ if (y != x + 1 || y != &array[6]) abort();
|
||||
\\ y = x - idx;
|
||||
\\ if (y != x - 1 || y != &array[4]) abort();
|
||||
\\
|
||||
\\ idx = 0;
|
||||
\\ y = --idx + x;
|
||||
\\ if (y != x - 1 || y != &array[4]) abort();
|
||||
\\ y = idx + x;
|
||||
\\ if (y != x - 1 || y != &array[4]) abort();
|
||||
\\ y = x - idx;
|
||||
\\ if (y != x + 1 || y != &array[6]) abort();
|
||||
\\
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user