change @bitcast to @ptrcast

See #290
This commit is contained in:
Andrew Kelley 2017-03-31 06:18:20 -04:00
parent 3ca027ca82
commit f8e63c4584
15 changed files with 91 additions and 82 deletions

View file

@ -634,9 +634,6 @@ calls the public `panic` function exposed in the root source file, or
if there is not one specified, invokes the one provided in
`std/special/panic.zig`.
### @bitcast(comptime DestType: type, value: var) -> DestType
### @ptrcast(comptime DestType: type, value: var) -> DestType
Transmutes memory from one type to another without changing any bits.
The source and destination types must have the same size. This function
can be used to, for example, reinterpret a pointer, or convert a `f32` to a
`u32`.
Converts a pointer of one type to a pointer of another type.

View file

@ -1196,7 +1196,7 @@ enum BuiltinFnId {
BuiltinFnIdSetGlobalSection,
BuiltinFnIdSetGlobalLinkage,
BuiltinFnIdPanic,
BuiltinFnIdBitCast,
BuiltinFnIdPtrCast,
};
struct BuiltinFnEntry {
@ -1720,7 +1720,7 @@ enum IrInstructionId {
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
IrInstructionIdInitEnum,
IrInstructionIdBitCast,
IrInstructionIdPtrCast,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
@ -2370,11 +2370,11 @@ struct IrInstructionInitEnum {
LLVMValueRef tmp_ptr;
};
struct IrInstructionBitCast {
struct IrInstructionPtrCast {
IrInstruction base;
IrInstruction *dest_type;
IrInstruction *target;
IrInstruction *ptr;
};
struct IrInstructionWidenOrShorten {

View file

@ -1345,12 +1345,12 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
static LLVMValueRef ir_render_bitcast(CodeGen *g, IrExecutable *executable,
IrInstructionBitCast *instruction)
static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
IrInstructionPtrCast *instruction)
{
TypeTableEntry *wanted_type = instruction->base.value.type;
LLVMValueRef target = ir_llvm_value(g, instruction->target);
return LLVMBuildBitCast(g->builder, target, wanted_type->type_ref, "");
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
}
static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
@ -2776,8 +2776,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
case IrInstructionIdStructInit:
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
case IrInstructionIdBitCast:
return ir_render_bitcast(g, executable, (IrInstructionBitCast *)instruction);
case IrInstructionIdPtrCast:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
case IrInstructionIdWidenOrShorten:
return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
case IrInstructionIdPtrToInt:
@ -4260,7 +4260,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
create_builtin_fn(g, BuiltinFnIdBitCast, "bitcast", 2);
create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2);
}
static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {

View file

@ -480,8 +480,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) {
return IrInstructionIdInitEnum;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
return IrInstructionIdBitCast;
static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
return IrInstructionIdPtrCast;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
@ -1940,16 +1940,16 @@ static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old
return new_instruction;
}
static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *target)
static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *ptr)
{
IrInstructionBitCast *instruction = ir_build_instruction<IrInstructionBitCast>(
IrInstructionPtrCast *instruction = ir_build_instruction<IrInstructionPtrCast>(
irb, scope, source_node);
instruction->dest_type = dest_type;
instruction->target = target;
instruction->ptr = ptr;
if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(target, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
return &instruction->base;
}
@ -2666,12 +2666,12 @@ static IrInstruction *ir_instruction_initenum_get_dep(IrInstructionInitEnum *ins
}
}
static IrInstruction *ir_instruction_bitcast_get_dep(IrInstructionBitCast *instruction,
static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instruction,
size_t index)
{
switch (index) {
case 0: return instruction->dest_type;
case 1: return instruction->target;
case 1: return instruction->ptr;
default: return nullptr;
}
}
@ -2928,8 +2928,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_testcomptime_get_dep((IrInstructionTestComptime *) instruction, index);
case IrInstructionIdInitEnum:
return ir_instruction_initenum_get_dep((IrInstructionInitEnum *) instruction, index);
case IrInstructionIdBitCast:
return ir_instruction_bitcast_get_dep((IrInstructionBitCast *) instruction, index);
case IrInstructionIdPtrCast:
return ir_instruction_ptrcast_get_dep((IrInstructionPtrCast *) instruction, index);
case IrInstructionIdWidenOrShorten:
return ir_instruction_widenorshorten_get_dep((IrInstructionWidenOrShorten *) instruction, index);
case IrInstructionIdIntToPtr:
@ -4200,7 +4200,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_panic(irb, scope, node, arg0_value);
}
case BuiltinFnIdBitCast:
case BuiltinFnIdPtrCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
@ -4212,7 +4212,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
return ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
return ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
}
}
zig_unreachable();
@ -12182,34 +12182,36 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
}
static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
static bool is_ptr_type(TypeTableEntry *t) {
return (t->id == TypeTableEntryIdPointer || t->id == TypeTableEntryIdFn ||
(t->id == TypeTableEntryIdMaybe && (t->data.maybe.child_type->id == TypeTableEntryIdPointer ||
t->data.maybe.child_type->id == TypeTableEntryIdFn)));
}
static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->other;
TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
if (type_is_invalid(dest_type))
return ira->codegen->builtin_types.entry_invalid;
IrInstruction *target = instruction->target->other;
TypeTableEntry *src_type = target->value.type;
IrInstruction *ptr = instruction->ptr->other;
TypeTableEntry *src_type = ptr->value.type;
if (type_is_invalid(src_type))
return ira->codegen->builtin_types.entry_invalid;
ensure_complete_type(ira->codegen, dest_type);
ensure_complete_type(ira->codegen, src_type);
uint64_t dest_size_bytes = type_size(ira->codegen, dest_type);
uint64_t src_size_bytes = type_size(ira->codegen, src_type);
if (dest_size_bytes != src_size_bytes) {
ir_add_error(ira, &instruction->base,
buf_sprintf("destination type '%s' has size %" PRIu64 " but source type '%s' has size %" PRIu64,
buf_ptr(&dest_type->name), dest_size_bytes,
buf_ptr(&src_type->name), src_size_bytes));
if (!is_ptr_type(src_type)) {
ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
if (instr_is_comptime(target) && src_type->id == dest_type->id &&
(src_type->id == TypeTableEntryIdPointer || src_type->id == TypeTableEntryIdMaybe))
{
ConstExprValue *val = ir_resolve_const(ira, target, UndefOk);
if (!is_ptr_type(dest_type)) {
ir_add_error(ira, dest_type_value,
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
if (instr_is_comptime(ptr)) {
ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
if (!val)
return ira->codegen->builtin_types.entry_invalid;
@ -12219,8 +12221,8 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
return dest_type;
}
IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, nullptr, target);
IrInstruction *result = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, nullptr, ptr);
ir_link_new_instruction(result, &instruction->base);
result->value.type = dest_type;
return dest_type;
@ -12464,8 +12466,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
case IrInstructionIdPanic:
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
case IrInstructionIdBitCast:
return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
case IrInstructionIdPtrCast:
return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
@ -12637,7 +12639,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
case IrInstructionIdInitEnum:
case IrInstructionIdBitCast:
case IrInstructionIdPtrCast:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr:

View file

@ -765,9 +765,13 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction)
fprintf(irp->f, "}");
}
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
fprintf(irp->f, "@bitcast(");
ir_print_other_instruction(irp, instruction->target);
static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, "@ptrcast(");
if (instruction->dest_type) {
ir_print_other_instruction(irp, instruction->dest_type);
}
fprintf(irp->f, ",");
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ")");
}
@ -1098,8 +1102,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdInitEnum:
ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
break;
case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
case IrInstructionIdPtrCast:
ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
break;
case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);

