diff options
| author | vegecode <39607947+vegecode@users.noreply.github.com> | 2019-01-02 15:47:47 -0600 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-01-02 16:47:47 -0500 |
| commit | f6cd68386d76e4a9a489187c47f218b59e1734f3 (patch) | |
| tree | 016fbfe6ceff6e7535bc55c27735e8723ee037de /src/ir.cpp | |
| parent | 6df8e4bca73309f2e340dbfa9031f1bb16a73bcc (diff) | |
| download | zig-f6cd68386d76e4a9a489187c47f218b59e1734f3.tar.gz zig-f6cd68386d76e4a9a489187c47f218b59e1734f3.zip | |
@bitreverse intrinsic, part of #767 (#1865)
* bitreverse - give bswap behavior
* bitreverse, comptime_ints, negative values still not working?
* bitreverse working for negative comptime ints
* Finished bitreverse test cases
* Undo exporting a bigint function. @bitreverse test name includes ampersand
* added docs entry for @bitreverse
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index b1429ae8ac..dac5403550 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<IrInstructionBitReverse>(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<IrInstructionCheckRuntimeScope>(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(); } @@ -21115,6 +21145,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<uint8_t>(buf_size); + uint8_t *result_buf = allocate_nonzero<uint8_t>(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 +21546,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 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: case IrInstructionIdBswap: + case IrInstructionIdBitReverse: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: |
