diff --git a/src/all_types.hpp b/src/all_types.hpp index 14b99228ca..149b7f4647 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3567,6 +3567,8 @@ struct IrInstGenCmpxchg { IrInstGen *cmp_value; IrInstGen *new_value; IrInstGen *result_loc; + // non null if operand needs widening and truncating + ZigType *actual_type; bool is_weak; }; @@ -4199,6 +4201,8 @@ struct IrInstGenAtomicRmw { IrInstGen *ptr; IrInstGen *operand; + // non null if operand needs widening and truncating + ZigType *actual_type; AtomicRmwOp op; AtomicOrder ordering; }; @@ -4215,6 +4219,8 @@ struct IrInstGenAtomicLoad { IrInstGen base; IrInstGen *ptr; + // non null if operand needs widening and truncating + ZigType *actual_type; AtomicOrder ordering; }; @@ -4232,6 +4238,8 @@ struct IrInstGenAtomicStore { IrInstGen *ptr; IrInstGen *value; + // non null if operand needs widening and truncating + ZigType *actual_type; AtomicOrder ordering; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 7238d5041b..cfb3de292a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5225,12 +5225,12 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); ZigType *operand_type = instruction->new_value->value->type; - if (operand_type->id == ZigTypeIdBool) { - // treat bool as u8 + if (instruction->actual_type != nullptr) { + // operand needs widening and truncating ptr_val = LLVMBuildBitCast(g->builder, ptr_val, - LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), ""); - cmp_val = LLVMConstZExt(cmp_val, g->builtin_types.entry_u8->llvm_type); - new_val = LLVMConstZExt(new_val, g->builtin_types.entry_u8->llvm_type); + LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), ""); + cmp_val = LLVMConstZExt(cmp_val, get_llvm_type(g, instruction->actual_type)); + new_val = LLVMConstZExt(new_val, get_llvm_type(g, instruction->actual_type)); } LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order); @@ -5245,8 +5245,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I if (!handle_is_ptr(g, optional_type)) { LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (operand_type->id == ZigTypeIdBool) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, ""); + if (instruction->actual_type != nullptr) { + payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); } LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); @@ -5262,8 +5262,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I ir_assert(type_has_bits(g, child_type), &instruction->base); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (operand_type->id == ZigTypeIdBool) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, ""); + if (instruction->actual_type != nullptr) { + payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); } LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); @@ -5842,14 +5842,14 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - if (operand_type->id == ZigTypeIdBool) { - // treat bool as u8 + if (instruction->actual_type != nullptr) { + // operand needs widening and truncating LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), ""); - LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_u8->llvm_type, ""); + LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), ""); + LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, get_llvm_type(g, instruction->actual_type), ""); LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, g->is_single_threaded); - return LLVMBuildTrunc(g->builder, uncasted_result, g->builtin_types.entry_bool->llvm_type, ""); + return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); } if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) { @@ -5872,13 +5872,13 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type; - if (operand_type->id == ZigTypeIdBool) { - // treat bool as u8 + if (instruction->actual_type != nullptr) { + // operand needs widening and truncating ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), ""); + LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), ""); LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, ""); LLVMSetOrdering(load_inst, ordering); - return LLVMBuildTrunc(g->builder, load_inst, g->builtin_types.entry_bool->llvm_type, ""); + return LLVMBuildTrunc(g->builder, load_inst, get_llvm_type(g, operand_type), ""); } LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, ""); LLVMSetOrdering(load_inst, ordering); @@ -5892,12 +5892,11 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); LLVMValueRef value = ir_llvm_value(g, instruction->value); - ZigType *operand_type = instruction->value->value->type; - if (operand_type->id == ZigTypeIdBool) { - // treat bool as u8 + if (instruction->actual_type != nullptr) { + // operand needs widening and truncating ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), ""); - value = LLVMConstZExt(value, g->builtin_types.entry_u8->llvm_type); + LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), ""); + value = LLVMConstZExt(value, get_llvm_type(g, instruction->actual_type)); } LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type); LLVMSetOrdering(store_inst, ordering); diff --git a/src/ir.cpp b/src/ir.cpp index cad1d382e1..9465be8b0b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -227,7 +227,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name static void ir_assert(bool ok, IrInst* source_instruction); static void ir_assert_gen(bool ok, IrInstGen *source_instruction); static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *var); -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op); +static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type); static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc); static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); @@ -3406,7 +3406,7 @@ static IrInstSrc *ir_build_cmpxchg_src(IrBuilderSrc *irb, Scope *scope, AstNode static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type, IrInstGen *ptr, IrInstGen *cmp_value, IrInstGen *new_value, - AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc) + AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc, ZigType *actual_type) { IrInstGenCmpxchg *instruction = ir_build_inst_gen(&ira->new_irb, source_instruction->scope, source_instruction->source_node); @@ -3418,6 +3418,7 @@ static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instructio instruction->failure_order = failure_order; instruction->is_weak = is_weak; instruction->result_loc = result_loc; + instruction->actual_type = actual_type; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(cmp_value, ira->new_irb.current_basic_block); @@ -4554,7 +4555,7 @@ static IrInstSrc *ir_build_atomic_rmw_src(IrBuilderSrc *irb, Scope *scope, AstNo } static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr, - IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type) + IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type) { IrInstGenAtomicRmw *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); instruction->base.value->type = operand_type; @@ -4562,6 +4563,7 @@ static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr, instruction->op = op; instruction->operand = operand; instruction->ordering = ordering; + instruction->actual_type = actual_type; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(operand, ira->new_irb.current_basic_block); @@ -4585,13 +4587,14 @@ static IrInstSrc *ir_build_atomic_load_src(IrBuilderSrc *irb, Scope *scope, AstN } static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr, - IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type) + IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type) { IrInstGenAtomicLoad *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); instruction->base.value->type = operand_type; instruction->ptr = ptr; instruction->ordering = ordering; + instruction->actual_type = actual_type; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); @@ -4616,13 +4619,14 @@ static IrInstSrc *ir_build_atomic_store_src(IrBuilderSrc *irb, Scope *scope, Ast } static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr, - IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering) + IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering, ZigType *actual_type) { IrInstGenAtomicStore *instruction = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); instruction->ptr = ptr; instruction->value = value; instruction->ordering = ordering; + instruction->actual_type = actual_type; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(value, ira->new_irb.current_basic_block); @@ -25121,7 +25125,8 @@ static IrInstGen *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstSrcEmb } static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxchg *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); + ZigType *actual_type; + ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child, &actual_type); if (type_is_invalid(operand_type)) return ira->codegen->invalid_inst_gen; @@ -25213,7 +25218,7 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch return ir_build_cmpxchg_gen(ira, &instruction->base.base, result_type, casted_ptr, casted_cmp_value, casted_new_value, - success_order, failure_order, instruction->is_weak, result_loc); + success_order, failure_order, instruction->is_weak, result_loc, actual_type); } static IrInstGen *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstSrcFence *instruction) { @@ -28305,17 +28310,15 @@ static IrInstGen *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstSrcTagTy } } -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { +static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type) { ZigType *operand_type = ir_resolve_type(ira, op); if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; - if (operand_type->id == ZigTypeIdInt) { - if (operand_type->data.integral.bit_count < 8) { - ir_add_error(ira, &op->base, - buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type", - operand_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; + *actual_type = nullptr; + if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { + if (operand_type->id == ZigTypeIdEnum) { + operand_type = operand_type->data.enumeration.tag_int_type; } uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); if (operand_type->data.integral.bit_count > max_atomic_bits) { @@ -28324,30 +28327,22 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { max_atomic_bits, operand_type->data.integral.bit_count)); return ira->codegen->builtin_types.entry_invalid; } - if (!is_power_of_2(operand_type->data.integral.bit_count)) { - ir_add_error(ira, &op->base, - buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (operand_type->id == ZigTypeIdEnum) { - ZigType *int_type = operand_type->data.enumeration.tag_int_type; - if (int_type->data.integral.bit_count < 8) { - ir_add_error(ira, &op->base, - buf_sprintf("expected enum tag type 8 bits or larger, found %" PRIu32 "-bit tag type", - int_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - if (int_type->data.integral.bit_count > max_atomic_bits) { - ir_add_error(ira, &op->base, - buf_sprintf("expected %" PRIu32 "-bit enum tag type or smaller, found %" PRIu32 "-bit tag type", - max_atomic_bits, int_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - if (!is_power_of_2(int_type->data.integral.bit_count)) { - ir_add_error(ira, &op->base, - buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; + auto bit_count = operand_type->data.integral.bit_count; + bool is_signed = operand_type->data.integral.is_signed; + if (bit_count < 2 || !is_power_of_2(bit_count)) { + if (bit_count < 8) { + *actual_type = get_int_type(ira->codegen, is_signed, 8); + } else if (bit_count < 16) { + *actual_type = get_int_type(ira->codegen, is_signed, 16); + } else if (bit_count < 32) { + *actual_type = get_int_type(ira->codegen, is_signed, 32); + } else if (bit_count < 64) { + *actual_type = get_int_type(ira->codegen, is_signed, 64); + } else if (bit_count < 128) { + *actual_type = get_int_type(ira->codegen, is_signed, 128); + } else { + zig_unreachable(); + } } } else if (operand_type->id == ZigTypeIdFloat) { uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); @@ -28359,6 +28354,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { } } else if (operand_type->id == ZigTypeIdBool) { // will be treated as u8 + *actual_type = ira->codegen->builtin_types.entry_u8; } else { Error err; ZigType *operand_ptr_type; @@ -28376,7 +28372,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { } static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAtomicRmw *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); + ZigType *actual_type; + ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type); if (type_is_invalid(operand_type)) return ira->codegen->invalid_inst_gen; @@ -28434,11 +28431,12 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto } return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op, - ordering, operand_type); + ordering, operand_type, actual_type); } static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAtomicLoad *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); + ZigType *actual_type; + ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type); if (type_is_invalid(operand_type)) return ira->codegen->invalid_inst_gen; @@ -28468,11 +28466,12 @@ static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAt return result; } - return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type); + return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type, actual_type); } static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcAtomicStore *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); + ZigType *actual_type; + ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type); if (type_is_invalid(operand_type)) return ira->codegen->invalid_inst_gen; @@ -28511,7 +28510,7 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA return result; } - return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering); + return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering, actual_type); } static IrInstGen *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstSrcSaveErrRetAddr *instruction) {