authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-11-13 00:25:44+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-11-13 00:25:44+02:00
log110ef2e52825656fc048cba020f0fc36a1e58d13
treecae3ae95a6ce44f85650c44b90365f7cc5cb4045
parent956ba8b0e7ada08f2f85cd41ee73af6453db0c16
signaturelock-open Commit is signed but in an unrecognized format.

add @atomicStore builtin


6 files changed, 185 insertions(+), 3 deletions(-)

doc/langref.html.in+22-3
......@@ -6612,14 +6612,14 @@ async fn func(y: *i32) void {
66126612 This builtin function atomically dereferences a pointer and returns the value.
66136613 </p>
66146614 <p>
6615 {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#},
6616 or an integer whose bit count meets these requirements:
6615 {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}
6616 an integer whose bit count meets these requirements:
66176617 </p>
66186618 <ul>
66196619 <li>At least 8</li>
66206620 <li>At most the same as usize</li>
66216621 <li>Power of 2</li>
6622 </ul>
6622 </ul> or an enum with a valid integer tag type.
66236623 <p>
66246624 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
66256625 we can remove this restriction
......@@ -6660,6 +6660,25 @@ async fn func(y: *i32) void {
66606660 <li>{#syntax#}.Min{#endsyntax#} - stores the operand if it is smaller. Supports integers and floats.</li>
66616661 </ul>
66626662 {#header_close#}
6663 {#header_open|@atomicStore#}
6664 <pre>{#syntax#}@atomicStore(comptime T: type, ptr: *T, value: T, comptime ordering: builtin.AtomicOrder) void{#endsyntax#}</pre>
6665 <p>
6666 This builtin function atomically stores a value.
6667 </p>
6668 <p>
6669 {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}
6670 an integer whose bit count meets these requirements:
6671 </p>
6672 <ul>
6673 <li>At least 8</li>
6674 <li>At most the same as usize</li>
6675 <li>Power of 2</li>
6676 </ul> or an enum with a valid integer tag type.
6677 <p>
6678 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
6679 we can remove this restriction
6680 </p>
6681 {#header_close#}
66636682 {#header_open|@bitCast#}
66646683 <pre>{#syntax#}@bitCast(comptime DestType: type, value: var) DestType{#endsyntax#}</pre>
66656684 <p>
src/all_types.hpp+12
......@@ -1700,6 +1700,7 @@ enum BuiltinFnId {
17001700 BuiltinFnIdErrorReturnTrace,
17011701 BuiltinFnIdAtomicRmw,
17021702 BuiltinFnIdAtomicLoad,
1703 BuiltinFnIdAtomicStore,
17031704 BuiltinFnIdHasDecl,
17041705 BuiltinFnIdUnionInit,
17051706 BuiltinFnIdFrameAddress,
......@@ -2569,6 +2570,7 @@ enum IrInstructionId {
25692570 IrInstructionIdErrorUnion,
25702571 IrInstructionIdAtomicRmw,
25712572 IrInstructionIdAtomicLoad,
2573 IrInstructionIdAtomicStore,
25722574 IrInstructionIdSaveErrRetAddr,
25732575 IrInstructionIdAddImplicitReturnType,
25742576 IrInstructionIdErrSetCast,
......@@ -3713,6 +3715,16 @@ struct IrInstructionAtomicLoad {
37133715 AtomicOrder resolved_ordering;
37143716};
37153717
3718struct IrInstructionAtomicStore {
3719 IrInstruction base;
3720
3721 IrInstruction *operand_type;
3722 IrInstruction *ptr;
3723 IrInstruction *value;
3724 IrInstruction *ordering;
3725 AtomicOrder resolved_ordering;
3726};
3727
37163728struct IrInstructionSaveErrRetAddr {
37173729 IrInstruction base;
37183730};
src/codegen.cpp+14
......@@ -5650,6 +5650,17 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
56505650 return load_inst;
56515651}
56525652
5653static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutable *executable,
5654 IrInstructionAtomicStore *instruction)
5655{
5656 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
5657 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
5658 LLVMValueRef value = ir_llvm_value(g, instruction->value);
5659 LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value.type);
5660 LLVMSetOrdering(store_inst, ordering);
5661 return nullptr;
5662}
5663
56535664static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
56545665 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
56555666 assert(instruction->base.value.type->id == ZigTypeIdFloat);
......@@ -6253,6 +6264,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
62536264 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
62546265 case IrInstructionIdAtomicLoad:
62556266 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
6267 case IrInstructionIdAtomicStore:
6268 return ir_render_atomic_store(g, executable, (IrInstructionAtomicStore *)instruction);
62566269 case IrInstructionIdSaveErrRetAddr:
62576270 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
62586271 case IrInstructionIdFloatOp:
......@@ -8064,6 +8077,7 @@ static void define_builtin_fns(CodeGen *g) {
80648077 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
80658078 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
80668079 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
8080 create_builtin_fn(g, BuiltinFnIdAtomicStore, "atomicStore", 4);
80678081 create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
80688082 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
80698083 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
src/ir.cpp+103
......@@ -1009,6 +1009,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
10091009 return IrInstructionIdAtomicLoad;
10101010}
10111011
1012static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicStore *) {
1013 return IrInstructionIdAtomicStore;
1014}
1015
10121016static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
10131017 return IrInstructionIdSaveErrRetAddr;
10141018}
......@@ -3186,6 +3190,25 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode
31863190 return &instruction->base;
31873191}
31883192
3193static IrInstruction *ir_build_atomic_store(IrBuilder *irb, Scope *scope, AstNode *source_node,
3194 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *value,
3195 IrInstruction *ordering, AtomicOrder resolved_ordering)
3196{
3197 IrInstructionAtomicStore *instruction = ir_build_instruction<IrInstructionAtomicStore>(irb, scope, source_node);
3198 instruction->operand_type = operand_type;
3199 instruction->ptr = ptr;
3200 instruction->value = value;
3201 instruction->ordering = ordering;
3202 instruction->resolved_ordering = resolved_ordering;
3203
3204 if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block);
3205 ir_ref_instruction(ptr, irb->current_basic_block);
3206 ir_ref_instruction(value, irb->current_basic_block);
3207 if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block);
3208
3209 return &instruction->base;
3210}
3211
31893212static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
31903213 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
31913214 return &instruction->base;
......@@ -5730,6 +5753,33 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
57305753 AtomicOrderMonotonic);
57315754 return ir_lval_wrap(irb, scope, inst, lval, result_loc);
57325755 }
5756 case BuiltinFnIdAtomicStore:
5757 {
5758 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5759 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5760 if (arg0_value == irb->codegen->invalid_instruction)
5761 return arg0_value;
5762
5763 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
5764 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
5765 if (arg1_value == irb->codegen->invalid_instruction)
5766 return arg1_value;
5767
5768 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
5769 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
5770 if (arg2_value == irb->codegen->invalid_instruction)
5771 return arg2_value;
5772
5773 AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
5774 IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
5775 if (arg3_value == irb->codegen->invalid_instruction)
5776 return arg3_value;
5777
5778 IrInstruction *inst = ir_build_atomic_store(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value,
5779 // this value does not mean anything since we passed non-null values for other arg
5780 AtomicOrderMonotonic);
5781 return ir_lval_wrap(irb, scope, inst, lval, result_loc);
5782 }
57335783 case BuiltinFnIdIntToEnum:
57345784 {
57355785 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -25748,6 +25798,56 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
2574825798 return result;
2574925799}
2575025800
25801static IrInstruction *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstructionAtomicStore *instruction) {
25802 ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
25803 if (type_is_invalid(operand_type))
25804 return ira->codegen->invalid_instruction;
25805
25806 IrInstruction *ptr_inst = instruction->ptr->child;
25807 if (type_is_invalid(ptr_inst->value.type))
25808 return ira->codegen->invalid_instruction;
25809
25810 ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true);
25811 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
25812 if (type_is_invalid(casted_ptr->value.type))
25813 return ira->codegen->invalid_instruction;
25814
25815 IrInstruction *value = instruction->value->child;
25816 if (type_is_invalid(value->value.type))
25817 return ira->codegen->invalid_instruction;
25818
25819 IrInstruction *casted_value = ir_implicit_cast(ira, value, operand_type);
25820 if (type_is_invalid(casted_value->value.type))
25821 return ira->codegen->invalid_instruction;
25822
25823
25824 AtomicOrder ordering;
25825 if (instruction->ordering == nullptr) {
25826 ordering = instruction->resolved_ordering;
25827 } else {
25828 if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering))
25829 return ira->codegen->invalid_instruction;
25830 }
25831
25832 if (ordering == AtomicOrderAcquire || ordering == AtomicOrderAcqRel) {
25833 ir_assert(instruction->ordering != nullptr, &instruction->base);
25834 ir_add_error(ira, instruction->ordering,
25835 buf_sprintf("@atomicStore atomic ordering must not be Acquire or AcqRel"));
25836 return ira->codegen->invalid_instruction;
25837 }
25838
25839 if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) {
25840 IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr, nullptr);
25841 ir_assert(result->value.type != nullptr, &instruction->base);
25842 return result;
25843 }
25844
25845 IrInstruction *result = ir_build_atomic_store(&ira->new_irb, instruction->base.scope,
25846 instruction->base.source_node, nullptr, casted_ptr, casted_value, nullptr, ordering);
25847 result->value.type = ira->codegen->builtin_types.entry_void;
25848 return result;
25849}
25850
2575125851static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
2575225852 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
2575325853 instruction->base.source_node);
......@@ -26782,6 +26882,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2678226882 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
2678326883 case IrInstructionIdAtomicLoad:
2678426884 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);
26885 case IrInstructionIdAtomicStore:
26886 return ir_analyze_instruction_atomic_store(ira, (IrInstructionAtomicStore *)instruction);
2678526887 case IrInstructionIdSaveErrRetAddr:
2678626888 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
2678726889 case IrInstructionIdAddImplicitReturnType:
......@@ -26962,6 +27064,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2696227064 case IrInstructionIdSaveErrRetAddr:
2696327065 case IrInstructionIdAddImplicitReturnType:
2696427066 case IrInstructionIdAtomicRmw:
27067 case IrInstructionIdAtomicStore:
2696527068 case IrInstructionIdCmpxchgGen:
2696627069 case IrInstructionIdCmpxchgSrc:
2696727070 case IrInstructionIdAssertZero:
src/ir_print.cpp+26
......@@ -324,6 +324,8 @@ const char* ir_instruction_type_str(IrInstructionId id) {
324324 return "AtomicRmw";
325325 case IrInstructionIdAtomicLoad:
326326 return "AtomicLoad";
327 case IrInstructionIdAtomicStore:
328 return "AtomicStore";
327329 case IrInstructionIdSaveErrRetAddr:
328330 return "SaveErrRetAddr";
329331 case IrInstructionIdAddImplicitReturnType:
......@@ -1871,6 +1873,27 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct
18711873 fprintf(irp->f, ")");
18721874}
18731875
1876static void ir_print_atomic_store(IrPrint *irp, IrInstructionAtomicStore *instruction) {
1877 fprintf(irp->f, "@atomicStore(");
1878 if (instruction->operand_type != nullptr) {
1879 ir_print_other_instruction(irp, instruction->operand_type);
1880 } else {
1881 fprintf(irp->f, "[TODO print]");
1882 }
1883 fprintf(irp->f, ",");
1884 ir_print_other_instruction(irp, instruction->ptr);
1885 fprintf(irp->f, ",");
1886 ir_print_other_instruction(irp, instruction->value);
1887 fprintf(irp->f, ",");
1888 if (instruction->ordering != nullptr) {
1889 ir_print_other_instruction(irp, instruction->ordering);
1890 } else {
1891 fprintf(irp->f, "[TODO print]");
1892 }
1893 fprintf(irp->f, ")");
1894}
1895
1896
18741897static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
18751898 fprintf(irp->f, "@saveErrRetAddr()");
18761899}
......@@ -2431,6 +2454,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool
24312454 case IrInstructionIdAtomicLoad:
24322455 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
24332456 break;
2457 case IrInstructionIdAtomicStore:
2458 ir_print_atomic_store(irp, (IrInstructionAtomicStore *)instruction);
2459 break;
24342460 case IrInstructionIdEnumToInt:
24352461 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);
24362462 break;
test/stage1/behavior/atomics.zig+8
......@@ -123,3 +123,11 @@ test "atomic load and rmw with enum" {
123123 expect(@atomicLoad(Value, &x, .SeqCst) != .a);
124124 expect(@atomicLoad(Value, &x, .SeqCst) != .b);
125125}
126
127test "atomic store" {
128 var x: u32 = 0;
129 @atomicStore(u32, &x, 1, .SeqCst);
130 expect(@atomicLoad(u32, &x, .SeqCst) == 1);
131 @atomicStore(u32, &x, 12345678, .SeqCst);
132 expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
133}
\ No newline at end of file