View file

@ -74,7 +74,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
const name = %return compile_unit.die.getAttrString(st, DW.AT_name);
%return out_stream.printf("{} -> {}\n", return_address, name);
maybe_fp = *@bitcast(&const ?&const u8, fp);
maybe_fp = *@ptrcast(&const ?&const u8, fp);
}
},
ObjectFormat.coff => {

View file

@ -236,7 +236,7 @@ test "basicHashMapTest" {
}
fn hash_i32(x: i32) -> u32 {
*@bitcast(&u32, &x)
*@ptrcast(&u32, &x)
}
fn eql_i32(a: i32, b: i32) -> bool {
a == b

View file

@ -78,7 +78,7 @@ pub const IncrementingAllocator = struct {
fn alloc(allocator: &Allocator, n: usize) -> %[]u8 {
// TODO
//const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
const self = @bitcast(&IncrementingAllocator, allocator);
const self = @ptrcast(&IncrementingAllocator, allocator);
const new_end_index = self.end_index + n;
if (new_end_index > self.bytes.len) {
return error.NoMem;

View file

@ -239,7 +239,7 @@ pub const AF_MAX = PF_MAX;
/// Get the errno from a syscall return value, or 0 for no error.
pub fn getErrno(r: usize) -> usize {
const signed_r = *@bitcast(&isize, &r);
const signed_r = *@ptrcast(&isize, &r);
if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
}

View file

@ -15,7 +15,7 @@ export fn __udivdi3(a: du_int, b: du_int) -> du_int {
fn du_int_to_udwords(x: du_int) -> udwords {
@setDebugSafety(this, false);
return *@bitcast(&udwords, &x);
return *@ptrcast(&udwords, &x);
}
export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
@ -66,7 +66,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
if (var rem ?= maybe_rem) {
r[high] = n[high] % d[high];
r[low] = 0;
*rem = *@bitcast(&du_int, &r[0]);
*rem = *@ptrcast(&du_int, &r[0]);
}
return n[high] / d[high];
}
@ -78,7 +78,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
if (var rem ?= maybe_rem) {
r[low] = n[low];
r[high] = n[high] & (d[high] - 1);
*rem = *@bitcast(&du_int, &r[0]);
*rem = *@ptrcast(&du_int, &r[0]);
}
return n[high] >> @ctz(d[high]);
}
@ -89,7 +89,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
// 0 <= sr <= n_uword_bits - 2 or sr large
if (sr > n_uword_bits - 2) {
if (var rem ?= maybe_rem) {
*rem = *@bitcast(&du_int, &n[0]);
*rem = *@ptrcast(&du_int, &n[0]);
}
return 0;
}
@ -113,12 +113,12 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
*rem = n[low] & (d[low] - 1);
}
if (d[low] == 1) {
return *@bitcast(&du_int, &n[0]);
return *@ptrcast(&du_int, &n[0]);
}
sr = @ctz(d[low]);
q[high] = n[high] >> sr;
q[low] = (n[high] << (n_uword_bits - sr)) | (n[low] >> sr);
return *@bitcast(&du_int, &q[0]);
return *@ptrcast(&du_int, &q[0]);
}
// K X
// ---
@ -154,7 +154,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
// 0 <= sr <= n_uword_bits - 1 or sr large
if (sr > n_uword_bits - 1) {
if (var rem ?= maybe_rem) {
*rem = *@bitcast(&du_int, &n[0]);
*rem = *@ptrcast(&du_int, &n[0]);
}
return 0;
}
@ -191,17 +191,17 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int {
// r.all -= d.all;
// carry = 1;
// }
const s: di_int = (di_int)(*@bitcast(&du_int, &d[0]) - *@bitcast(&du_int, &r[0]) - 1) >> (n_udword_bits - 1);
const s: di_int = (di_int)(*@ptrcast(&du_int, &d[0]) - *@ptrcast(&du_int, &r[0]) - 1) >> (n_udword_bits - 1);
carry = su_int(s & 1);
*@bitcast(&du_int, &r[0]) -= *@bitcast(&du_int, &d[0]) & u64(s);
*@ptrcast(&du_int, &r[0]) -= *@ptrcast(&du_int, &d[0]) & u64(s);
sr -= 1;
}
*@bitcast(&du_int, &q[0]) = (*@bitcast(&du_int, &q[0]) << 1) | u64(carry);
*@ptrcast(&du_int, &q[0]) = (*@ptrcast(&du_int, &q[0]) << 1) | u64(carry);
if (var rem ?= maybe_rem) {
*rem = *@bitcast(&du_int, &r[0]);
*rem = *@ptrcast(&du_int, &r[0]);
}
return *@bitcast(&du_int, &q[0]);
return *@ptrcast(&du_int, &q[0]);
}
export fn __umoddi3(a: du_int, b: du_int) -> du_int {

View file

@ -15,7 +15,7 @@ test "numLitIntToPtrCast" {
test "pointerReinterpretConstFloatToInt" {
const float: f64 = 5.99999999999994648725e-01;
const float_ptr = &float;
const int_ptr = @bitcast(&i32, float_ptr);
const int_ptr = @ptrcast(&i32, float_ptr);
const int_val = *int_ptr;
assert(int_val == 858993411);
}

View file

@ -121,5 +121,5 @@ test "genericFnWithImplicitCast" {
}
fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
getByte(@bitcast(&const u8, &mem[0]))
getByte(@ptrcast(&const u8, &mem[0]))
}

View file

@ -246,15 +246,15 @@ test "typeEquality" {
const global_a: i32 = 1234;
const global_b: &const i32 = &global_a;
const global_c: &const f32 = @bitcast(&const f32, global_b);
const global_c: &const f32 = @ptrcast(&const f32, global_b);
test "compileTimeGlobalReinterpret" {
const d = @bitcast(&const i32, global_c);
const d = @ptrcast(&const i32, global_c);
assert(*d == 1234);
}
test "explicitCastMaybePointers" {
const a: ?&i32 = undefined;
const b: ?&f32 = @bitcast(?&f32, a);
const b: ?&f32 = @ptrcast(?&f32, a);
}
test "genericMallocFree" {
@ -263,7 +263,7 @@ test "genericMallocFree" {
}
const some_mem : [100]u8 = undefined;
fn memAlloc(comptime T: type, n: usize) -> %[]T {
return @bitcast(&T, &some_mem[0])[0...n];
return @ptrcast(&T, &some_mem[0])[0...n];
}
fn memFree(comptime T: type, memory: []T) { }

View file

@ -41,7 +41,7 @@ const VoidStructFieldsFoo = struct {
test "fn" {
var foo: StructFoo = undefined;
@memset(@bitcast(&u8, &foo), 0, @sizeOf(StructFoo));
@memset(@ptrcast(&u8, &foo), 0, @sizeOf(StructFoo));
foo.a += 1;
foo.b = foo.a == 1;
testFoo(foo);

View file

@ -460,8 +460,8 @@ const foo : i32 = 0;
const c = @cImport(@cInclude("stdlib.h"));
export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
const a_int = @bitcast(&i32, a ?? unreachable);
const b_int = @bitcast(&i32, b ?? unreachable);
const a_int = @ptrcast(&i32, a ?? unreachable);
const b_int = @ptrcast(&i32, b ?? unreachable);
if (*a_int < *b_int) {
-1
} else if (*a_int > *b_int) {
@ -474,7 +474,7 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
export fn main(args: c_int, argv: &&u8) -> c_int {
var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
c.qsort(@bitcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
for (array) |item, i| {
if (item != i) {
@ -1812,6 +1812,12 @@ export fn entry() {
foo(global_array);
}
)SOURCE", 1, ".tmp_source.zig:5:9: error: expected type '[]i32', found '[10]i32'");
add_compile_fail_case("ptrcast to non-pointer", R"SOURCE(
export fn entry(a: &i32) -> usize {
return @ptrcast(usize, a);
}
)SOURCE", 1, ".tmp_source.zig:3:21: error: expected pointer, found 'usize'");
}
//////////////////////////////////////////////////////////////////////////////