authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 04:06:07-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 04:06:07-05:00
log8fcb1a141b1f76a0c6b28338723535ec5fbf638b
tree6789b38ce297bedeb60e15446a5980bc3da18574
parent10cea15cc3061272a0ed05fafe9e762f6454fafc

IR: implement fence and cmpxchg builtins


7 files changed, 365 insertions(+), 306 deletions(-)

src/all_types.hpp+25
......@@ -1407,6 +1407,8 @@ enum IrInstructionId {
14071407 IrInstructionIdCompileErr,
14081408 IrInstructionIdErrName,
14091409 IrInstructionIdEmbedFile,
1410 IrInstructionIdCmpxchg,
1411 IrInstructionIdFence,
14101412};
14111413
14121414struct IrInstruction {
......@@ -1859,6 +1861,29 @@ struct IrInstructionEmbedFile {
18591861 IrInstruction *name;
18601862};
18611863
1864struct IrInstructionCmpxchg {
1865 IrInstruction base;
1866
1867 IrInstruction *ptr;
1868 IrInstruction *cmp_value;
1869 IrInstruction *new_value;
1870 IrInstruction *success_order_value;
1871 IrInstruction *failure_order_value;
1872
1873 // if this instruction gets to runtime then we know these values:
1874 AtomicOrder success_order;
1875 AtomicOrder failure_order;
1876};
1877
1878struct IrInstructionFence {
1879 IrInstruction base;
1880
1881 IrInstruction *order_value;
1882
1883 // if this instruction gets to runtime then we know these values:
1884 AtomicOrder order;
1885};
1886
18621887enum LValPurpose {
18631888 LValPurposeNone,
18641889 LValPurposeAssign,
src/analyze.cpp+11
......@@ -2798,3 +2798,14 @@ ConstExprValue *create_const_float(double value) {
27982798 init_const_float(const_val, value);
27992799 return const_val;
28002800}
2801
2802void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag) {
2803 const_val->special = ConstValSpecialStatic;
2804 const_val->data.x_enum.tag = tag;
2805}
2806
2807ConstExprValue *create_const_enum_tag(uint64_t tag) {
2808 ConstExprValue *const_val = allocate<ConstExprValue>(1);
2809 init_const_enum_tag(const_val, tag);
2810 return const_val;
2811}
src/analyze.hpp+3
......@@ -95,4 +95,7 @@ ConstExprValue *create_const_signed(int64_t x);
9595void init_const_float(ConstExprValue *const_val, double value);
9696ConstExprValue *create_const_float(double value);
9797
98void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag);
99ConstExprValue *create_const_enum_tag(uint64_t tag);
100
98101#endif
src/codegen.cpp+37
......@@ -1839,6 +1839,38 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
18391839 return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
18401840}
18411841
1842static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
1843 switch (atomic_order) {
1844 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
1845 case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic;
1846 case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire;
1847 case AtomicOrderRelease: return LLVMAtomicOrderingRelease;
1848 case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease;
1849 case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent;
1850 }
1851 zig_unreachable();
1852}
1853
1854static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
1855 LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
1856 LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
1857 LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
1858
1859 LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
1860 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
1861
1862 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
1863 success_order, failure_order);
1864
1865 return LLVMBuildExtractValue(g->builder, result_val, 1, "");
1866}
1867
1868static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
1869 LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering(instruction->order);
1870 LLVMBuildFence(g->builder, atomic_order, false, "");
1871 return nullptr;
1872}
1873
18421874static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
18431875 AstNode *source_node = instruction->source_node;
18441876 Scope *scope = instruction->scope;
......@@ -1928,6 +1960,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
19281960 return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
19291961 case IrInstructionIdErrName:
19301962 return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
1963 case IrInstructionIdCmpxchg:
1964 return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
1965 case IrInstructionIdFence:
1966 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
19311967 case IrInstructionIdSwitchVar:
19321968 case IrInstructionIdContainerInitList:
19331969 case IrInstructionIdStructInit:
......@@ -2989,6 +3025,7 @@ static void define_builtin_types(CodeGen *g) {
29893025
29903026 {
29913027 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3028 entry->zero_bits = true; // only allowed at compile time
29923029 buf_init_from_str(&entry->name, "AtomicOrder");
29933030 uint32_t field_count = 6;
29943031 entry->data.enumeration.src_field_count = field_count;
src/ir.cpp+249-306
......@@ -347,6 +347,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
347347 return IrInstructionIdEmbedFile;
348348}
349349
350static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
351 return IrInstructionIdCmpxchg;
352}
353
354static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
355 return IrInstructionIdFence;
356}
357
350358template<typename T>
351359static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
352360 T *special_instruction = allocate<T>(1);
......@@ -1357,6 +1365,54 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
13571365 return &instruction->base;
13581366}
13591367
1368static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
1369 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1370 AtomicOrder success_order, AtomicOrder failure_order)
1371{
1372 IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
1373 instruction->ptr = ptr;
1374 instruction->cmp_value = cmp_value;
1375 instruction->new_value = new_value;
1376 instruction->success_order_value = success_order_value;
1377 instruction->failure_order_value = failure_order_value;
1378 instruction->success_order = success_order;
1379 instruction->failure_order = failure_order;
1380
1381 ir_ref_instruction(ptr);
1382 ir_ref_instruction(cmp_value);
1383 ir_ref_instruction(new_value);
1384 ir_ref_instruction(success_order_value);
1385 ir_ref_instruction(failure_order_value);
1386
1387 return &instruction->base;
1388}
1389
1390static IrInstruction *ir_build_cmpxchg_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr,
1391 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1392 AtomicOrder success_order, AtomicOrder failure_order)
1393{
1394 IrInstruction *new_instruction = ir_build_cmpxchg(irb, old_instruction->scope, old_instruction->source_node,
1395 ptr, cmp_value, new_value, success_order_value, failure_order_value, success_order, failure_order);
1396 ir_link_new_instruction(new_instruction, old_instruction);
1397 return new_instruction;
1398}
1399
1400static IrInstruction *ir_build_fence(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *order_value, AtomicOrder order) {
1401 IrInstructionFence *instruction = ir_build_instruction<IrInstructionFence>(irb, scope, source_node);
1402 instruction->order_value = order_value;
1403 instruction->order = order;
1404
1405 ir_ref_instruction(order_value);
1406
1407 return &instruction->base;
1408}
1409
1410static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *order_value, AtomicOrder order) {
1411 IrInstruction *new_instruction = ir_build_fence(irb, old_instruction->scope, old_instruction->source_node, order_value, order);
1412 ir_link_new_instruction(new_instruction, old_instruction);
1413 return new_instruction;
1414}
1415
13601416static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
13611417 bool gen_error_defers, bool gen_maybe_defers)
13621418{
......@@ -2096,6 +2152,46 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
20962152
20972153 return ir_build_embed_file(irb, scope, node, arg0_value);
20982154 }
2155 case BuiltinFnIdCmpExchange:
2156 {
2157 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2158 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2159 if (arg0_value == irb->codegen->invalid_instruction)
2160 return arg0_value;
2161
2162 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
2163 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
2164 if (arg1_value == irb->codegen->invalid_instruction)
2165 return arg1_value;
2166
2167 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
2168 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
2169 if (arg2_value == irb->codegen->invalid_instruction)
2170 return arg2_value;
2171
2172 AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
2173 IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
2174 if (arg3_value == irb->codegen->invalid_instruction)
2175 return arg3_value;
2176
2177 AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
2178 IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
2179 if (arg4_value == irb->codegen->invalid_instruction)
2180 return arg4_value;
2181
2182 return ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
2183 arg2_value, arg3_value, arg4_value,
2184 AtomicOrderUnordered, AtomicOrderUnordered);
2185 }
2186 case BuiltinFnIdFence:
2187 {
2188 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2189 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2190 if (arg0_value == irb->codegen->invalid_instruction)
2191 return arg0_value;
2192
2193 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
2194 }
20992195 case BuiltinFnIdMemcpy:
21002196 case BuiltinFnIdMemset:
21012197 case BuiltinFnIdAlignof:
......@@ -2107,8 +2203,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
21072203 case BuiltinFnIdBreakpoint:
21082204 case BuiltinFnIdReturnAddress:
21092205 case BuiltinFnIdFrameAddress:
2110 case BuiltinFnIdCmpExchange:
2111 case BuiltinFnIdFence:
21122206 case BuiltinFnIdDivExact:
21132207 case BuiltinFnIdTruncate:
21142208 case BuiltinFnIdIntType:
......@@ -3470,6 +3564,12 @@ static bool is_slice(TypeTableEntry *type) {
34703564 return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
34713565}
34723566
3567static bool is_container(TypeTableEntry *type) {
3568 return type->id == TypeTableEntryIdStruct ||
3569 type->id == TypeTableEntryIdEnum ||
3570 type->id == TypeTableEntryIdUnion;
3571}
3572
34733573static bool is_u8(TypeTableEntry *type) {
34743574 return type->id == TypeTableEntryIdInt &&
34753575 !type->data.integral.is_signed && type->data.integral.bit_count == 8;
......@@ -4085,6 +4185,22 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
40854185 return true;
40864186}
40874187
4188static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
4189 if (value->type_entry->id == TypeTableEntryIdInvalid)
4190 return false;
4191
4192 IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_atomic_order_enum);
4193 if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
4194 return false;
4195
4196 ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
4197 if (!const_val)
4198 return false;
4199
4200 *out = (AtomicOrder)const_val->data.x_enum.tag;
4201 return true;
4202}
4203
40884204static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
40894205 if (value->type_entry->id == TypeTableEntryIdInvalid)
40904206 return nullptr;
......@@ -5689,15 +5805,23 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
56895805 if (container_ptr->type_entry->id == TypeTableEntryIdInvalid)
56905806 return ira->codegen->builtin_types.entry_invalid;
56915807
5692 assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
5693 TypeTableEntry *container_type = container_ptr->type_entry->data.pointer.child_type;
5808 TypeTableEntry *container_type;
5809 if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
5810 container_type = container_ptr->type_entry->data.pointer.child_type;
5811 } else if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
5812 container_type = container_ptr->type_entry;
5813 } else {
5814 zig_unreachable();
5815 }
56945816
5817 bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
56955818 Buf *field_name = field_ptr_instruction->field_name;
56965819 AstNode *source_node = field_ptr_instruction->base.source_node;
56975820
56985821 if (container_type->id == TypeTableEntryIdInvalid) {
56995822 return container_type;
57005823 } else if (is_container_ref(container_type)) {
5824 assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
57015825 return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_ptr, container_type);
57025826 } else if (container_type->id == TypeTableEntryIdArray) {
57035827 if (buf_eql_str(field_name, "len")) {
......@@ -5717,26 +5841,43 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
57175841 ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
57185842 if (!container_ptr_val)
57195843 return ira->codegen->builtin_types.entry_invalid;
5720 ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
5721 TypeTableEntry *child_type = child_val->data.x_type;
5844
5845 TypeTableEntry *child_type;
5846 if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
5847 TypeTableEntry *ptr_type = container_ptr_val->data.x_type;
5848 assert(ptr_type->id == TypeTableEntryIdPointer);
5849 child_type = ptr_type->data.pointer.child_type;
5850 } else if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
5851 ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
5852 child_type = child_val->data.x_type;
5853 } else {
5854 zig_unreachable();
5855 }
57225856
57235857 if (child_type->id == TypeTableEntryIdInvalid) {
57245858 return ira->codegen->builtin_types.entry_invalid;
5725 } else if (child_type->id == TypeTableEntryIdEnum) {
5726 zig_panic("TODO enum type field");
5727 } else if (child_type->id == TypeTableEntryIdStruct) {
5859 } else if (is_container(child_type)) {
5860 if (child_type->id == TypeTableEntryIdEnum) {
5861 TypeEnumField *field = find_enum_type_field(child_type, field_name);
5862 if (field) {
5863 if (field->type_entry->id == TypeTableEntryIdVoid) {
5864 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_enum_tag(field->value),
5865 child_type, depends_on_compile_var, ConstPtrSpecialNone);
5866 } else {
5867 zig_panic("TODO enum tag type");
5868 }
5869 }
5870 }
57285871 ScopeDecls *container_scope = get_container_scope(child_type);
57295872 auto entry = container_scope->decl_table.maybe_get(field_name);
57305873 Tld *tld = entry ? entry->value : nullptr;
57315874 if (tld) {
5732 bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
57335875 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld, depends_on_compile_var);
5734 } else {
5735 add_node_error(ira->codegen, source_node,
5736 buf_sprintf("container '%s' has no member called '%s'",
5737 buf_ptr(&child_type->name), buf_ptr(field_name)));
5738 return ira->codegen->builtin_types.entry_invalid;
57395876 }
5877 ir_add_error(ira, &field_ptr_instruction->base,
5878 buf_sprintf("container '%s' has no member called '%s'",
5879 buf_ptr(&child_type->name), buf_ptr(field_name)));
5880 return ira->codegen->builtin_types.entry_invalid;
57405881 } else if (child_type->id == TypeTableEntryIdPureError) {
57415882 auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);
57425883 if (err_table_entry) {
......@@ -5744,7 +5885,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
57445885 const_val->special = ConstValSpecialStatic;
57455886 const_val->data.x_pure_err = err_table_entry->value;
57465887
5747 bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
57485888 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
57495889 child_type, depends_on_compile_var, ConstPtrSpecialNone);
57505890 }
......@@ -5760,6 +5900,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
57605900 return ira->codegen->builtin_types.entry_invalid;
57615901 }
57625902 } else if (container_type->id == TypeTableEntryIdNamespace) {
5903 assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
57635904 ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
57645905 if (!container_ptr_val)
57655906 return ira->codegen->builtin_types.entry_invalid;
......@@ -5769,7 +5910,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
57695910
57705911 ImportTableEntry *namespace_import = namespace_val->data.x_import;
57715912
5772 bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
57735913 Tld *tld = find_decl(&namespace_import->decls_scope->base, field_name);
57745914 if (!tld) {
57755915 // we must now resolve all the use decls
......@@ -7184,10 +7324,10 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
71847324 int err;
71857325 if ((err = os_fetch_file_path(&file_path, &file_contents))) {
71867326 if (err == ErrorFileNotFound) {
7187 ir_add_error(ira, &instruction->base, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
7327 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
71887328 return ira->codegen->builtin_types.entry_invalid;
71897329 } else {
7190 ir_add_error(ira, &instruction->base, buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
7330 ir_add_error(ira, instruction->name, buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
71917331 return ira->codegen->builtin_types.entry_invalid;
71927332 }
71937333 }
......@@ -7197,11 +7337,94 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
71977337
71987338 bool depends_on_compile_var = true;
71997339 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
7200 init_const_str_lit(out_val,&file_contents);
7340 init_const_str_lit(out_val, &file_contents);
72017341
72027342 return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents));
72037343}
72047344
7345static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
7346 IrInstruction *ptr = instruction->ptr->other;
7347 if (ptr->type_entry->id == TypeTableEntryIdInvalid)
7348 return ira->codegen->builtin_types.entry_invalid;
7349
7350 IrInstruction *cmp_value = instruction->cmp_value->other;
7351 if (cmp_value->type_entry->id == TypeTableEntryIdInvalid)
7352 return ira->codegen->builtin_types.entry_invalid;
7353
7354 IrInstruction *new_value = instruction->new_value->other;
7355 if (new_value->type_entry->id == TypeTableEntryIdInvalid)
7356 return ira->codegen->builtin_types.entry_invalid;
7357
7358 IrInstruction *success_order_value = instruction->success_order_value->other;
7359 if (success_order_value->type_entry->id == TypeTableEntryIdInvalid)
7360 return ira->codegen->builtin_types.entry_invalid;
7361
7362 AtomicOrder success_order;
7363 if (!ir_resolve_atomic_order(ira, success_order_value, &success_order))
7364 return ira->codegen->builtin_types.entry_invalid;
7365
7366 IrInstruction *failure_order_value = instruction->failure_order_value->other;
7367 if (failure_order_value->type_entry->id == TypeTableEntryIdInvalid)
7368 return ira->codegen->builtin_types.entry_invalid;
7369
7370 AtomicOrder failure_order;
7371 if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
7372 return ira->codegen->builtin_types.entry_invalid;
7373
7374 if (ptr->type_entry->id != TypeTableEntryIdPointer) {
7375 ir_add_error(ira, instruction->ptr,
7376 buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->type_entry->name)));
7377 return ira->codegen->builtin_types.entry_invalid;
7378 }
7379
7380 TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type;
7381
7382 IrInstruction *casted_cmp_value = ir_get_casted_value(ira, cmp_value, child_type);
7383 if (casted_cmp_value->type_entry->id == TypeTableEntryIdInvalid)
7384 return ira->codegen->builtin_types.entry_invalid;
7385
7386 IrInstruction *casted_new_value = ir_get_casted_value(ira, new_value, child_type);
7387 if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
7388 return ira->codegen->builtin_types.entry_invalid;
7389
7390 if (success_order < AtomicOrderMonotonic) {
7391 ir_add_error(ira, success_order_value,
7392 buf_sprintf("success atomic ordering must be Monotonic or stricter"));
7393 return ira->codegen->builtin_types.entry_invalid;
7394 }
7395 if (failure_order < AtomicOrderMonotonic) {
7396 ir_add_error(ira, failure_order_value,
7397 buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
7398 return ira->codegen->builtin_types.entry_invalid;
7399 }
7400 if (failure_order > success_order) {
7401 ir_add_error(ira, failure_order_value,
7402 buf_sprintf("failure atomic ordering must be no stricter than success"));
7403 return ira->codegen->builtin_types.entry_invalid;
7404 }
7405 if (failure_order == AtomicOrderRelease || failure_order == AtomicOrderAcqRel) {
7406 ir_add_error(ira, failure_order_value,
7407 buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
7408 return ira->codegen->builtin_types.entry_invalid;
7409 }
7410
7411 ir_build_cmpxchg_from(&ira->new_irb, &instruction->base, ptr, casted_cmp_value, casted_new_value,
7412 success_order_value, failure_order_value, success_order, failure_order);
7413 return ira->codegen->builtin_types.entry_bool;
7414}
7415
7416static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
7417 IrInstruction *order_value = instruction->order_value->other;
7418 if (order_value->type_entry->id == TypeTableEntryIdInvalid)
7419 return ira->codegen->builtin_types.entry_invalid;
7420
7421 AtomicOrder order;
7422 if (!ir_resolve_atomic_order(ira, order_value, &order))
7423 return ira->codegen->builtin_types.entry_invalid;
7424
7425 ir_build_fence_from(&ira->new_irb, &instruction->base, order_value, order);
7426 return ira->codegen->builtin_types.entry_void;
7427}
72057428
72067429static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
72077430 switch (instruction->id) {
......@@ -7305,6 +7528,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
73057528 return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
73067529 case IrInstructionIdEmbedFile:
73077530 return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
7531 case IrInstructionIdCmpxchg:
7532 return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
7533 case IrInstructionIdFence:
7534 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
73087535 case IrInstructionIdCast:
73097536 case IrInstructionIdStructFieldPtr:
73107537 case IrInstructionIdEnumFieldPtr:
......@@ -7404,6 +7631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
74047631 case IrInstructionIdCInclude:
74057632 case IrInstructionIdCDefine:
74067633 case IrInstructionIdCUndef:
7634 case IrInstructionIdCmpxchg:
7635 case IrInstructionIdFence:
74077636 return true;
74087637 case IrInstructionIdPhi:
74097638 case IrInstructionIdUnOp:
......@@ -7453,102 +7682,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
74537682// TODO port over all this commented out code into new IR way of doing things
74547683
74557684
7456//static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
7457// BlockContext *context, AstNode *node)
7458//{
7459// assert(node->type == NodeTypeFnCallExpr);
7460//
7461// AstNode **ptr_arg = &node->data.fn_call_expr.params.at(0);
7462// AstNode **cmp_arg = &node->data.fn_call_expr.params.at(1);
7463// AstNode **new_arg = &node->data.fn_call_expr.params.at(2);
7464// AstNode **success_order_arg = &node->data.fn_call_expr.params.at(3);
7465// AstNode **failure_order_arg = &node->data.fn_call_expr.params.at(4);
7466//
7467// TypeTableEntry *ptr_type = analyze_expression(g, import, context, nullptr, *ptr_arg);
7468// if (ptr_type->id == TypeTableEntryIdInvalid) {
7469// return g->builtin_types.entry_invalid;
7470// } else if (ptr_type->id != TypeTableEntryIdPointer) {
7471// add_node_error(g, *ptr_arg,
7472// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr_type->name)));
7473// return g->builtin_types.entry_invalid;
7474// }
7475//
7476// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
7477// TypeTableEntry *cmp_type = analyze_expression(g, import, context, child_type, *cmp_arg);
7478// TypeTableEntry *new_type = analyze_expression(g, import, context, child_type, *new_arg);
7479//
7480// TypeTableEntry *success_order_type = analyze_expression(g, import, context,
7481// g->builtin_types.entry_atomic_order_enum, *success_order_arg);
7482// TypeTableEntry *failure_order_type = analyze_expression(g, import, context,
7483// g->builtin_types.entry_atomic_order_enum, *failure_order_arg);
7484//
7485// if (cmp_type->id == TypeTableEntryIdInvalid ||
7486// new_type->id == TypeTableEntryIdInvalid ||
7487// success_order_type->id == TypeTableEntryIdInvalid ||
7488// failure_order_type->id == TypeTableEntryIdInvalid)
7489// {
7490// return g->builtin_types.entry_invalid;
7491// }
7492//
7493// ConstExprValue *success_order_val = &get_resolved_expr(*success_order_arg)->const_val;
7494// ConstExprValue *failure_order_val = &get_resolved_expr(*failure_order_arg)->const_val;
7495// if (!success_order_val->ok) {
7496// add_node_error(g, *success_order_arg, buf_sprintf("unable to evaluate constant expression"));
7497// return g->builtin_types.entry_invalid;
7498// } else if (!failure_order_val->ok) {
7499// add_node_error(g, *failure_order_arg, buf_sprintf("unable to evaluate constant expression"));
7500// return g->builtin_types.entry_invalid;
7501// }
7502//
7503// if (success_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
7504// add_node_error(g, *success_order_arg,
7505// buf_sprintf("success atomic ordering must be Monotonic or stricter"));
7506// return g->builtin_types.entry_invalid;
7507// }
7508// if (failure_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
7509// add_node_error(g, *failure_order_arg,
7510// buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
7511// return g->builtin_types.entry_invalid;
7512// }
7513// if (failure_order_val->data.x_enum.tag > success_order_val->data.x_enum.tag) {
7514// add_node_error(g, *failure_order_arg,
7515// buf_sprintf("failure atomic ordering must be no stricter than success"));
7516// return g->builtin_types.entry_invalid;
7517// }
7518// if (failure_order_val->data.x_enum.tag == AtomicOrderRelease ||
7519// failure_order_val->data.x_enum.tag == AtomicOrderAcqRel)
7520// {
7521// add_node_error(g, *failure_order_arg,
7522// buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
7523// return g->builtin_types.entry_invalid;
7524// }
7525//
7526// return g->builtin_types.entry_bool;
7527//}
7528//
7529//static TypeTableEntry *analyze_fence(CodeGen *g, ImportTableEntry *import,
7530// BlockContext *context, AstNode *node)
7531//{
7532// assert(node->type == NodeTypeFnCallExpr);
7533//
7534// AstNode **atomic_order_arg = &node->data.fn_call_expr.params.at(0);
7535// TypeTableEntry *atomic_order_type = analyze_expression(g, import, context,
7536// g->builtin_types.entry_atomic_order_enum, *atomic_order_arg);
7537//
7538// if (atomic_order_type->id == TypeTableEntryIdInvalid) {
7539// return g->builtin_types.entry_invalid;
7540// }
7541//
7542// ConstExprValue *atomic_order_val = &get_resolved_expr(*atomic_order_arg)->const_val;
7543//
7544// if (!atomic_order_val->ok) {
7545// add_node_error(g, *atomic_order_arg, buf_sprintf("unable to evaluate constant expression"));
7546// return g->builtin_types.entry_invalid;
7547// }
7548//
7549// return g->builtin_types.entry_void;
7550//}
7551//
75527685//static TypeTableEntry *analyze_div_exact(CodeGen *g, ImportTableEntry *import,
75537686// BlockContext *context, AstNode *node)
75547687//{
......@@ -7780,8 +7913,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
77807913// return g->builtin_types.entry_invalid;
77817914// }
77827915// }
7783// case BuiltinFnIdImport:
7784// return analyze_import(g, import, context, node);
77857916// case BuiltinFnIdBreakpoint:
77867917// mark_impure_fn(g, context, node);
77877918// return g->builtin_types.entry_void;
......@@ -7789,20 +7920,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
77897920// case BuiltinFnIdFrameAddress:
77907921// mark_impure_fn(g, context, node);
77917922// return builtin_fn->return_type;
7792// case BuiltinFnIdCmpExchange:
7793// return analyze_cmpxchg(g, import, context, node);
7794// case BuiltinFnIdFence:
7795// return analyze_fence(g, import, context, node);
77967923// case BuiltinFnIdDivExact:
77977924// return analyze_div_exact(g, import, context, node);
77987925// case BuiltinFnIdTruncate:
77997926// return analyze_truncate(g, import, context, node);
78007927// case BuiltinFnIdIntType:
78017928// return analyze_int_type(g, import, context, node);
7802// case BuiltinFnIdSetFnTest:
7803// return analyze_set_fn_test(g, import, context, node);
7804// case BuiltinFnIdSetFnNoInline:
7805// return analyze_set_fn_no_inline(g, import, context, node);
78067929// }
78077930// zig_unreachable();
78087931//}
......@@ -7881,68 +8004,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
78818004// }
78828005// zig_unreachable();
78838006//}
7884//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7885// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
7886// AstNode *out_node)
7887//{
7888// assert(field_access_node->type == NodeTypeFieldAccessExpr);
7889//
7890// TypeEnumField *type_enum_field = find_enum_type_field(enum_type, field_name);
7891// if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) {
7892// return g->builtin_types.entry_invalid;
7893// }
7894//
7895// field_access_node->data.field_access_expr.type_enum_field = type_enum_field;
7896//
7897// if (type_enum_field) {
7898// if (value_node) {
7899// AstNode **value_node_ptr = value_node->parent_field;
7900// TypeTableEntry *value_type = analyze_expression(g, import, context,
7901// type_enum_field->type_entry, value_node);
7902//
7903// if (value_type->id == TypeTableEntryIdInvalid) {
7904// return g->builtin_types.entry_invalid;
7905// }
7906//
7907// StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;
7908// codegen->type_entry = enum_type;
7909// codegen->source_node = field_access_node;
7910//
7911// ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val;
7912// if (value_const_val->ok) {
7913// ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val;
7914// const_val->ok = true;
7915// const_val->data.x_enum.tag = type_enum_field->value;
7916// const_val->data.x_enum.payload = value_const_val;
7917// } else {
7918// if (context->fn_entry) {
7919// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
7920// } else {
7921// add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression"));
7922// return g->builtin_types.entry_invalid;
7923// }
7924// }
7925// } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {
7926// add_node_error(g, field_access_node,
7927// buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
7928// buf_ptr(&enum_type->name),
7929// buf_ptr(field_name),
7930// buf_ptr(&type_enum_field->type_entry->name)));
7931// } else {
7932// Expr *expr = get_resolved_expr(out_node);
7933// expr->const_val.ok = true;
7934// expr->const_val.data.x_enum.tag = type_enum_field->value;
7935// expr->const_val.data.x_enum.payload = nullptr;
7936// }
7937// } else {
7938// add_node_error(g, field_access_node,
7939// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
7940// buf_ptr(&enum_type->name)));
7941// }
7942// return enum_type;
7943//}
7944//
7945//
79468007//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
79478008// AstNode *node)
79488009//{
......@@ -8182,34 +8243,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
81828243//
81838244
81848245
8185//static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) {
8186// assert(node->type == NodeTypeFnCallExpr);
8187//
8188// AstNode *ptr_arg = node->data.fn_call_expr.params.at(0);
8189// AstNode *cmp_arg = node->data.fn_call_expr.params.at(1);
8190// AstNode *new_arg = node->data.fn_call_expr.params.at(2);
8191// AstNode *success_order_arg = node->data.fn_call_expr.params.at(3);
8192// AstNode *failure_order_arg = node->data.fn_call_expr.params.at(4);
8193//
8194// LLVMValueRef ptr_val = gen_expr(g, ptr_arg);
8195// LLVMValueRef cmp_val = gen_expr(g, cmp_arg);
8196// LLVMValueRef new_val = gen_expr(g, new_arg);
8197//
8198// ConstExprValue *success_order_val = &get_resolved_expr(success_order_arg)->const_val;
8199// ConstExprValue *failure_order_val = &get_resolved_expr(failure_order_arg)->const_val;
8200//
8201// assert(success_order_val->ok);
8202// assert(failure_order_val->ok);
8203//
8204// LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering((AtomicOrder)success_order_val->data.x_enum.tag);
8205// LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag);
8206//
8207// LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
8208// success_order, failure_order);
8209//
8210// return LLVMBuildExtractValue(g->builder, result_val, 1, "");
8211//}
8212//
82138246//static LLVMValueRef gen_div_exact(CodeGen *g, AstNode *node) {
82148247// assert(node->type == NodeTypeFnCallExpr);
82158248//
......@@ -8269,9 +8302,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
82698302// switch (builtin_fn->id) {
82708303// case BuiltinFnIdInvalid:
82718304// case BuiltinFnIdTypeof:
8272// case BuiltinFnIdImport:
8273// case BuiltinFnIdCImport:
8274// case BuiltinFnIdCompileErr:
82758305// case BuiltinFnIdIntType:
82768306// zig_unreachable();
82778307// case BuiltinFnIdAddWithOverflow:
......@@ -8585,25 +8615,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
85858615// }
85868616//}
85878617//
8588//
8589//
8590//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
8591// assert(node->type == NodeTypeBinOpExpr);
8592//
8593// AstNode *lhs_node = node->data.bin_op_expr.op1;
8594//
8595// TypeTableEntry *op1_type;
8596//
8597// LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
8598//
8599// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
8600//
8601// LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
8602//
8603// gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
8604// return nullptr;
8605//}
8606//
86078618//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
86088619// assert(node->type == NodeTypeUnwrapErrorExpr);
86098620//
......@@ -8894,71 +8905,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {
88948905// gen_var_debug_decl(g, variable);
88958906// return nullptr;
88968907//}
8897//
8898//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
8899// assert(node->type == NodeTypeArrayAccessExpr);
8900//
8901// LLVMValueRef ptr = gen_array_ptr(g, node);
8902// TypeTableEntry *child_type;
8903// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
8904// if (array_type->id == TypeTableEntryIdPointer) {
8905// child_type = array_type->data.pointer.child_type;
8906// } else if (array_type->id == TypeTableEntryIdStruct) {
8907// assert(array_type->data.structure.is_slice);
8908// TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
8909// assert(child_ptr_type->id == TypeTableEntryIdPointer);
8910// child_type = child_ptr_type->data.pointer.child_type;
8911// } else if (array_type->id == TypeTableEntryIdArray) {
8912// child_type = array_type->data.array.child_type;
8913// } else {
8914// zig_unreachable();
8915// }
8916//
8917// if (is_lvalue || !ptr || handle_is_ptr(child_type)) {
8918// return ptr;
8919// } else {
8920// return LLVMBuildLoad(g->builder, ptr, "");
8921// }
8922//}
8923//
8924//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
8925// AstNode *init_expr = node->data.variable_declaration.expr;
8926// if (node->data.variable_declaration.is_const && init_expr) {
8927// TypeTableEntry *init_expr_type = get_expr_type(init_expr);
8928// if (init_expr_type->id == TypeTableEntryIdNumLitFloat ||
8929// init_expr_type->id == TypeTableEntryIdNumLitInt)
8930// {
8931// return nullptr;
8932// }
8933// }
8934//
8935// LLVMValueRef init_val = nullptr;
8936// TypeTableEntry *init_val_type;
8937// return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false);
8938//}
8939//
8940//static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) {
8941// assert(node->type == NodeTypeFnCallExpr);
8942//
8943// AstNode *atomic_order_arg = node->data.fn_call_expr.params.at(0);
8944// ConstExprValue *atomic_order_val = &get_resolved_expr(atomic_order_arg)->const_val;
8945//
8946// assert(atomic_order_val->ok);
8947//
8948// LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering((AtomicOrder)atomic_order_val->data.x_enum.tag);
8949//
8950// LLVMBuildFence(g->builder, atomic_order, false, "");
8951// return nullptr;
8952//}
8953//
8954//static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
8955// switch (atomic_order) {
8956// case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
8957// case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic;
8958// case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire;
8959// case AtomicOrderRelease: return LLVMAtomicOrderingRelease;
8960// case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease;
8961// case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent;
8962// }
8963// zig_unreachable();
8964//}
src/ir_print.cpp+26
......@@ -719,6 +719,26 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
719719 fprintf(irp->f, ")");
720720}
721721
722static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
723 fprintf(irp->f, "@cmpxchg(");
724 ir_print_other_instruction(irp, instruction->ptr);
725 fprintf(irp->f, ", ");
726 ir_print_other_instruction(irp, instruction->cmp_value);
727 fprintf(irp->f, ", ");
728 ir_print_other_instruction(irp, instruction->new_value);
729 fprintf(irp->f, ", ");
730 ir_print_other_instruction(irp, instruction->success_order_value);
731 fprintf(irp->f, ", ");
732 ir_print_other_instruction(irp, instruction->failure_order_value);
733 fprintf(irp->f, ")");
734}
735
736static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
737 fprintf(irp->f, "@fence(");
738 ir_print_other_instruction(irp, instruction->order_value);
739 fprintf(irp->f, ")");
740}
741
722742static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
723743 ir_print_prefix(irp, instruction);
724744 switch (instruction->id) {
......@@ -883,6 +903,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
883903 case IrInstructionIdEmbedFile:
884904 ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
885905 break;
906 case IrInstructionIdCmpxchg:
907 ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
908 break;
909 case IrInstructionIdFence:
910 ir_print_fence(irp, (IrInstructionFence *)instruction);
911 break;
886912 }
887913 fprintf(irp->f, "\n");
888914}
test/self_hosted2.zig+14
......@@ -273,6 +273,18 @@ fn testErrorName() {
273273// return result;
274274//}
275275
276fn cmpxchg() {
277 var x: i32 = 1234;
278 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
279 assert(x == 5678);
280}
281
282fn fence() {
283 var x: i32 = 1234;
284 @fence(AtomicOrder.SeqCst);
285 x = 5678;
286}
287
276288fn assert(ok: bool) {
277289 if (!ok)
278290 @unreachable();
......@@ -300,6 +312,8 @@ fn runAllTests() {
300312 testMinValueAndMaxValue();
301313 testReturnStringFromFunction();
302314 testErrorName();
315 cmpxchg();
316 fence();
303317}
304318
305319export nakedcc fn _start() -> unreachable {