diff --git a/doc/langref.html.in b/doc/langref.html.in index 2a2b4003fb..6e03d3ec6d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5316,6 +5316,18 @@ comptime {

{#header_close#} + {#header_open|@bitreverse#} +
{#syntax#}@bitreverse(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} accepts any integer type.

+

+ Reverses the bitpattern of an integer value, including the sign bit if applicable. +

+

+ For example 0b10110110 ({#syntax#}u8 = 182{#endsyntax#}, {#syntax#}i8 = -74{#endsyntax#}) + becomes 0b01101101 ({#syntax#}u8 = 109{#endsyntax#}, {#syntax#}i8 = 109{#endsyntax#}). +

+ {#header_close#} + {#header_open|@byteOffsetOf#}
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}

diff --git a/src/all_types.hpp b/src/all_types.hpp index 2b55f8ee2e..91b24e3110 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1166,6 +1166,7 @@ struct ZigTypeFn { FnGenParamInfo *gen_param_info; LLVMTypeRef raw_type_ref; + ZigLLVMDIType *raw_di_type; ZigType *bound_fn_parent; }; @@ -1415,6 +1416,7 @@ enum BuiltinFnId { BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, BuiltinFnIdBswap, + BuiltinFnIdBitReverse, }; struct BuiltinFnEntry { @@ -1488,6 +1490,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, ZigLLVMFnIdBswap, + ZigLLVMFnIdBitReverse, }; enum AddSubMul { @@ -1520,6 +1523,9 @@ struct ZigLLVMFnKey { struct { uint32_t bit_count; } bswap; + struct { + uint32_t bit_count; + } bit_reverse; } data; }; @@ -2162,6 +2168,7 @@ enum IrInstructionId { IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, IrInstructionIdBswap, + IrInstructionIdBitReverse, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3262,6 +3269,13 @@ struct IrInstructionBswap { IrInstruction *op; }; +struct IrInstructionBitReverse { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 0f2b8e48cc..af65838eae 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1220,7 +1220,10 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); - fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type, + LLVMStoreSizeOfType(g->target_data_ref, fn_type->type_ref), + LLVMABIAlignmentOfType(g->target_data_ref, fn_type->type_ref), ""); } g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); @@ -6121,6 +6124,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; case ZigLLVMFnIdBswap: return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; + case ZigLLVMFnIdBitReverse: + return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6141,6 +6146,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.pop_count.bit_count == b.data.pop_count.bit_count; case ZigLLVMFnIdBswap: return a.data.bswap.bit_count == b.data.bswap.bit_count; + case ZigLLVMFnIdBitReverse: + return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/bigint.cpp b/src/bigint.cpp index 8a8d028e82..7299f2379c 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) { bigint_add(x, ©, &one); } + diff --git a/src/codegen.cpp b/src/codegen.cpp index 817cc9aeae..dd2f2b6565 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -649,7 +649,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, - fn_table_entry->type_entry->di_type, is_internal_linkage, + fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage, is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); @@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdBswap; key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBitReverse) { + fn_name = "bitreverse"; + n_args = 1; + key.id = ZigLLVMFnIdBitReverse; + key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); } +static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBitReverse); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); } zig_unreachable(); } @@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); + create_builtin_fn(g, BuiltinFnIdBitReverse, "bitreverse", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index b1429ae8ac..6e6c46885b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { return IrInstructionIdBswap; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) { + return IrInstructionIdBitReverse; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } +static IrInstruction *ir_build_bit_reverse(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBitReverse *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo Buf *name = fn_ref_expr->data.symbol_expr.symbol; auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - if (!entry) { + if (!entry) { // new built in not found add_node_error(irb->codegen, node, buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); return irb->codegen->invalid_instruction; @@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBitReverse: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -14547,8 +14577,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_instruction; - ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type, + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, PtrLenSingle, align_bytes, (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), (uint32_t)host_int_bytes_for_result_type); @@ -16853,16 +16882,12 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { Error err; - static ConstExprValue *type_info_var = nullptr; // TODO oops this global variable made it past code review - static ZigType *type_info_type = nullptr; // TODO oops this global variable made it past code review - if (type_info_var == nullptr) { - type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); - assert(type_info_var->type->id == ZigTypeIdMetaType); + ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); + assert(type_info_var->type->id == ZigTypeIdMetaType); + assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - type_info_type = type_info_var->data.x_type; - assert(type_info_type->id == ZigTypeIdUnion); - } + ZigType *type_info_type = type_info_var->data.x_type; + assert(type_info_type->id == ZigTypeIdUnion); if (type_name == nullptr && root == nullptr) return type_info_type; @@ -17075,12 +17100,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ensure_field_index(fn_def_val->type, "return_type", 7); fn_def_fields[7].special = ConstValSpecialStatic; fn_def_fields[7].type = ira->codegen->builtin_types.entry_type; - if (fn_entry->src_implicit_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type; - else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type; - else - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; + fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; // arg_names: [][] const u8 ensure_field_index(fn_def_val->type, "arg_names", 8); size_t fn_arg_count = fn_entry->variable_list.length; @@ -20150,8 +20170,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } - case ZigTypeIdArray: - zig_panic("TODO buf_read_value_bytes array type"); + case ZigTypeIdArray: { + uint64_t elem_size = type_size(ira->codegen, val->type->data.array.child_type); + size_t len = val->type->data.array.len; + + switch (val->data.x_array.special) { + case ConstArraySpecialNone: + val->data.x_array.data.s_none.elements = create_const_vals(len); + for (size_t i = 0; i < len; i++) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = val->type->data.array.child_type; + if ((err = buf_read_value_bytes(ira, source_node, buf + (elem_size * i), elem))) + return err; + } + break; + case ConstArraySpecialUndef: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); + case ConstArraySpecialBuf: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); + } + + return ErrorNone; + } case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { @@ -20333,6 +20374,7 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru IrInstruction *result = ir_const(ira, &instruction->base, dest_type); result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); return result; } @@ -21115,6 +21157,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction return result; } +static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t num_bits = int_type->data.integral.bit_count; + size_t buf_size = (num_bits + 7) / 8; + uint8_t *comptime_buf = allocate_nonzero(buf_size); + uint8_t *result_buf = allocate_nonzero(buf_size); + memset(comptime_buf,0,buf_size); + memset(result_buf,0,buf_size); + + bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); + + size_t bit_i = 0; + size_t bit_rev_i = num_bits - 1; + for (; bit_i < num_bits; bit_i++, bit_rev_i--) { + if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { + result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); + } + } + + bigint_read_twos_complement(&result->value.data.x_bigint, + result_buf, + int_type->data.integral.bit_count, + ira->codegen->is_big_endian, + int_type->data.integral.is_signed); + + return result; + } + + IrInstruction *result = ir_build_bit_reverse(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; @@ -21453,6 +21558,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_analyze_instruction_bit_reverse(ira, (IrInstructionBitReverse *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21675,6 +21782,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: case IrInstructionIdBswap: + case IrInstructionIdBitReverse: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e09b0073eb..b5099db86a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bit_reverse(IrPrint *irp, IrInstructionBitReverse *instruction) { + fprintf(irp->f, "@bitreverse("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBswap: ir_print_bswap(irp, (IrInstructionBswap *)instruction); break; + case IrInstructionIdBitReverse: + ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index eae5516db3..2f2f4c0a1b 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -22,6 +22,8 @@ pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int; pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; pub extern "c" fn setuid(uid: c_uint) c_int; pub extern "c" fn kill(pid: c_int, sig: c_int) c_int; +pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; +pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { @@ -91,3 +93,28 @@ pub const dirent = extern struct { d_pad1: u16, d_name: [256]u8, }; + +pub const in_port_t = u16; +pub const sa_family_t = u16; + +pub const sockaddr = extern union { + in: sockaddr_in, + in6: sockaddr_in6, +}; + +pub const sockaddr_in = extern struct { + len: u8, + family: sa_family_t, + port: in_port_t, + addr: [16]u8, + zero: [8]u8, +}; + +pub const sockaddr_in6 = extern struct { + len: u8, + family: sa_family_t, + port: in_port_t, + flowinfo: u32, + addr: [16]u8, + scope_id: u32, +}; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 603265b956..a3ab5e7749 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -26,6 +26,21 @@ pub const PROT_READ = 1; pub const PROT_WRITE = 2; pub const PROT_EXEC = 4; +pub const CLOCK_REALTIME = 0; +pub const CLOCK_VIRTUAL = 1; +pub const CLOCK_PROF = 2; +pub const CLOCK_MONOTONIC = 4; +pub const CLOCK_UPTIME = 5; +pub const CLOCK_UPTIME_PRECISE = 7; +pub const CLOCK_UPTIME_FAST = 8; +pub const CLOCK_REALTIME_PRECISE = 9; +pub const CLOCK_REALTIME_FAST = 10; +pub const CLOCK_MONOTONIC_PRECISE = 11; +pub const CLOCK_MONOTONIC_FAST = 12; +pub const CLOCK_SECOND = 13; +pub const CLOCK_THREAD_CPUTIME_ID = 14; +pub const CLOCK_PROCESS_CPUTIME_ID = 15; + pub const MAP_FAILED = maxInt(usize); pub const MAP_SHARED = 0x0001; pub const MAP_PRIVATE = 0x0002; @@ -510,6 +525,10 @@ pub const TIOCGPKT = 0x80045438; pub const TIOCGPTLCK = 0x80045439; pub const TIOCGEXCL = 0x80045440; +pub const sockaddr = c.sockaddr; +pub const sockaddr_in = c.sockaddr_in; +pub const sockaddr_in6 = c.sockaddr_in6; + fn unsigned(s: i32) u32 { return @bitCast(u32, s); } @@ -699,6 +718,14 @@ pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { return errnoWrap(c.nanosleep(req, rem)); } +pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { + return errnoWrap(c.clock_gettime(clk_id, tp)); +} + +pub fn clock_getres(clk_id: i32, tp: *timespec) usize { + return errnoWrap(c.clock_getres(clk_id, tp)); +} + pub fn setuid(uid: u32) usize { return errnoWrap(c.setuid(uid)); } diff --git a/std/os/time.zig b/std/os/time.zig index c3588838bc..42f32f8fee 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -61,7 +61,7 @@ pub fn timestamp() u64 { /// Get the posix timestamp, UTC, in milliseconds pub const milliTimestamp = switch (builtin.os) { Os.windows => milliTimestampWindows, - Os.linux => milliTimestampPosix, + Os.linux, Os.freebsd => milliTimestampPosix, Os.macosx, Os.ios => milliTimestampDarwin, else => @compileError("Unsupported OS"), }; @@ -179,7 +179,7 @@ pub const Timer = struct { debug.assert(err != windows.FALSE); self.start_time = @intCast(u64, start_time); }, - Os.linux => { + Os.linux, Os.freebsd => { //On Linux, seccomp can do arbitrary things to our ability to call // syscalls, including return any errno value it wants and // inconsistently throwing errors. Since we can't account for @@ -215,7 +215,7 @@ pub const Timer = struct { var clock = clockNative() - self.start_time; return switch (builtin.os) { Os.windows => @divFloor(clock * ns_per_s, self.frequency), - Os.linux => clock, + Os.linux, Os.freebsd => clock, Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), else => @compileError("Unsupported OS"), }; @@ -236,7 +236,7 @@ pub const Timer = struct { const clockNative = switch (builtin.os) { Os.windows => clockWindows, - Os.linux => clockLinux, + Os.linux, Os.freebsd => clockLinux, Os.macosx, Os.ios => clockDarwin, else => @compileError("Unsupported OS"), }; diff --git a/test/behavior.zig b/test/behavior.zig index 8090359772..10cd08dad7 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -9,6 +9,7 @@ comptime { _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); _ = @import("cases/bswap.zig"); + _ = @import("cases/bitreverse.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig new file mode 100644 index 0000000000..3721e68a94 --- /dev/null +++ b/test/cases/bitreverse.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const assert = std.debug.assert; +const minInt = std.math.minInt; + +test "@bitreverse" { + comptime testBitReverse(); + testBitReverse(); +} + +fn testBitReverse() void { + // using comptime_ints, unsigned + assert(@bitreverse(u0, 0) == 0); + assert(@bitreverse(u5, 0x12) == 0x9); + assert(@bitreverse(u8, 0x12) == 0x48); + assert(@bitreverse(u16, 0x1234) == 0x2c48); + assert(@bitreverse(u24, 0x123456) == 0x6a2c48); + assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using runtime uints, unsigned + var num0: u0 = 0; + assert(@bitreverse(u0, num0) == 0); + var num5: u5 = 0x12; + assert(@bitreverse(u5, num5) == 0x9); + var num8: u8 = 0x12; + assert(@bitreverse(u8, num8) == 0x48); + var num16: u16 = 0x1234; + assert(@bitreverse(u16, num16) == 0x2c48); + var num24: u24 = 0x123456; + assert(@bitreverse(u24, num24) == 0x6a2c48); + var num32: u32 = 0x12345678; + assert(@bitreverse(u32, num32) == 0x1e6a2c48); + var num40: u40 = 0x123456789a; + assert(@bitreverse(u40, num40) == 0x591e6a2c48); + var num48: u48 = 0x123456789abc; + assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); + var num56: u56 = 0x123456789abcde; + assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + var num64: u64 = 0x123456789abcdef1; + assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + var num128: u128 = 0x123456789abcdef11121314151617181; + assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using comptime_ints, signed, positive + assert(@bitreverse(i0, 0) == 0); + assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); + assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); + assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); + assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); + assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); + assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); + assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); + assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); + assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); + + // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. + var neg5: i5 = minInt(i5) + 1; + assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + var neg8: i8 = -18; + assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + var neg16: i16 = -32694; + assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + var neg24: i24 = -6773785; + assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + var neg32: i32 = -16773785; + assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + var neg40: i40 = minInt(i40) + 12345; + assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + var neg48: i48 = minInt(i48) + 12345; + assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + var neg56: i56 = minInt(i56) + 12345; + assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + var neg64: i64 = minInt(i64) + 12345; + assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + var neg128: i128 = minInt(i128) + 12345; + assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); +} diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig index 6695352383..ba3cc52f09 100644 --- a/test/cases/inttoptr.zig +++ b/test/cases/inttoptr.zig @@ -11,3 +11,17 @@ fn randomAddressToFunction() void { var addr: usize = 0xdeadbeef; var ptr = @intToPtr(fn () void, addr); } + +test "mutate through ptr initialized with constant intToPtr value" { + forceCompilerAnalyzeBranchHardCodedPtrDereference(false); +} + +fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { + const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); + if (x) { + hardCodedP.* = hardCodedP.* | 10; + } else { + return; + } +} + diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig index 6f0e6e5946..54c3dda849 100644 --- a/test/cases/ptrcast.zig +++ b/test/cases/ptrcast.zig @@ -34,3 +34,19 @@ fn testReinterpretBytesAsExternStruct() void { var val = ptr.c; assertOrPanic(val == 5); } + +test "reinterpret struct field at comptime" { + const numLittle = comptime Bytes.init(0x12345678); + assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); +} + +const Bytes = struct { + bytes: [4]u8, + + pub fn init(v: u32) Bytes { + var res: Bytes = undefined; + @ptrCast(*align(1) u32, &res.bytes).* = v; + + return res; + } +};