aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp1335
1 files changed, 936 insertions, 399 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a58832f983..539356ef2f 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -17,6 +17,7 @@
#include "os.hpp"
#include "translate_c.hpp"
#include "target.hpp"
+#include "util.hpp"
#include "zig_llvm.h"
#include <stdio.h>
@@ -59,6 +60,33 @@ PackageTableEntry *new_anonymous_package(void) {
return new_package("", "");
}
+static const char *symbols_that_llvm_depends_on[] = {
+ "memcpy",
+ "memset",
+ "sqrt",
+ "powi",
+ "sin",
+ "cos",
+ "pow",
+ "exp",
+ "exp2",
+ "log",
+ "log10",
+ "log2",
+ "fma",
+ "fabs",
+ "minnum",
+ "maxnum",
+ "copysign",
+ "floor",
+ "ceil",
+ "trunc",
+ "rint",
+ "nearbyint",
+ "round",
+ // TODO probably all of compiler-rt needs to go here
+};
+
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
Buf *zig_lib_dir)
{
@@ -88,10 +116,15 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->exported_symbol_names.init(8);
g->external_prototypes.init(8);
g->string_literals_table.init(16);
+ g->type_info_cache.init(32);
g->is_test_build = false;
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
+ for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
+ g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
+ }
+
if (root_src_path) {
Buf *src_basename = buf_alloc();
Buf *src_dir = buf_alloc();
@@ -325,13 +358,6 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
return addLLVMAttr(arg_val, param_index + 1, attr_name);
}
-static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
- unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
- assert(kind_id != 0);
- LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
- LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
-}
-
static bool is_symbol_available(CodeGen *g, Buf *name) {
return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
}
@@ -512,7 +538,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
}
if (fn_table_entry->body_node != nullptr) {
- bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;
+ bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
+ g->build_mode != BuildModeSmallRelease &&
+ !fn_table_entry->def_scope->safety_off;
if (want_fn_safety) {
if (g->libc_link_lib != nullptr) {
addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
@@ -578,11 +606,6 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (param_type->id == TypeTableEntryIdPointer) {
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
}
- // Note: byval is disabled on windows due to an LLVM bug:
- // https://github.com/zig-lang/zig/issues/536
- if (is_byval && g->zig_target.os != OsWindows) {
- addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
- }
}
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
@@ -652,6 +675,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
}
case ScopeIdDeferExpr:
case ScopeIdLoop:
+ case ScopeIdSuspend:
case ScopeIdCompTime:
case ScopeIdCoroPrelude:
return get_di_scope(g, scope->parent);
@@ -717,12 +741,12 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
return fn_val;
}
-static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
+static LLVMValueRef get_float_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
assert(type_entry->id == TypeTableEntryIdFloat);
ZigLLVMFnKey key = {};
key.id = fn_id;
- key.data.floor_ceil.bit_count = (uint32_t)type_entry->data.floating.bit_count;
+ key.data.floating.bit_count = (uint32_t)type_entry->data.floating.bit_count;
auto existing_entry = g->llvm_fn_table.maybe_get(key);
if (existing_entry)
@@ -733,6 +757,8 @@ static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, Zi
name = "floor";
} else if (fn_id == ZigLLVMFnIdCeil) {
name = "ceil";
+ } else if (fn_id == ZigLLVMFnIdSqrt) {
+ name = "sqrt";
} else {
zig_unreachable();
}
@@ -815,7 +841,7 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
}
static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
- if (g->build_mode == BuildModeFastRelease)
+ if (g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease)
return false;
// TODO memoize
@@ -859,7 +885,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("exact division produced remainder");
case PanicMsgIdSliceWidenRemainder:
return buf_create_from_str("slice widening size mismatch");
- case PanicMsgIdUnwrapMaybeFail:
+ case PanicMsgIdUnwrapOptionalFail:
return buf_create_from_str("attempt to unwrap null");
case PanicMsgIdUnreachable:
return buf_create_from_str("reached unreachable code");
@@ -869,6 +895,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("incorrect alignment");
case PanicMsgIdBadUnionField:
return buf_create_from_str("access of inactive union field");
+ case PanicMsgIdBadEnumValue:
+ return buf_create_from_str("invalid enum value");
+ case PanicMsgIdFloatToInt:
+ return buf_create_from_str("integer part of floating point value out of bounds");
}
zig_unreachable();
}
@@ -887,7 +917,8 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
assert(val->global_refs->llvm_global);
}
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
}
@@ -932,6 +963,53 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
return g->memcpy_fn_val;
}
+static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
+ if (g->stacksave_fn_val)
+ return g->stacksave_fn_val;
+
+ // declare i8* @llvm.stacksave()
+
+ LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
+ g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
+ assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
+
+ return g->stacksave_fn_val;
+}
+
+static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
+ if (g->stackrestore_fn_val)
+ return g->stackrestore_fn_val;
+
+ // declare void @llvm.stackrestore(i8* %ptr)
+
+ LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
+ LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), &param_type, 1, false);
+ g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
+ assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
+
+ return g->stackrestore_fn_val;
+}
+
+static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
+ if (g->write_register_fn_val)
+ return g->write_register_fn_val;
+
+ // declare void @llvm.write_register.i64(metadata, i64 @value)
+ // !0 = !{!"sp\00"}
+
+ LLVMTypeRef param_types[] = {
+ LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
+ LLVMIntType(g->pointer_size_bytes * 8),
+ };
+
+ LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
+ Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
+ g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
+ assert(LLVMGetIntrinsicID(g->write_register_fn_val));
+
+ return g->write_register_fn_val;
+}
+
static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
if (g->coro_destroy_fn_val)
return g->coro_destroy_fn_val;
@@ -1408,7 +1486,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMValueRef full_buf_ptr = LLVMConstInBoundsGEP(global_array, full_buf_ptr_indices, 2);
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
LLVMValueRef global_slice_fields[] = {
full_buf_ptr,
@@ -1626,7 +1705,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, T
return trunc_val;
}
LLVMValueRef orig_val;
- if (actual_type->data.integral.is_signed) {
+ if (wanted_type->data.integral.is_signed) {
orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");
} else {
orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
@@ -1900,7 +1979,7 @@ static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, TypeTableEntry *type
if (type_entry->id == TypeTableEntryIdInt)
return val;
- LLVMValueRef floor_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdFloor);
+ LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor);
return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");
}
@@ -1908,7 +1987,7 @@ static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, TypeTableEntry *type_
if (type_entry->id == TypeTableEntryIdInt)
return val;
- LLVMValueRef ceil_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdCeil);
+ LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil);
return LLVMBuildCall(g->builder, ceil_fn, &val, 1, "");
}
@@ -2159,9 +2238,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrInstruction *op2 = bin_op_instruction->op2;
assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
- op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
- op_id == IrBinOpBitShiftRightExact ||
- (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet));
+ op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
+ op_id == IrBinOpBitShiftRightExact ||
+ (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet) ||
+ (op1->value.type->id == TypeTableEntryIdPointer &&
+ (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
+ op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
+ );
TypeTableEntry *type_entry = op1->value.type;
bool want_runtime_safety = bin_op_instruction->safety_check_on &&
@@ -2169,6 +2252,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
LLVMValueRef op1_value = ir_llvm_value(g, op1);
LLVMValueRef op2_value = ir_llvm_value(g, op2);
+
+
switch (op_id) {
case IrBinOpInvalid:
case IrBinOpArrayCat:
@@ -2193,12 +2278,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
} else if (type_entry->id == TypeTableEntryIdInt) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
- } else if (type_entry->id == TypeTableEntryIdEnum) {
- LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
- return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
- } else if (type_entry->id == TypeTableEntryIdErrorSet ||
- type_entry->id == TypeTableEntryIdPointer ||
- type_entry->id == TypeTableEntryIdBool)
+ } else if (type_entry->id == TypeTableEntryIdEnum ||
+ type_entry->id == TypeTableEntryIdErrorSet ||
+ type_entry->id == TypeTableEntryIdBool ||
+ get_codegen_ptr_type(type_entry) != nullptr)
{
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
@@ -2207,7 +2290,11 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
}
case IrBinOpAdd:
case IrBinOpAddWrap:
- if (type_entry->id == TypeTableEntryIdFloat) {
+ if (type_entry->id == TypeTableEntryIdPointer) {
+ assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
+ // TODO runtime safety
+ return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdInt) {
@@ -2270,7 +2357,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
}
case IrBinOpSub:
case IrBinOpSubWrap:
- if (type_entry->id == TypeTableEntryIdFloat) {
+ if (type_entry->id == TypeTableEntryIdPointer) {
+ assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
+ // TODO runtime safety
+ LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
+ return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdInt) {
@@ -2460,7 +2552,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
assert(wanted_type->data.structure.is_slice);
assert(actual_type->id == TypeTableEntryIdArray);
- TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
@@ -2486,15 +2578,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
} else {
return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
}
- case CastOpFloatToInt:
+ case CastOpFloatToInt: {
assert(wanted_type->id == TypeTableEntryIdInt);
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base));
+
+ bool want_safety = ir_want_runtime_safety(g, &cast_instruction->base);
+
+ LLVMValueRef result;
if (wanted_type->data.integral.is_signed) {
- return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
+ result = LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
} else {
- return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
+ result = LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
}
+ if (want_safety) {
+ LLVMValueRef back_to_float;
+ if (wanted_type->data.integral.is_signed) {
+ back_to_float = LLVMBuildSIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
+ } else {
+ back_to_float = LLVMBuildUIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
+ }
+ LLVMValueRef difference = LLVMBuildFSub(g->builder, expr_val, back_to_float, "");
+ LLVMValueRef one_pos = LLVMConstReal(LLVMTypeOf(expr_val), 1.0f);
+ LLVMValueRef one_neg = LLVMConstReal(LLVMTypeOf(expr_val), -1.0f);
+ LLVMValueRef ok_bit_pos = LLVMBuildFCmp(g->builder, LLVMRealOLT, difference, one_pos, "");
+ LLVMValueRef ok_bit_neg = LLVMBuildFCmp(g->builder, LLVMRealOGT, difference, one_neg, "");
+ LLVMValueRef ok_bit = LLVMBuildAnd(g->builder, ok_bit_pos, ok_bit_neg, "");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckOk");
+ LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckFail");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, bad_block);
+ LLVMPositionBuilderAtEnd(g->builder, bad_block);
+ gen_safety_crash(g, PanicMsgIdFloatToInt);
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+ return result;
+ }
case CastOpBoolToInt:
assert(wanted_type->id == TypeTableEntryIdInt);
assert(actual_type->id == TypeTableEntryIdBool);
@@ -2504,6 +2622,31 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
}
return expr_val;
+ case CastOpBitCast:
+ return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpPtrOfArrayToSlice: {
+ assert(cast_instruction->tmp_ptr);
+ assert(actual_type->id == TypeTableEntryIdPointer);
+ TypeTableEntry *array_type = actual_type->data.pointer.child_type;
+ assert(array_type->id == TypeTableEntryIdArray);
+
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ slice_ptr_index, "");
+ LLVMValueRef indices[] = {
+ LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+ LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
+ };
+ LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
+ gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
+
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ slice_len_index, "");
+ LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+ array_type->data.array.len, false);
+ gen_store_untyped(g, len_value, len_field_ptr, 0, false);
+
+ return cast_instruction->tmp_ptr;
+ }
}
zig_unreachable();
}
@@ -2559,8 +2702,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
- return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
+ LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
instruction->target->value.type, tag_int_type, target_val);
+
+ if (ir_want_runtime_safety(g, &instruction->base)) {
+ LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
+ LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
+ size_t field_count = wanted_type->data.enumeration.src_field_count;
+ LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
+ for (size_t field_i = 0; field_i < field_count; field_i += 1) {
+ LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
+ &wanted_type->data.enumeration.fields[field_i].value);
+ LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
+ }
+ LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
+ gen_safety_crash(g, PanicMsgIdBadEnumValue);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_value_block);
+ }
+ return tag_int_value;
}
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
@@ -2639,7 +2799,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
switch (op_id) {
case IrUnOpInvalid:
- case IrUnOpMaybe:
+ case IrUnOpOptional:
case IrUnOpDereference:
zig_unreachable();
case IrUnOpNegation:
@@ -2717,7 +2877,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
if (have_init_expr) {
assert(var->value->type == init_value->value.type);
TypeTableEntry *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
- var->align_bytes, 0, 0);
+ PtrLenSingle, var->align_bytes, 0, 0);
gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
} else {
bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
@@ -2814,7 +2974,13 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on;
- if (array_type->id == TypeTableEntryIdArray) {
+ if (array_type->id == TypeTableEntryIdArray ||
+ (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
+ {
+ if (array_type->id == TypeTableEntryIdPointer) {
+ assert(array_type->data.pointer.child_type->id == TypeTableEntryIdArray);
+ array_type = array_type->data.pointer.child_type;
+ }
if (safety_check_on) {
LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
array_type->data.array.len, false);
@@ -2855,18 +3021,26 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
} else if (array_type->id == TypeTableEntryIdStruct) {
assert(array_type->data.structure.is_slice);
+ if (!type_has_bits(instruction->base.value.type)) {
+ if (safety_check_on) {
+ assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind);
+ add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, array_ptr);
+ }
+ return nullptr;
+ }
+
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
if (safety_check_on) {
- size_t len_index = array_type->data.structure.fields[1].gen_index;
+ size_t len_index = array_type->data.structure.fields[slice_len_index].gen_index;
assert(len_index != SIZE_MAX);
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, "");
LLVMValueRef len = gen_load_untyped(g, len_ptr, 0, false, "");
add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
}
- size_t ptr_index = array_type->data.structure.fields[0].gen_index;
+ size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
assert(ptr_index != SIZE_MAX);
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, "");
LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, "");
@@ -2895,6 +3069,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
return 1 + get_async_allocator_arg_index(g, fn_type_id);
}
+
+static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
+
+ LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
+ LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
+
+ LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
+ LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
+ LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
+ LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
+ return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
+}
+
+static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
+ LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
+
+ if (g->sp_md_node == nullptr) {
+ Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
+ LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
+ g->sp_md_node = LLVMMDNode(&str_node, 1);
+ }
+
+ LLVMValueRef params[] = {
+ g->sp_md_node,
+ aligned_end_addr,
+ };
+
+ LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
+}
+
static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
LLVMValueRef fn_val;
TypeTableEntry *fn_type;
@@ -2961,18 +3167,24 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
- LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
- gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
+ LLVMValueRef result;
+
+ if (instruction->new_stack == nullptr) {
+ result = ZigLLVMBuildCall(g->builder, fn_val,
+ gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
+ } else {
+ LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
+ LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
- for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
- FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
- // Note: byval is disabled on windows due to an LLVM bug:
- // https://github.com/zig-lang/zig/issues/536
- if (gen_info->is_byval && g->zig_target.os != OsWindows) {
- addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
- }
+ LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
+ LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
+ gen_set_stack_pointer(g, new_stack_addr);
+ result = ZigLLVMBuildCall(g->builder, fn_val,
+ gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
+ LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
}
+
if (instruction->is_async) {
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
LLVMBuildStore(g->builder, result, payload_ptr);
@@ -2985,6 +3197,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
return nullptr;
} else if (first_arg_ret) {
return instruction->tmp_ptr;
+ } else if (handle_is_ptr(src_return_type)) {
+ auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);
+ LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr));
+ return instruction->tmp_ptr;
} else {
return result;
}
@@ -3185,7 +3401,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
- assert(maybe_type->id == TypeTableEntryIdMaybe);
+ assert(maybe_type->id == TypeTableEntryIdOptional);
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
if (child_type->zero_bits) {
return maybe_handle;
@@ -3207,23 +3423,23 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
}
static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
- IrInstructionUnwrapMaybe *instruction)
+ IrInstructionUnwrapOptional *instruction)
{
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
- assert(maybe_type->id == TypeTableEntryIdMaybe);
+ assert(maybe_type->id == TypeTableEntryIdOptional);
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail);
+ gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
@@ -3243,14 +3459,24 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
ZigLLVMFnKey key = {};
const char *fn_name;
+ uint32_t n_args;
if (fn_id == BuiltinFnIdCtz) {
fn_name = "cttz";
+ n_args = 2;
key.id = ZigLLVMFnIdCtz;
key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;
- } else {
+ } else if (fn_id == BuiltinFnIdClz) {
fn_name = "ctlz";
+ n_args = 2;
key.id = ZigLLVMFnIdClz;
key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;
+ } else if (fn_id == BuiltinFnIdPopCount) {
+ fn_name = "ctpop";
+ n_args = 1;
+ key.id = ZigLLVMFnIdPopCount;
+ key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
+ } else {
+ zig_unreachable();
}
auto existing_entry = g->llvm_fn_table.maybe_get(key);
@@ -3263,7 +3489,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
int_type->type_ref,
LLVMInt1Type(),
};
- LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);
+ LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, n_args, false);
LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
assert(LLVMGetIntrinsicID(fn_val));
@@ -3296,6 +3522,14 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
}
+static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
+ TypeTableEntry *int_type = instruction->value->value.type;
+ LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
+ LLVMValueRef operand = ir_llvm_value(g, instruction->value);
+ LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
+ return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
+}
+
static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
@@ -3366,34 +3600,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
}
+static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) {
+ assert(enum_type->id == TypeTableEntryIdEnum);
+ if (enum_type->data.enumeration.name_function)
+ return enum_type->data.enumeration.name_function;
+
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
+ TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type);
+ TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
+
+ LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0),
+ &tag_int_type->type_ref, 1, false);
+
+ Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
+ LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+ LLVMSetLinkage(fn_val, LLVMInternalLinkage);
+ LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
+ addLLVMFnAttr(fn_val, "nounwind");
+ add_uwtable_attr(g, fn_val);
+ if (g->build_mode == BuildModeDebug) {
+ ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
+ ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
+ }
+
+ LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
+ LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
+ FnTableEntry *prev_cur_fn = g->cur_fn;
+ LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
+
+ LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
+ LLVMPositionBuilderAtEnd(g->builder, entry_block);
+ ZigLLVMClearCurrentDebugLocation(g->builder);
+ g->cur_fn = nullptr;
+ g->cur_fn_val = fn_val;
+
+ size_t field_count = enum_type->data.enumeration.src_field_count;
+ LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
+ LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0);
+ LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
+
+
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ LLVMValueRef array_ptr_indices[] = {
+ LLVMConstNull(usize->type_ref),
+ LLVMConstNull(usize->type_ref),
+ };
+
+ for (size_t field_i = 0; field_i < field_count; field_i += 1) {
+ Buf *name = enum_type->data.enumeration.fields[field_i].name;
+ LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
+ LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
+ LLVMSetInitializer(str_global, str_init);
+ LLVMSetLinkage(str_global, LLVMPrivateLinkage);
+ LLVMSetGlobalConstant(str_global, true);
+ LLVMSetUnnamedAddr(str_global, true);
+ LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
+
+ LLVMValueRef fields[] = {
+ LLVMConstGEP(str_global, array_ptr_indices, 2),
+ LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
+ };
+ LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2);
+
+ LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
+ LLVMSetInitializer(slice_global, slice_init_value);
+ LLVMSetLinkage(slice_global, LLVMPrivateLinkage);
+ LLVMSetGlobalConstant(slice_global, true);
+ LLVMSetUnnamedAddr(slice_global, true);
+ LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value)));
+
+ LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name");
+ LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
+ &enum_type->data.enumeration.fields[field_i].value);
+ LLVMAddCase(switch_instr, this_tag_int_value, return_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, return_block);
+ LLVMBuildRet(g->builder, slice_global);
+ }
+
+ LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
+ if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
+ gen_safety_crash(g, PanicMsgIdBadEnumValue);
+ } else {
+ LLVMBuildUnreachable(g->builder);
+ }
+
+ g->cur_fn = prev_cur_fn;
+ g->cur_fn_val = prev_cur_fn_val;
+ LLVMPositionBuilderAtEnd(g->builder, prev_block);
+ LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+
+ enum_type->data.enumeration.name_function = fn_val;
+ return fn_val;
+}
+
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
IrInstructionTagName *instruction)
{
TypeTableEntry *enum_type = instruction->target->value.type;
assert(enum_type->id == TypeTableEntryIdEnum);
- assert(enum_type->data.enumeration.generate_name_table);
- TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
- LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
- if (ir_want_runtime_safety(g, &instruction->base)) {
- size_t field_count = enum_type->data.enumeration.src_field_count;
-
- // if the field_count can't fit in the bits of the enum_type, then it can't possibly
- // be the wrong value
- BigInt field_bi;
- bigint_init_unsigned(&field_bi, field_count);
- if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
- LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
- add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
- }
- }
+ LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
- LLVMValueRef indices[] = {
- LLVMConstNull(g->builtin_types.entry_usize->type_ref),
- gen_widen_or_shorten(g, false, tag_int_type,
- g->builtin_types.entry_usize, enum_tag_value),
- };
- return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
+ LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
+ return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
+ get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
}
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
@@ -3443,17 +3755,17 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
} else if (target_type->id == TypeTableEntryIdFn) {
align_bytes = target_type->data.fn.fn_type_id.alignment;
ptr_val = target_val;
- } else if (target_type->id == TypeTableEntryIdMaybe &&
+ } else if (target_type->id == TypeTableEntryIdOptional &&
target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
{
align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
ptr_val = target_val;
- } else if (target_type->id == TypeTableEntryIdMaybe &&
+ } else if (target_type->id == TypeTableEntryIdOptional &&
target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
{
align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
ptr_val = target_val;
- } else if (target_type->id == TypeTableEntryIdMaybe &&
+ } else if (target_type->id == TypeTableEntryIdOptional &&
target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
{
zig_panic("TODO audit this function");
@@ -3552,9 +3864,30 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
- success_order, failure_order);
+ success_order, failure_order, instruction->is_weak);
+
+ TypeTableEntry *maybe_type = instruction->base.value.type;
+ assert(maybe_type->id == TypeTableEntryIdOptional);
+ TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
- return LLVMBuildExtractValue(g->builder, result_val, 1, "");
+ if (type_is_codegen_pointer(child_type)) {
+ LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
+ LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
+ return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
+ }
+
+ assert(instruction->tmp_ptr != nullptr);
+ assert(type_has_bits(instruction->type));
+
+ LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
+ gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
+
+ LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
+ LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
+ gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
+ return instruction->tmp_ptr;
}
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
@@ -3654,7 +3987,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
- if (array_type->id == TypeTableEntryIdArray) {
+ if (array_type->id == TypeTableEntryIdArray ||
+ (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
+ {
+ if (array_type->id == TypeTableEntryIdPointer) {
+ array_type = array_type->data.pointer.child_type;
+ }
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
LLVMValueRef end_val;
if (instruction->end) {
@@ -3662,7 +4000,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
} else {
end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
}
-
if (want_runtime_safety) {
add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
if (instruction->end) {
@@ -3695,6 +4032,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
return tmp_struct_ptr;
} else if (array_type->id == TypeTableEntryIdPointer) {
+ assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
@@ -3702,11 +4040,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
}
- LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
- LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
- gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
+ if (type_has_bits(array_type)) {
+ size_t gen_ptr_index = instruction->base.value.type->data.structure.fields[slice_ptr_index].gen_index;
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
+ LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
+ gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
+ }
- LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
+ size_t gen_len_index = instruction->base.value.type->data.structure.fields[slice_len_index].gen_index;
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
@@ -3804,6 +4146,26 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
return LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
}
+static LLVMValueRef get_handle_fn_val(CodeGen *g) {
+ if (g->coro_frame_fn_val)
+ return g->coro_frame_fn_val;
+
+ LLVMTypeRef fn_type = LLVMFunctionType( LLVMPointerType(LLVMInt8Type(), 0)
+ , nullptr, 0, false);
+ Buf *name = buf_sprintf("llvm.coro.frame");
+ g->coro_frame_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
+ assert(LLVMGetIntrinsicID(g->coro_frame_fn_val));
+
+ return g->coro_frame_fn_val;
+}
+
+static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
+ IrInstructionHandle *instruction)
+{
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_promise->type_ref);
+ return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
+}
+
static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
TypeTableEntry *int_type = instruction->result_ptr_type;
assert(int_type->id == TypeTableEntryIdInt);
@@ -3939,10 +4301,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
}
}
-static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
+static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) {
TypeTableEntry *wanted_type = instruction->base.value.type;
- assert(wanted_type->id == TypeTableEntryIdMaybe);
+ assert(wanted_type->id == TypeTableEntryIdOptional);
TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
@@ -4049,7 +4411,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
- false, false, field_align_bytes,
+ false, false, PtrLenSingle, field_align_bytes,
(uint32_t)type_struct_field->packed_bits_offset, (uint32_t)type_struct_field->unaligned_bit_count);
gen_assign_raw(g, field_ptr, ptr_type, value);
@@ -4065,7 +4427,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
- false, false, field_align_bytes,
+ false, false, PtrLenSingle, field_align_bytes,
0, 0);
LLVMValueRef uncasted_union_ptr;
@@ -4312,7 +4674,8 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
LLVMPositionBuilderAtEnd(g->builder, ok_block);
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
TypeTableEntry *slice_type = get_slice_type(g, u8_ptr_type);
size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
@@ -4381,6 +4744,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
}
+static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
+ IrInstructionAtomicLoad *instruction)
+{
+ LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
+ LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+ LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value.type, "");
+ LLVMSetOrdering(load_inst, ordering);
+ return load_inst;
+}
+
static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
IrInstructionMergeErrRetTraces *instruction)
{
@@ -4402,6 +4775,13 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e
return nullptr;
}
+static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {
+ LLVMValueRef op = ir_llvm_value(g, instruction->op);
+ assert(instruction->base.value.type->id == TypeTableEntryIdFloat);
+ LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt);
+ return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -4453,13 +4833,13 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdCheckSwitchProngs:
case IrInstructionIdCheckStatementIsVoid:
case IrInstructionIdTypeName:
- case IrInstructionIdCanImplicitCast:
case IrInstructionIdDeclRef:
case IrInstructionIdSwitchVar:
case IrInstructionIdOffsetOf:
+ case IrInstructionIdTypeInfo:
case IrInstructionIdTypeId:
case IrInstructionIdSetEvalBranchQuota:
- case IrInstructionIdPtrTypeOf:
+ case IrInstructionIdPtrType:
case IrInstructionIdOpaqueType:
case IrInstructionIdSetAlignStack:
case IrInstructionIdArgType:
@@ -4469,6 +4849,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdPromiseResultType:
case IrInstructionIdAwaitBookkeeping:
case IrInstructionIdAddImplicitReturnType:
+ case IrInstructionIdIntCast:
+ case IrInstructionIdFloatCast:
+ case IrInstructionIdIntToFloat:
+ case IrInstructionIdFloatToInt:
+ case IrInstructionIdBoolToInt:
+ case IrInstructionIdErrSetCast:
+ case IrInstructionIdFromBytes:
+ case IrInstructionIdToBytes:
+ case IrInstructionIdEnumToInt:
zig_unreachable();
case IrInstructionIdReturn:
@@ -4505,12 +4894,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNonNull:
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
- case IrInstructionIdUnwrapMaybe:
- return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
+ case IrInstructionIdUnwrapOptional:
+ return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
case IrInstructionIdClz:
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
+ case IrInstructionIdPopCount:
+ return ir_render_pop_count(g, executable, (IrInstructionPopCount *)instruction);
case IrInstructionIdSwitchBr:
return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);
case IrInstructionIdPhi:
@@ -4539,6 +4930,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
case IrInstructionIdFrameAddress:
return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
+ case IrInstructionIdHandle:
+ return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
case IrInstructionIdOverflowOp:
return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdTestErr:
@@ -4547,8 +4940,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
case IrInstructionIdUnwrapErrPayload:
return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
- case IrInstructionIdMaybeWrap:
- return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction);
+ case IrInstructionIdOptionalWrap:
+ return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction);
case IrInstructionIdErrWrapCode:
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
case IrInstructionIdErrWrapPayload:
@@ -4617,12 +5010,16 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
case IrInstructionIdAtomicRmw:
return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
+ case IrInstructionIdAtomicLoad:
+ return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
case IrInstructionIdSaveErrRetAddr:
return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
case IrInstructionIdMergeErrRetTraces:
return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
case IrInstructionIdMarkErrRetTracePtr:
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
+ case IrInstructionIdSqrt:
+ return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
}
zig_unreachable();
}
@@ -4649,7 +5046,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
-static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
+static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -4665,6 +5062,10 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
parent->data.p_array.elem_index);
case ConstParentIdUnion:
return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
+ case ConstParentIdScalar:
+ render_const_val(g, parent->data.p_scalar.scalar_val, "");
+ render_const_val_global(g, parent->data.p_scalar.scalar_val, "");
+ return parent->data.p_scalar.scalar_val->global_refs->llvm_global;
}
zig_unreachable();
}
@@ -4690,7 +5091,8 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
};
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
} else {
- zig_unreachable();
+ assert(parent->id == ConstParentIdScalar);
+ return base_ptr;
}
}
@@ -4734,10 +5136,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdComptimeFloat:
+ case TypeTableEntryIdComptimeInt:
+ case TypeTableEntryIdUndefined:
+ case TypeTableEntryIdNull:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
@@ -4769,7 +5171,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
}
case TypeTableEntryIdPointer:
case TypeTableEntryIdFn:
- case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdOptional:
case TypeTableEntryIdPromise:
{
LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
@@ -4817,6 +5219,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef
return LLVMTypeOf(val) != type_entry->type_ref;
}
+static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) {
+ render_const_val_global(g, const_val, name);
+ switch (const_val->data.x_ptr.special) {
+ case ConstPtrSpecialInvalid:
+ case ConstPtrSpecialDiscard:
+ zig_unreachable();
+ case ConstPtrSpecialRef:
+ {
+ ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
+ render_const_val(g, pointee, "");
+ render_const_val_global(g, pointee, "");
+ ConstExprValue *other_val = pointee;
+ const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ case ConstPtrSpecialBaseArray:
+ {
+ ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
+ size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
+ assert(array_const_val->type->id == TypeTableEntryIdArray);
+ if (array_const_val->type->zero_bits) {
+ // make this a null pointer
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
+ elem_index);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialBaseStruct:
+ {
+ ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
+ assert(struct_const_val->type->id == TypeTableEntryIdStruct);
+ if (struct_const_val->type->zero_bits) {
+ // make this a null pointer
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
+ size_t gen_field_index =
+ struct_const_val->type->data.structure.fields[src_field_index].gen_index;
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
+ gen_field_index);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialHardCodedAddr:
+ {
+ uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ case ConstPtrSpecialFunction:
+ return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
+ }
+ zig_unreachable();
+}
+
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
TypeTableEntry *type_entry = const_val->type;
assert(!type_entry->zero_bits);
@@ -4839,6 +5314,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
const_val->data.x_err_set->value, false);
case TypeTableEntryIdFloat:
switch (type_entry->data.floating.bit_count) {
+ case 16:
+ return LLVMConstReal(type_entry->type_ref, zig_f16_to_double(const_val->data.x_f16));
case 32:
return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
case 64:
@@ -4861,23 +5338,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
} else {
return LLVMConstNull(LLVMInt1Type());
}
- case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdOptional:
{
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
if (child_type->zero_bits) {
- return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
+ return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
} else if (type_is_codegen_pointer(child_type)) {
- if (const_val->data.x_maybe) {
- return gen_const_val(g, const_val->data.x_maybe, "");
- } else {
- return LLVMConstNull(child_type->type_ref);
- }
+ return gen_const_val_ptr(g, const_val, name);
} else {
LLVMValueRef child_val;
LLVMValueRef maybe_val;
bool make_unnamed_struct;
- if (const_val->data.x_maybe) {
- child_val = gen_const_val(g, const_val->data.x_maybe, "");
+ if (const_val->data.x_optional) {
+ child_val = gen_const_val(g, const_val->data.x_optional, "");
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
@@ -5067,78 +5540,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
case TypeTableEntryIdPointer:
- {
- render_const_val_global(g, const_val, name);
- switch (const_val->data.x_ptr.special) {
- case ConstPtrSpecialInvalid:
- case ConstPtrSpecialDiscard:
- zig_unreachable();
- case ConstPtrSpecialRef:
- {
- ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
- render_const_val(g, pointee, "");
- render_const_val_global(g, pointee, "");
- ConstExprValue *other_val = pointee;
- const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
- render_const_val_global(g, const_val, "");
- return const_val->global_refs->llvm_value;
- }
- case ConstPtrSpecialBaseArray:
- {
- ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
- size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
- assert(array_const_val->type->id == TypeTableEntryIdArray);
- if (array_const_val->type->zero_bits) {
- // make this a null pointer
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
- const_val->type->type_ref);
- render_const_val_global(g, const_val, "");
- return const_val->global_refs->llvm_value;
- }
- LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
- elem_index);
- LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
- const_val->global_refs->llvm_value = ptr_val;
- render_const_val_global(g, const_val, "");
- return ptr_val;
- }
- case ConstPtrSpecialBaseStruct:
- {
- ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
- assert(struct_const_val->type->id == TypeTableEntryIdStruct);
- if (struct_const_val->type->zero_bits) {
- // make this a null pointer
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
- const_val->type->type_ref);
- render_const_val_global(g, const_val, "");
- return const_val->global_refs->llvm_value;
- }
- size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
- size_t gen_field_index =
- struct_const_val->type->data.structure.fields[src_field_index].gen_index;
- LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
- gen_field_index);
- LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
- const_val->global_refs->llvm_value = ptr_val;
- render_const_val_global(g, const_val, "");
- return ptr_val;
- }
- case ConstPtrSpecialHardCodedAddr:
- {
- uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
- const_val->type->type_ref);
- render_const_val_global(g, const_val, "");
- return const_val->global_refs->llvm_value;
- }
- case ConstPtrSpecialFunction:
- return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
- }
- }
- zig_unreachable();
+ return gen_const_val_ptr(g, const_val, name);
case TypeTableEntryIdErrorUnion:
{
TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
@@ -5180,10 +5582,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdComptimeFloat:
+ case TypeTableEntryIdComptimeInt:
+ case TypeTableEntryIdUndefined:
+ case TypeTableEntryIdNull:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -5232,7 +5634,8 @@ static void generate_error_name_table(CodeGen *g) {
assert(g->errors_by_index.length > 0);
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
@@ -5269,54 +5672,6 @@ static void generate_error_name_table(CodeGen *g) {
LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init)));
}
-static void generate_enum_name_tables(CodeGen *g) {
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
- TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
-
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- LLVMValueRef array_ptr_indices[] = {
- LLVMConstNull(usize->type_ref),
- LLVMConstNull(usize->type_ref),
- };
-
-
- for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
- TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
- assert(enum_type->id == TypeTableEntryIdEnum);
-
- size_t field_count = enum_type->data.enumeration.src_field_count;
- LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
- for (size_t field_i = 0; field_i < field_count; field_i += 1) {
- Buf *name = enum_type->data.enumeration.fields[field_i].name;
-
- LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
- LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
- LLVMSetInitializer(str_global, str_init);
- LLVMSetLinkage(str_global, LLVMPrivateLinkage);
- LLVMSetGlobalConstant(str_global, true);
- LLVMSetUnnamedAddr(str_global, true);
- LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
-
- LLVMValueRef fields[] = {
- LLVMConstGEP(str_global, array_ptr_indices, 2),
- LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
- };
- values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
- }
-
- LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count);
-
- Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false);
- LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name));
- LLVMSetInitializer(name_table, name_table_init);
- LLVMSetLinkage(name_table, LLVMPrivateLinkage);
- LLVMSetGlobalConstant(name_table, true);
- LLVMSetUnnamedAddr(name_table, true);
- LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
- enum_type->data.enumeration.name_table = name_table;
- }
-}
-
static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
IrExecutable *executable = &fn->analyzed_executable;
assert(executable->basic_block_list.length > 0);
@@ -5413,14 +5768,13 @@ static void do_code_gen(CodeGen *g) {
}
generate_error_name_table(g);
- generate_enum_name_tables(g);
// Generate module level variables
for (size_t i = 0; i < g->global_vars.length; i += 1) {
TldVar *tld_var = g->global_vars.at(i);
VariableTableEntry *var = tld_var->var;
- if (var->value->type->id == TypeTableEntryIdNumLitFloat) {
+ if (var->value->type->id == TypeTableEntryIdComptimeFloat) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
@@ -5434,7 +5788,7 @@ static void do_code_gen(CodeGen *g) {
continue;
}
- if (var->value->type->id == TypeTableEntryIdNumLitInt) {
+ if (var->value->type->id == TypeTableEntryIdComptimeInt) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
@@ -5552,8 +5906,8 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdSlice) {
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
slot = &slice_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdMaybeWrap) {
- IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction;
+ } else if (instruction->id == IrInstructionIdOptionalWrap) {
+ IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
slot = &maybe_wrap_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdErrWrapPayload) {
IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
@@ -5561,6 +5915,9 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdErrWrapCode) {
IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
slot = &err_wrap_code_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdCmpxchg) {
+ IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
+ slot = &cmpxchg_instruction->tmp_ptr;
} else {
zig_unreachable();
}
@@ -5670,6 +6027,7 @@ static void do_code_gen(CodeGen *g) {
ir_render(g, fn_table_entry);
}
+
assert(!g->errors.length);
if (buf_len(&g->global_asm) != 0) {
@@ -5722,10 +6080,12 @@ static void do_code_gen(CodeGen *g) {
os_path_join(g->cache_dir, o_basename, output_path);
ensure_cache_dir(g);
+ bool is_small = g->build_mode == BuildModeSmallRelease;
+
switch (g->emit_file_type) {
case EmitFileTypeBinary:
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
- ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug))
+ ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
{
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
}
@@ -5735,7 +6095,7 @@ static void do_code_gen(CodeGen *g) {
case EmitFileTypeAssembly:
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
- ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug))
+ ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
{
zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
}
@@ -5744,7 +6104,7 @@ static void do_code_gen(CodeGen *g) {
case EmitFileTypeLLVMIr:
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
- ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug))
+ ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
{
zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
}
@@ -5756,21 +6116,6 @@ static void do_code_gen(CodeGen *g) {
}
}
-static const uint8_t int_sizes_in_bits[] = {
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 16,
- 29,
- 32,
- 64,
- 128,
-};
-
struct CIntTypeInfo {
CIntType id;
const char *name;
@@ -5823,25 +6168,27 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_block = entry;
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
- buf_init_from_str(&entry->name, "(float literal)");
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdComptimeFloat);
+ buf_init_from_str(&entry->name, "comptime_float");
entry->zero_bits = true;
g->builtin_types.entry_num_lit_float = entry;
+ g->primitive_type_table.put(&entry->name, entry);
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
- buf_init_from_str(&entry->name, "(integer literal)");
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdComptimeInt);
+ buf_init_from_str(&entry->name, "comptime_int");
entry->zero_bits = true;
g->builtin_types.entry_num_lit_int = entry;
+ g->primitive_type_table.put(&entry->name, entry);
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefined);
buf_init_from_str(&entry->name, "(undefined)");
entry->zero_bits = true;
g->builtin_types.entry_undef = entry;
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit);
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNull);
buf_init_from_str(&entry->name, "(null)");
entry->zero_bits = true;
g->builtin_types.entry_null = entry;
@@ -5853,16 +6200,6 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_arg_tuple = entry;
}
- for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
- uint8_t size_in_bits = int_sizes_in_bits[int_size_i];
- for (size_t is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) {
- bool is_signed = is_signed_list[is_sign_i];
- TypeTableEntry *entry = make_int_type(g, is_signed, size_in_bits);
- g->primitive_type_table.put(&entry->name, entry);
- get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
- }
- }
-
for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) {
const CIntTypeInfo *info = &c_int_type_infos[i];
uint32_t size_in_bits = target_c_type_size_in_bits(&g->zig_target, info->id);
@@ -5921,58 +6258,30 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_usize = entry;
}
}
- {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->type_ref = LLVMFloatType();
- buf_init_from_str(&entry->name, "f32");
- entry->data.floating.bit_count = 32;
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
- debug_size_in_bits,
- ZigLLVMEncoding_DW_ATE_float());
- g->builtin_types.entry_f32 = entry;
- g->primitive_type_table.put(&entry->name, entry);
- }
- {
+ auto add_fp_entry = [] (CodeGen *g,
+ const char *name,
+ uint32_t bit_count,
+ LLVMTypeRef type_ref,
+ TypeTableEntry **field) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->type_ref = LLVMDoubleType();
- buf_init_from_str(&entry->name, "f64");
- entry->data.floating.bit_count = 64;
+ entry->type_ref = type_ref;
+ buf_init_from_str(&entry->name, name);
+ entry->data.floating.bit_count = bit_count;
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
debug_size_in_bits,
ZigLLVMEncoding_DW_ATE_float());
- g->builtin_types.entry_f64 = entry;
+ *field = entry;
g->primitive_type_table.put(&entry->name, entry);
- }
- {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->type_ref = LLVMFP128Type();
- buf_init_from_str(&entry->name, "f128");
- entry->data.floating.bit_count = 128;
-
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
- debug_size_in_bits,
- ZigLLVMEncoding_DW_ATE_float());
- g->builtin_types.entry_f128 = entry;
- g->primitive_type_table.put(&entry->name, entry);
- }
- {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->type_ref = LLVMX86FP80Type();
- buf_init_from_str(&entry->name, "c_longdouble");
- entry->data.floating.bit_count = 80;
+ };
+ add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
+ add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
+ add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
+ add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
+ add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble);
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
- debug_size_in_bits,
- ZigLLVMEncoding_DW_ATE_float());
- g->builtin_types.entry_c_longdouble = entry;
- g->primitive_type_table.put(&entry->name, entry);
- }
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
entry->type_ref = LLVMVoidType();
@@ -6006,12 +6315,9 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_u29 = get_int_type(g, false, 29);
g->builtin_types.entry_u32 = get_int_type(g, false, 32);
g->builtin_types.entry_u64 = get_int_type(g, false, 64);
- g->builtin_types.entry_u128 = get_int_type(g, false, 128);
g->builtin_types.entry_i8 = get_int_type(g, true, 8);
- g->builtin_types.entry_i16 = get_int_type(g, true, 16);
g->builtin_types.entry_i32 = get_int_type(g, true, 32);
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
- g->builtin_types.entry_i128 = get_int_type(g, true, 128);
{
g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");
@@ -6061,6 +6367,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
+ create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
@@ -6070,6 +6377,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
+ create_builtin_fn(g, BuiltinFnIdField, "field", 2);
+ create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
@@ -6080,15 +6389,25 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
+ create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
- create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
- create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
+ create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
+ create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
+ create_builtin_fn(g, BuiltinFnIdIntCast, "intCast", 2);
+ create_builtin_fn(g, BuiltinFnIdFloatCast, "floatCast", 2);
+ create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);
+ create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);
+ create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1);
+ create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1);
+ create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1);
+ create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1);
+ create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2);
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
@@ -6109,8 +6428,10 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2);
create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
+ create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
+ create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
@@ -6122,6 +6443,10 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
+ create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
+ create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
+ create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
+ create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
}
static const char *bool_to_str(bool b) {
@@ -6133,17 +6458,12 @@ static const char *build_mode_to_str(BuildMode build_mode) {
case BuildModeDebug: return "Mode.Debug";
case BuildModeSafeRelease: return "Mode.ReleaseSafe";
case BuildModeFastRelease: return "Mode.ReleaseFast";
+ case BuildModeSmallRelease: return "Mode.ReleaseSmall";
}
zig_unreachable();
}
-static void define_builtin_compile_vars(CodeGen *g) {
- if (g->std_package == nullptr)
- return;
-
- const char *builtin_zig_basename = "builtin.zig";
- Buf *builtin_zig_path = buf_alloc();
- os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
+Buf *codegen_generate_builtin_source(CodeGen *g) {
Buf *contents = buf_alloc();
// Modifications to this struct must be coordinated with code that does anything with
@@ -6273,6 +6593,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
" Debug,\n"
" ReleaseSafe,\n"
" ReleaseFast,\n"
+ " ReleaseSmall,\n"
"};\n\n");
}
{
@@ -6286,6 +6607,197 @@ static void define_builtin_compile_vars(CodeGen *g) {
}
{
buf_appendf(contents,
+ "pub const TypeInfo = union(TypeId) {\n"
+ " Type: void,\n"
+ " Void: void,\n"
+ " Bool: void,\n"
+ " NoReturn: void,\n"
+ " Int: Int,\n"
+ " Float: Float,\n"
+ " Pointer: Pointer,\n"
+ " Array: Array,\n"
+ " Struct: Struct,\n"
+ " ComptimeFloat: void,\n"
+ " ComptimeInt: void,\n"
+ " Undefined: void,\n"
+ " Null: void,\n"
+ " Optional: Optional,\n"
+ " ErrorUnion: ErrorUnion,\n"
+ " ErrorSet: ErrorSet,\n"
+ " Enum: Enum,\n"
+ " Union: Union,\n"
+ " Fn: Fn,\n"
+ " Namespace: void,\n"
+ " Block: void,\n"
+ " BoundFn: Fn,\n"
+ " ArgTuple: void,\n"
+ " Opaque: void,\n"
+ " Promise: Promise,\n"
+ "\n\n"
+ " pub const Int = struct {\n"
+ " is_signed: bool,\n"
+ " bits: u8,\n"
+ " };\n"
+ "\n"
+ " pub const Float = struct {\n"
+ " bits: u8,\n"
+ " };\n"
+ "\n"
+ " pub const Pointer = struct {\n"
+ " size: Size,\n"
+ " is_const: bool,\n"
+ " is_volatile: bool,\n"
+ " alignment: u32,\n"
+ " child: type,\n"
+ "\n"
+ " pub const Size = enum {\n"
+ " One,\n"
+ " Many,\n"
+ " Slice,\n"
+ " };\n"
+ " };\n"
+ "\n"
+ " pub const Array = struct {\n"
+ " len: usize,\n"
+ " child: type,\n"
+ " };\n"
+ "\n"
+ " pub const ContainerLayout = enum {\n"
+ " Auto,\n"
+ " Extern,\n"
+ " Packed,\n"
+ " };\n"
+ "\n"
+ " pub const StructField = struct {\n"
+ " name: []const u8,\n"
+ " offset: ?usize,\n"
+ " field_type: type,\n"
+ " };\n"
+ "\n"
+ " pub const Struct = struct {\n"
+ " layout: ContainerLayout,\n"
+ " fields: []StructField,\n"
+ " defs: []Definition,\n"
+ " };\n"
+ "\n"
+ " pub const Optional = struct {\n"
+ " child: type,\n"
+ " };\n"
+ "\n"
+ " pub const ErrorUnion = struct {\n"
+ " error_set: type,\n"
+ " payload: type,\n"
+ " };\n"
+ "\n"
+ " pub const Error = struct {\n"
+ " name: []const u8,\n"
+ " value: usize,\n"
+ " };\n"
+ "\n"
+ " pub const ErrorSet = struct {\n"
+ " errors: []Error,\n"
+ " };\n"
+ "\n"
+ " pub const EnumField = struct {\n"
+ " name: []const u8,\n"
+ " value: usize,\n"
+ " };\n"
+ "\n"
+ " pub const Enum = struct {\n"
+ " layout: ContainerLayout,\n"
+ " tag_type: type,\n"
+ " fields: []EnumField,\n"
+ " defs: []Definition,\n"
+ " };\n"
+ "\n"
+ " pub const UnionField = struct {\n"
+ " name: []const u8,\n"
+ " enum_field: ?EnumField,\n"
+ " field_type: type,\n"
+ " };\n"
+ "\n"
+ " pub const Union = struct {\n"
+ " layout: ContainerLayout,\n"
+ " tag_type: ?type,\n"
+ " fields: []UnionField,\n"
+ " defs: []Definition,\n"
+ " };\n"
+ "\n"
+ " pub const CallingConvention = enum {\n"
+ " Unspecified,\n"
+ " C,\n"
+ " Cold,\n"
+ " Naked,\n"
+ " Stdcall,\n"
+ " Async,\n"
+ " };\n"
+ "\n"
+ " pub const FnArg = struct {\n"
+ " is_generic: bool,\n"
+ " is_noalias: bool,\n"
+ " arg_type: ?type,\n"
+ " };\n"
+ "\n"
+ " pub const Fn = struct {\n"
+ " calling_convention: CallingConvention,\n"
+ " is_generic: bool,\n"
+ " is_var_args: bool,\n"
+ " return_type: ?type,\n"
+ " async_allocator_type: ?type,\n"
+ " args: []FnArg,\n"
+ " };\n"
+ "\n"
+ " pub const Promise = struct {\n"
+ " child: ?type,\n"
+ " };\n"
+ "\n"
+ " pub const Definition = struct {\n"
+ " name: []const u8,\n"
+ " is_pub: bool,\n"
+ " data: Data,\n"
+ "\n"
+ " pub const Data = union(enum) {\n"
+ " Type: type,\n"
+ " Var: type,\n"
+ " Fn: FnDef,\n"
+ "\n"
+ " pub const FnDef = struct {\n"
+ " fn_type: type,\n"
+ " inline_type: Inline,\n"
+ " calling_convention: CallingConvention,\n"
+ " is_var_args: bool,\n"
+ " is_extern: bool,\n"
+ " is_export: bool,\n"
+ " lib_name: ?[]const u8,\n"
+ " return_type: type,\n"
+ " arg_names: [][] const u8,\n"
+ "\n"
+ " pub const Inline = enum {\n"
+ " Auto,\n"
+ " Always,\n"
+ " Never,\n"
+ " };\n"
+ " };\n"
+ " };\n"
+ " };\n"
+ "};\n\n");
+ assert(ContainerLayoutAuto == 0);
+ assert(ContainerLayoutExtern == 1);
+ assert(ContainerLayoutPacked == 2);
+
+ assert(CallingConventionUnspecified == 0);
+ assert(CallingConventionC == 1);
+ assert(CallingConventionCold == 2);
+ assert(CallingConventionNaked == 3);
+ assert(CallingConventionStdcall == 4);
+ assert(CallingConventionAsync == 5);
+
+ assert(FnInlineAuto == 0);
+ assert(FnInlineAlways == 1);
+ assert(FnInlineNever == 2);
+ }
+ {
+ buf_appendf(contents,
"pub const FloatMode = enum {\n"
" Optimized,\n"
" Strict,\n"
@@ -6317,13 +6829,27 @@ static void define_builtin_compile_vars(CodeGen *g) {
buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
+
+ return contents;
+}
+
+static void define_builtin_compile_vars(CodeGen *g) {
+ if (g->std_package == nullptr)
+ return;
+
+ const char *builtin_zig_basename = "builtin.zig";
+ Buf *builtin_zig_path = buf_alloc();
+ os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
+
+ Buf *contents = codegen_generate_builtin_source(g);
ensure_cache_dir(g);
os_write_file(builtin_zig_path, contents);
int err;
Buf *abs_full_path = buf_alloc();
if ((err = os_path_real(builtin_zig_path, abs_full_path))) {
- zig_panic("unable to open '%s': %s", buf_ptr(builtin_zig_path), err_str(err));
+ fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
+ exit(1);
}
assert(g->root_package);
@@ -6383,7 +6909,7 @@ static void init(CodeGen *g) {
const char *target_specific_features;
if (g->is_native_target) {
// LLVM creates invalid binaries on Windows sometimes.
- // See https://github.com/zig-lang/zig/issues/508
+ // See https://github.com/ziglang/zig/issues/508
// As a workaround we do not use target native features on Windows.
if (g->zig_target.os == OsWindows) {
target_specific_cpu_args = "";
@@ -6443,7 +6969,7 @@ static void init(CodeGen *g) {
}
}
- g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
+ g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
define_builtin_fns(g);
define_builtin_compile_vars(g);
@@ -6490,11 +7016,11 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
Buf *abs_full_path = buf_alloc();
int err;
if ((err = os_path_real(&path_to_code_src, abs_full_path))) {
- zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
+ zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
}
Buf *import_code = buf_alloc();
if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
- zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
+ zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
}
return add_source_file(g, package, abs_full_path, import_code);
@@ -6522,7 +7048,8 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
exit(0);
}
- TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
+ PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
TypeTableEntry *fn_type = get_test_fn_type(g);
@@ -6577,12 +7104,14 @@ static void gen_root_source(CodeGen *g) {
Buf *abs_full_path = buf_alloc();
int err;
if ((err = os_path_real(rel_full_path, abs_full_path))) {
- zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
+ fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
+ exit(1);
}
Buf *source_code = buf_alloc();
if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
- zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
+ fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
+ exit(1);
}
g->root_import = add_source_file(g, g->root_package, abs_full_path, source_code);
@@ -6681,10 +7210,10 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdComptimeFloat:
+ case TypeTableEntryIdComptimeInt:
+ case TypeTableEntryIdUndefined:
+ case TypeTableEntryIdNull:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -6726,7 +7255,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
case TypeTableEntryIdArray:
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
return;
- case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdOptional:
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
return;
case TypeTableEntryIdFn:
@@ -6815,7 +7344,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf));
break;
}
- case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdOptional:
{
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
if (child_type->zero_bits) {
@@ -6866,10 +7395,10 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdComptimeFloat:
+ case TypeTableEntryIdComptimeInt:
+ case TypeTableEntryIdUndefined:
+ case TypeTableEntryIdNull:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdPromise:
zig_unreachable();
@@ -6925,7 +7454,7 @@ static void gen_h_file(CodeGen *g) {
FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
if (!out_h)
- zig_panic("unable to open %s: %s", buf_ptr(g->out_h_path), strerror(errno));
+ zig_panic("unable to open %s: %s\n", buf_ptr(g->out_h_path), strerror(errno));
Buf *export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)));
buf_upcase(export_macro);
@@ -7018,67 +7547,76 @@ static void gen_h_file(CodeGen *g) {
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdComptimeFloat:
+ case TypeTableEntryIdComptimeInt:
case TypeTableEntryIdArray:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdUndefined:
+ case TypeTableEntryIdNull:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
- case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdOptional:
case TypeTableEntryIdFn:
case TypeTableEntryIdPromise:
zig_unreachable();
case TypeTableEntryIdEnum:
- assert(type_entry->data.enumeration.layout == ContainerLayoutExtern);
- fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));
- for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
- TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
- Buf *value_buf = buf_alloc();
- bigint_append_buf(value_buf, &enum_field->value, 10);
- fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));
- if (field_i != type_entry->data.enumeration.src_field_count - 1) {
- fprintf(out_h, ",");
+ if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
+ fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));
+ for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
+ TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
+ Buf *value_buf = buf_alloc();
+ bigint_append_buf(value_buf, &enum_field->value, 10);
+ fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));
+ if (field_i != type_entry->data.enumeration.src_field_count - 1) {
+ fprintf(out_h, ",");
+ }
+ fprintf(out_h, "\n");
}
- fprintf(out_h, "\n");
+ fprintf(out_h, "};\n\n");
+ } else {
+ fprintf(out_h, "enum %s;\n", buf_ptr(&type_entry->name));
}
- fprintf(out_h, "};\n\n");
break;
case TypeTableEntryIdStruct:
- assert(type_entry->data.structure.layout == ContainerLayoutExtern);
- fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));
- for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
- TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
-
- Buf *type_name_buf = buf_alloc();
- get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
-
- if (struct_field->type_entry->id == TypeTableEntryIdArray) {
- fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),
- buf_ptr(struct_field->name),
- struct_field->type_entry->data.array.len);
- } else {
- fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));
- }
+ if (type_entry->data.structure.layout == ContainerLayoutExtern) {
+ fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));
+ for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
+ TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
+
+ Buf *type_name_buf = buf_alloc();
+ get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
+
+ if (struct_field->type_entry->id == TypeTableEntryIdArray) {
+ fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),
+ buf_ptr(struct_field->name),
+ struct_field->type_entry->data.array.len);
+ } else {
+ fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));
+ }
+ }
+ fprintf(out_h, "};\n\n");
+ } else {
+ fprintf(out_h, "struct %s;\n", buf_ptr(&type_entry->name));
}
- fprintf(out_h, "};\n\n");
break;
case TypeTableEntryIdUnion:
- assert(type_entry->data.unionation.layout == ContainerLayoutExtern);
- fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));
- for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
- TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
-
- Buf *type_name_buf = buf_alloc();
- get_c_type(g, gen_h, union_field->type_entry, type_name_buf);
- fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));
+ if (type_entry->data.unionation.layout == ContainerLayoutExtern) {
+ fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));
+ for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
+ TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
+
+ Buf *type_name_buf = buf_alloc();
+ get_c_type(g, gen_h, union_field->type_entry, type_name_buf);
+ fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));
+ }
+ fprintf(out_h, "};\n\n");
+ } else {
+ fprintf(out_h, "union %s;\n", buf_ptr(&type_entry->name));
}
- fprintf(out_h, "};\n\n");
break;
case TypeTableEntryIdOpaque:
fprintf(out_h, "struct %s;\n\n", buf_ptr(&type_entry->name));
@@ -7135,4 +7673,3 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
}
return pkg;
}
-