| author | |
| committer | |
| log | c95e49785772a54916418630fbc7283791a4aa72 |
| tree | 4097d9cfef1b2ce5209410310480fad730f5a5ec |
| parent | f2bc5ccbc2f322b625719d374bbb09a4335c1bd1 |
8 files changed, 213 insertions(+), 0 deletions(-)
src/all_types.hpp+10| ... | @@ -1115,6 +1115,7 @@ enum BuiltinFnId { | ... | @@ -1115,6 +1115,7 @@ enum BuiltinFnId { |
| 1115 | BuiltinFnIdErrName, | 1115 | BuiltinFnIdErrName, |
| 1116 | BuiltinFnIdBreakpoint, | 1116 | BuiltinFnIdBreakpoint, |
| 1117 | BuiltinFnIdEmbedFile, | 1117 | BuiltinFnIdEmbedFile, |
| 1118 | BuiltinFnIdCmpExchange, | ||
| 1118 | }; | 1119 | }; |
| 1119 | 1120 | ||
| 1120 | struct BuiltinFnEntry { | 1121 | struct BuiltinFnEntry { |
| ... | @@ -1183,6 +1184,7 @@ struct CodeGen { | ... | @@ -1183,6 +1184,7 @@ struct CodeGen { |
| 1183 | TypeTableEntry *entry_os_enum; | 1184 | TypeTableEntry *entry_os_enum; |
| 1184 | TypeTableEntry *entry_arch_enum; | 1185 | TypeTableEntry *entry_arch_enum; |
| 1185 | TypeTableEntry *entry_environ_enum; | 1186 | TypeTableEntry *entry_environ_enum; |
| 1187 | TypeTableEntry *entry_mem_order_enum; | ||
| 1186 | } builtin_types; | 1188 | } builtin_types; |
| 1187 | 1189 | ||
| 1188 | ZigTarget zig_target; | 1190 | ZigTarget zig_target; |
| ... | @@ -1322,6 +1324,14 @@ struct BlockContext { | ... | @@ -1322,6 +1324,14 @@ struct BlockContext { |
| 1322 | bool safety_off; | 1324 | bool safety_off; |
| 1323 | }; | 1325 | }; |
| 1324 | 1326 | ||
| 1327 | enum AtomicOrder { | ||
| 1328 | AtomicOrderUnordered, | ||
| 1329 | AtomicOrderMonotonic, | ||
| 1330 | AtomicOrderAcquire, | ||
| 1331 | AtomicOrderRelease, | ||
| 1332 | AtomicOrderAcqRel, | ||
| 1333 | AtomicOrderSeqCst, | ||
| 1334 | }; | ||
| 1325 | 1335 | ||
| 1326 | 1336 | ||
| 1327 | #endif | 1337 | #endif |
src/analyze.cpp+73| ... | @@ -4414,6 +4414,77 @@ static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import, | ... | @@ -4414,6 +4414,77 @@ static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import, |
| 4414 | return resolve_expr_const_val_as_string_lit(g, node, &file_contents); | 4414 | return resolve_expr_const_val_as_string_lit(g, node, &file_contents); |
| 4415 | } | 4415 | } |
| 4416 | 4416 | ||
| 4417 | static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import, | ||
| 4418 | BlockContext *context, AstNode *node) | ||
| 4419 | { | ||
| 4420 | AstNode **ptr_arg = &node->data.fn_call_expr.params.at(0); | ||
| 4421 | AstNode **cmp_arg = &node->data.fn_call_expr.params.at(1); | ||
| 4422 | AstNode **new_arg = &node->data.fn_call_expr.params.at(2); | ||
| 4423 | AstNode **success_order_arg = &node->data.fn_call_expr.params.at(3); | ||
| 4424 | AstNode **failure_order_arg = &node->data.fn_call_expr.params.at(4); | ||
| 4425 | |||
| 4426 | TypeTableEntry *ptr_type = analyze_expression(g, import, context, nullptr, *ptr_arg); | ||
| 4427 | if (ptr_type->id == TypeTableEntryIdInvalid) { | ||
| 4428 | return g->builtin_types.entry_invalid; | ||
| 4429 | } else if (ptr_type->id != TypeTableEntryIdPointer) { | ||
| 4430 | add_node_error(g, *ptr_arg, | ||
| 4431 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&ptr_type->name))); | ||
| 4432 | return g->builtin_types.entry_invalid; | ||
| 4433 | } | ||
| 4434 | |||
| 4435 | TypeTableEntry *child_type = ptr_type->data.pointer.child_type; | ||
| 4436 | TypeTableEntry *cmp_type = analyze_expression(g, import, context, child_type, *cmp_arg); | ||
| 4437 | TypeTableEntry *new_type = analyze_expression(g, import, context, child_type, *new_arg); | ||
| 4438 | |||
| 4439 | TypeTableEntry *success_order_type = analyze_expression(g, import, context, | ||
| 4440 | g->builtin_types.entry_mem_order_enum, *success_order_arg); | ||
| 4441 | TypeTableEntry *failure_order_type = analyze_expression(g, import, context, | ||
| 4442 | g->builtin_types.entry_mem_order_enum, *failure_order_arg); | ||
| 4443 | |||
| 4444 | if (cmp_type->id == TypeTableEntryIdInvalid || | ||
| 4445 | new_type->id == TypeTableEntryIdInvalid || | ||
| 4446 | success_order_type->id == TypeTableEntryIdInvalid || | ||
| 4447 | failure_order_type->id == TypeTableEntryIdInvalid) | ||
| 4448 | { | ||
| 4449 | return g->builtin_types.entry_invalid; | ||
| 4450 | } | ||
| 4451 | |||
| 4452 | ConstExprValue *success_order_val = &get_resolved_expr(*success_order_arg)->const_val; | ||
| 4453 | ConstExprValue *failure_order_val = &get_resolved_expr(*failure_order_arg)->const_val; | ||
| 4454 | if (!success_order_val->ok) { | ||
| 4455 | add_node_error(g, *success_order_arg, buf_sprintf("unable to evaluate constant expression")); | ||
| 4456 | return g->builtin_types.entry_invalid; | ||
| 4457 | } else if (!failure_order_val->ok) { | ||
| 4458 | add_node_error(g, *failure_order_arg, buf_sprintf("unable to evaluate constant expression")); | ||
| 4459 | return g->builtin_types.entry_invalid; | ||
| 4460 | } | ||
| 4461 | |||
| 4462 | if (success_order_val->data.x_enum.tag < AtomicOrderMonotonic) { | ||
| 4463 | add_node_error(g, *success_order_arg, | ||
| 4464 | buf_sprintf("success atomic ordering must be Monotonic or stricter")); | ||
| 4465 | return g->builtin_types.entry_invalid; | ||
| 4466 | } | ||
| 4467 | if (failure_order_val->data.x_enum.tag < AtomicOrderMonotonic) { | ||
| 4468 | add_node_error(g, *failure_order_arg, | ||
| 4469 | buf_sprintf("failure atomic ordering must be Monotonic or stricter")); | ||
| 4470 | return g->builtin_types.entry_invalid; | ||
| 4471 | } | ||
| 4472 | if (failure_order_val->data.x_enum.tag > success_order_val->data.x_enum.tag) { | ||
| 4473 | add_node_error(g, *failure_order_arg, | ||
| 4474 | buf_sprintf("failure atomic ordering must be no stricter than success")); | ||
| 4475 | return g->builtin_types.entry_invalid; | ||
| 4476 | } | ||
| 4477 | if (failure_order_val->data.x_enum.tag == AtomicOrderRelease || | ||
| 4478 | failure_order_val->data.x_enum.tag == AtomicOrderAcqRel) | ||
| 4479 | { | ||
| 4480 | add_node_error(g, *failure_order_arg, | ||
| 4481 | buf_sprintf("failure atomic ordering must not be Release or AcqRel")); | ||
| 4482 | return g->builtin_types.entry_invalid; | ||
| 4483 | } | ||
| 4484 | |||
| 4485 | return g->builtin_types.entry_bool; | ||
| 4486 | } | ||
| 4487 | |||
| 4417 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 4488 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4418 | TypeTableEntry *expected_type, AstNode *node) | 4489 | TypeTableEntry *expected_type, AstNode *node) |
| 4419 | { | 4490 | { |
| ... | @@ -4750,6 +4821,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -4750,6 +4821,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4750 | return g->builtin_types.entry_void; | 4821 | return g->builtin_types.entry_void; |
| 4751 | case BuiltinFnIdEmbedFile: | 4822 | case BuiltinFnIdEmbedFile: |
| 4752 | return analyze_embed_file(g, import, context, node); | 4823 | return analyze_embed_file(g, import, context, node); |
| 4824 | case BuiltinFnIdCmpExchange: | ||
| 4825 | return analyze_cmpxchg(g, import, context, node); | ||
| 4753 | } | 4826 | } |
| 4754 | zig_unreachable(); | 4827 | zig_unreachable(); |
| 4755 | } | 4828 | } |
src/codegen.cpp+80| ... | @@ -401,6 +401,46 @@ static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { | ... | @@ -401,6 +401,46 @@ static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { |
| 401 | return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); | 401 | return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { | ||
| 405 | switch (atomic_order) { | ||
| 406 | case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; | ||
| 407 | case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic; | ||
| 408 | case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire; | ||
| 409 | case AtomicOrderRelease: return LLVMAtomicOrderingRelease; | ||
| 410 | case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease; | ||
| 411 | case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent; | ||
| 412 | } | ||
| 413 | zig_unreachable(); | ||
| 414 | } | ||
| 415 | |||
| 416 | static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) { | ||
| 417 | assert(node->type == NodeTypeFnCallExpr); | ||
| 418 | |||
| 419 | AstNode *ptr_arg = node->data.fn_call_expr.params.at(0); | ||
| 420 | AstNode *cmp_arg = node->data.fn_call_expr.params.at(1); | ||
| 421 | AstNode *new_arg = node->data.fn_call_expr.params.at(2); | ||
| 422 | AstNode *success_order_arg = node->data.fn_call_expr.params.at(3); | ||
| 423 | AstNode *failure_order_arg = node->data.fn_call_expr.params.at(4); | ||
| 424 | |||
| 425 | LLVMValueRef ptr_val = gen_expr(g, ptr_arg); | ||
| 426 | LLVMValueRef cmp_val = gen_expr(g, cmp_arg); | ||
| 427 | LLVMValueRef new_val = gen_expr(g, new_arg); | ||
| 428 | |||
| 429 | ConstExprValue *success_order_val = &get_resolved_expr(success_order_arg)->const_val; | ||
| 430 | ConstExprValue *failure_order_val = &get_resolved_expr(failure_order_arg)->const_val; | ||
| 431 | |||
| 432 | assert(success_order_val->ok); | ||
| 433 | assert(failure_order_val->ok); | ||
| 434 | |||
| 435 | LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering((AtomicOrder)success_order_val->data.x_enum.tag); | ||
| 436 | LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag); | ||
| 437 | |||
| 438 | LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val, | ||
| 439 | success_order, failure_order, ""); | ||
| 440 | |||
| 441 | return LLVMBuildExtractValue(g->builder, result_val, 1, ""); | ||
| 442 | } | ||
| 443 | |||
| 404 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | 444 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 405 | assert(node->type == NodeTypeFnCallExpr); | 445 | assert(node->type == NodeTypeFnCallExpr); |
| 406 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 446 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| ... | @@ -546,6 +586,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -546,6 +586,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 546 | case BuiltinFnIdBreakpoint: | 586 | case BuiltinFnIdBreakpoint: |
| 547 | set_debug_source_node(g, node); | 587 | set_debug_source_node(g, node); |
| 548 | return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); | 588 | return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); |
| 589 | case BuiltinFnIdCmpExchange: | ||
| 590 | return gen_cmp_exchange(g, node); | ||
| 549 | } | 591 | } |
| 550 | zig_unreachable(); | 592 | zig_unreachable(); |
| 551 | } | 593 | } |
| ... | @@ -4052,6 +4094,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -4052,6 +4094,7 @@ static void define_builtin_types(CodeGen *g) { |
| 4052 | ZigLLVM_EnvironmentType environ_type = get_target_environ(i); | 4094 | ZigLLVM_EnvironmentType environ_type = get_target_environ(i); |
| 4053 | type_enum_field->name = buf_create_from_str(ZigLLVMGetEnvironmentTypeName(environ_type)); | 4095 | type_enum_field->name = buf_create_from_str(ZigLLVMGetEnvironmentTypeName(environ_type)); |
| 4054 | type_enum_field->value = i; | 4096 | type_enum_field->value = i; |
| 4097 | type_enum_field->type_entry = g->builtin_types.entry_void; | ||
| 4055 | 4098 | ||
| 4056 | if (environ_type == g->zig_target.env_type) { | 4099 | if (environ_type == g->zig_target.env_type) { |
| 4057 | g->target_environ_index = i; | 4100 | g->target_environ_index = i; |
| ... | @@ -4064,6 +4107,41 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -4064,6 +4107,41 @@ static void define_builtin_types(CodeGen *g) { |
| 4064 | 4107 | ||
| 4065 | g->builtin_types.entry_environ_enum = entry; | 4108 | g->builtin_types.entry_environ_enum = entry; |
| 4066 | } | 4109 | } |
| 4110 | |||
| 4111 | { | ||
| 4112 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); | ||
| 4113 | entry->deep_const = true; | ||
| 4114 | buf_init_from_str(&entry->name, "AtomicOrder"); | ||
| 4115 | uint32_t field_count = 6; | ||
| 4116 | entry->data.enumeration.field_count = field_count; | ||
| 4117 | entry->data.enumeration.fields = allocate<TypeEnumField>(field_count); | ||
| 4118 | entry->data.enumeration.fields[0].name = buf_create_from_str("Unordered"); | ||
| 4119 | entry->data.enumeration.fields[0].value = AtomicOrderUnordered; | ||
| 4120 | entry->data.enumeration.fields[0].type_entry = g->builtin_types.entry_void; | ||
| 4121 | entry->data.enumeration.fields[1].name = buf_create_from_str("Monotonic"); | ||
| 4122 | entry->data.enumeration.fields[1].value = AtomicOrderMonotonic; | ||
| 4123 | entry->data.enumeration.fields[1].type_entry = g->builtin_types.entry_void; | ||
| 4124 | entry->data.enumeration.fields[2].name = buf_create_from_str("Acquire"); | ||
| 4125 | entry->data.enumeration.fields[2].value = AtomicOrderAcquire; | ||
| 4126 | entry->data.enumeration.fields[2].type_entry = g->builtin_types.entry_void; | ||
| 4127 | entry->data.enumeration.fields[3].name = buf_create_from_str("Release"); | ||
| 4128 | entry->data.enumeration.fields[3].value = AtomicOrderRelease; | ||
| 4129 | entry->data.enumeration.fields[3].type_entry = g->builtin_types.entry_void; | ||
| 4130 | entry->data.enumeration.fields[4].name = buf_create_from_str("AcqRel"); | ||
| 4131 | entry->data.enumeration.fields[4].value = AtomicOrderAcqRel; | ||
| 4132 | entry->data.enumeration.fields[4].type_entry = g->builtin_types.entry_void; | ||
| 4133 | entry->data.enumeration.fields[5].name = buf_create_from_str("SeqCst"); | ||
| 4134 | entry->data.enumeration.fields[5].value = AtomicOrderSeqCst; | ||
| 4135 | entry->data.enumeration.fields[5].type_entry = g->builtin_types.entry_void; | ||
| 4136 | |||
| 4137 | entry->data.enumeration.complete = true; | ||
| 4138 | |||
| 4139 | TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); | ||
| 4140 | entry->data.enumeration.tag_type = tag_type_entry; | ||
| 4141 | |||
| 4142 | g->builtin_types.entry_mem_order_enum = entry; | ||
| 4143 | g->primitive_type_table.put(&entry->name, entry); | ||
| 4144 | } | ||
| 4067 | } | 4145 | } |
| 4068 | 4146 | ||
| 4069 | 4147 | ||
| ... | @@ -4162,6 +4240,8 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4162,6 +4240,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 4162 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1); | 4240 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1); |
| 4163 | create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1); | 4241 | create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1); |
| 4164 | create_builtin_fn_with_arg_count(g, BuiltinFnIdEmbedFile, "embed_file", 1); | 4242 | create_builtin_fn_with_arg_count(g, BuiltinFnIdEmbedFile, "embed_file", 1); |
| 4243 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCmpExchange, "cmpxchg", 5); | ||
| 4244 | //create_builtin_fn_with_arg_count(g, BuiltinFnIdAtomicRmw, "atomicrmw", 1); | ||
| 4165 | } | 4245 | } |
| 4166 | 4246 | ||
| 4167 | static void init(CodeGen *g, Buf *source_path) { | 4247 | static void init(CodeGen *g, Buf *source_path) { |
src/eval.cpp+1| ... | @@ -704,6 +704,7 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ | ... | @@ -704,6 +704,7 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ |
| 704 | case BuiltinFnIdCImport: | 704 | case BuiltinFnIdCImport: |
| 705 | case BuiltinFnIdErrName: | 705 | case BuiltinFnIdErrName: |
| 706 | case BuiltinFnIdEmbedFile: | 706 | case BuiltinFnIdEmbedFile: |
| 707 | case BuiltinFnIdCmpExchange: | ||
| 707 | zig_panic("TODO"); | 708 | zig_panic("TODO"); |
| 708 | case BuiltinFnIdBreakpoint: | 709 | case BuiltinFnIdBreakpoint: |
| 709 | case BuiltinFnIdInvalid: | 710 | case BuiltinFnIdInvalid: |
src/zig_llvm.cpp+25| ... | @@ -645,6 +645,31 @@ unsigned ZigLLVMGetPrefTypeAlignment(LLVMTargetDataRef TD, LLVMTypeRef Ty) { | ... | @@ -645,6 +645,31 @@ unsigned ZigLLVMGetPrefTypeAlignment(LLVMTargetDataRef TD, LLVMTypeRef Ty) { |
| 645 | return unwrap(TD)->getPrefTypeAlignment(unwrap(Ty)); | 645 | return unwrap(TD)->getPrefTypeAlignment(unwrap(Ty)); |
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | |||
| 649 | static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) { | ||
| 650 | switch (Ordering) { | ||
| 651 | case LLVMAtomicOrderingNotAtomic: return NotAtomic; | ||
| 652 | case LLVMAtomicOrderingUnordered: return Unordered; | ||
| 653 | case LLVMAtomicOrderingMonotonic: return Monotonic; | ||
| 654 | case LLVMAtomicOrderingAcquire: return Acquire; | ||
| 655 | case LLVMAtomicOrderingRelease: return Release; | ||
| 656 | case LLVMAtomicOrderingAcquireRelease: return AcquireRelease; | ||
| 657 | case LLVMAtomicOrderingSequentiallyConsistent: return SequentiallyConsistent; | ||
| 658 | } | ||
| 659 | abort(); | ||
| 660 | } | ||
| 661 | |||
| 662 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | ||
| 663 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | ||
| 664 | LLVMAtomicOrdering failure_ordering, | ||
| 665 | const char *name) | ||
| 666 | { | ||
| 667 | return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val), | ||
| 668 | mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering), | ||
| 669 | CrossThread)); | ||
| 670 | } | ||
| 671 | |||
| 672 | |||
| 648 | //------------------------------------ | 673 | //------------------------------------ |
| 649 | 674 | ||
| 650 | #include "buffer.hpp" | 675 | #include "buffer.hpp" |
src/zig_llvm.hpp+5| ... | @@ -39,6 +39,11 @@ void LLVMZigOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef | ... | @@ -39,6 +39,11 @@ void LLVMZigOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef |
| 39 | LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 39 | LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 40 | unsigned NumArgs, unsigned CC, const char *Name); | 40 | unsigned NumArgs, unsigned CC, const char *Name); |
| 41 | 41 | ||
| 42 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | ||
| 43 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | ||
| 44 | LLVMAtomicOrdering failure_ordering, | ||
| 45 | const char *name); | ||
| 46 | |||
| 42 | // 0 is return value, 1 is first arg | 47 | // 0 is return value, 1 is first arg |
| 43 | void LLVMZigAddNonNullAttr(LLVMValueRef fn, unsigned i); | 48 | void LLVMZigAddNonNullAttr(LLVMValueRef fn, unsigned i); |
| 44 | 49 |
test/run_tests.cpp+12| ... | @@ -1295,8 +1295,20 @@ fn foo() { | ... | @@ -1295,8 +1295,20 @@ fn foo() { |
| 1295 | #static_eval_enable(false) | 1295 | #static_eval_enable(false) |
| 1296 | fn bar() -> i32 { 2 } | 1296 | fn bar() -> i32 { 2 } |
| 1297 | )SOURCE", 1, ".tmp_source.zig:3:15: error: unable to infer expression type"); | 1297 | )SOURCE", 1, ".tmp_source.zig:3:15: error: unable to infer expression type"); |
| 1298 | |||
| 1299 | add_compile_fail_case("atomic orderings of cmpxchg", R"SOURCE( | ||
| 1300 | fn f() { | ||
| 1301 | var x: i32 = 1234; | ||
| 1302 | while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} | ||
| 1303 | while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} | ||
| 1304 | } | ||
| 1305 | )SOURCE", 2, | ||
| 1306 | ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success", | ||
| 1307 | ".tmp_source.zig:5:49: error: success atomic ordering must be Monotonic or stricter"); | ||
| 1298 | } | 1308 | } |
| 1299 | 1309 | ||
| 1310 | ////////////////////////////////////////////////////////////////////////////// | ||
| 1311 | |||
| 1300 | static void add_debug_safety_test_cases(void) { | 1312 | static void add_debug_safety_test_cases(void) { |
| 1301 | add_debug_safety_case("out of bounds slice access", R"SOURCE( | 1313 | add_debug_safety_case("out of bounds slice access", R"SOURCE( |
| 1302 | pub fn main(args: [][]u8) -> %void { | 1314 | pub fn main(args: [][]u8) -> %void { |
test/self_hosted.zig+7| ... | @@ -1442,3 +1442,10 @@ fn assign_to_if_var_ptr() { | ... | @@ -1442,3 +1442,10 @@ fn assign_to_if_var_ptr() { |
| 1442 | 1442 | ||
| 1443 | assert(??maybe_bool == false); | 1443 | assert(??maybe_bool == false); |
| 1444 | } | 1444 | } |
| 1445 | |||
| 1446 | #attribute("test") | ||
| 1447 | fn cmpxchg() { | ||
| 1448 | var x: i32 = 1234; | ||
| 1449 | while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} | ||
| 1450 | assert(x == 5678); | ||
| 1451 | } |