Commit a37bb4a4da
Changed files (7)
doc
example
hello_world
test
doc/vim/syntax/zig.vim
@@ -15,7 +15,8 @@ syn keyword zigRepeat while for
syn keyword zigConstant null undefined
syn keyword zigKeyword fn import
-syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type error
+syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 void unreachable type error
+syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong
syn keyword zigBoolean true false
doc/langref.md
@@ -187,7 +187,6 @@ u64 uint64_t unsigned 64-bit integer
f32 float 32-bit IEE754 floating point
f64 double 64-bit IEE754 floating point
-f128 long double 128-bit IEE754 floating point
isize intptr_t signed pointer sized integer
usize uintptr_t unsigned pointer sized integer
doc/targets.md
@@ -9,3 +9,5 @@ target-specific. Add logic for how to do function prototypes and function calls
for the target when an exported or external function has a byvalue struct.
Write the target-specific code in std.zig.
+
+Update the C integer types to be the correct size for the target.
example/hello_world/hello_libc.zig
@@ -2,10 +2,10 @@ export executable "hello";
#link("c")
extern {
- fn printf(__format: &const u8, ...) -> i32;
+ fn printf(__format: &const u8, ...) -> c_int;
}
-export fn main(argc: i32, argv: &&u8) -> i32 {
+export fn main(argc: c_int, argv: &&u8) -> c_int {
printf(c"Hello, world!\n");
return 0;
}
src/all_types.hpp
@@ -752,9 +752,6 @@ struct TypeTableEntryPointer {
struct TypeTableEntryInt {
bool is_signed;
- LLVMValueRef add_with_overflow_fn;
- LLVMValueRef sub_with_overflow_fn;
- LLVMValueRef mul_with_overflow_fn;
};
struct TypeTableEntryArray {
@@ -1025,6 +1022,7 @@ struct CodeGen {
uint32_t next_error_index;
uint32_t error_value_count;
TypeTableEntry *err_tag_type;
+ LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
};
struct VariableTableEntry {
src/codegen.cpp
@@ -100,6 +100,74 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no
}
}
+enum AddSubMul {
+ AddSubMulAdd = 0,
+ AddSubMulSub = 1,
+ AddSubMulMul = 2,
+};
+
+static int bits_index(int size_in_bits) {
+ switch (size_in_bits) {
+ case 8:
+ return 0;
+ case 16:
+ return 1;
+ case 32:
+ return 2;
+ case 64:
+ return 3;
+ default:
+ zig_unreachable();
+ }
+}
+
+static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
+ const char *signed_name, const char *unsigned_name)
+{
+ const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
+ Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
+
+ LLVMTypeRef return_elem_types[] = {
+ type_entry->type_ref,
+ LLVMInt1Type(),
+ };
+ LLVMTypeRef param_types[] = {
+ type_entry->type_ref,
+ type_entry->type_ref,
+ };
+ LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
+ LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
+ LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
+ assert(LLVMGetIntrinsicID(fn_val));
+ return fn_val;
+}
+
+static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul add_sub_mul) {
+ assert(type_entry->id == TypeTableEntryIdInt);
+ // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
+ int index0 = type_entry->data.integral.is_signed ? 0 : 1;
+ int index1 = add_sub_mul;
+ int index2 = bits_index(type_entry->size_in_bits);
+ LLVMValueRef *fn = &g->int_overflow_fns[index0][index1][index2];
+ if (*fn) {
+ return *fn;
+ }
+ switch (add_sub_mul) {
+ case AddSubMulAdd:
+ *fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");
+ break;
+ case AddSubMulSub:
+ *fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");
+ break;
+ case AddSubMulMul:
+ *fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
+ break;
+
+ }
+ return *fn;
+}
+
+
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -118,16 +186,17 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(fn_call_param_count == 4);
TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
- LLVMValueRef fn_val;
+ AddSubMul add_sub_mul;
if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {
- fn_val = int_type->data.integral.add_with_overflow_fn;
+ add_sub_mul = AddSubMulAdd;
} else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {
- fn_val = int_type->data.integral.sub_with_overflow_fn;
+ add_sub_mul = AddSubMulSub;
} else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {
- fn_val = int_type->data.integral.mul_with_overflow_fn;
+ add_sub_mul = AddSubMulMul;
} else {
zig_unreachable();
}
+ LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
@@ -2559,35 +2628,6 @@ static void do_code_gen(CodeGen *g) {
#endif
}
-static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
- const char *signed_name, const char *unsigned_name)
-{
- const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
- Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
-
- LLVMTypeRef return_elem_types[] = {
- type_entry->type_ref,
- LLVMInt1Type(),
- };
- LLVMTypeRef param_types[] = {
- type_entry->type_ref,
- type_entry->type_ref,
- };
- LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
- LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
- LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
- assert(LLVMGetIntrinsicID(fn_val));
- return fn_val;
-}
-
-static void add_int_overflow_fns(CodeGen *g, TypeTableEntry *type_entry) {
- assert(type_entry->id == TypeTableEntryIdInt);
-
- type_entry->data.integral.add_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");
- type_entry->data.integral.sub_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");
- type_entry->data.integral.mul_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
-}
-
static const int int_sizes_in_bits[] = {
8,
16,
@@ -2595,6 +2635,52 @@ static const int int_sizes_in_bits[] = {
64,
};
+enum CIntType {
+ CIntTypeShort,
+ CIntTypeUShort,
+ CIntTypeInt,
+ CIntTypeUInt,
+ CIntTypeLong,
+ CIntTypeULong,
+ CIntTypeLongLong,
+ CIntTypeULongLong,
+};
+
+struct CIntTypeInfo {
+ CIntType id;
+ const char *name;
+ bool is_signed;
+};
+
+static const CIntTypeInfo c_int_type_infos[] = {
+ {CIntTypeShort, "c_short", true},
+ {CIntTypeUShort, "c_ushort", false},
+ {CIntTypeInt, "c_int", true},
+ {CIntTypeUInt, "c_uint", false},
+ {CIntTypeLong, "c_long", true},
+ {CIntTypeULong, "c_ulong", false},
+ {CIntTypeLongLong, "c_longlong", true},
+ {CIntTypeULongLong, "c_ulonglong", false},
+};
+
+static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
+ // TODO other architectures besides x86_64
+ switch (id) {
+ case CIntTypeShort:
+ case CIntTypeUShort:
+ return 16;
+ case CIntTypeInt:
+ case CIntTypeUInt:
+ return 32;
+ case CIntTypeLong:
+ case CIntTypeULong:
+ case CIntTypeLongLong:
+ case CIntTypeULongLong:
+ return 64;
+ }
+ zig_unreachable();
+}
+
static void define_builtin_types(CodeGen *g) {
{
// if this type is anywhere in the AST, we should never hit codegen.
@@ -2639,8 +2725,6 @@ static void define_builtin_types(CodeGen *g) {
get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
- add_int_overflow_fns(g, entry);
-
if (!is_signed) {
break;
} else {
@@ -2649,6 +2733,26 @@ static void define_builtin_types(CodeGen *g) {
}
}
+ for (int i = 0; i < array_length(c_int_type_infos); i += 1) {
+ const CIntTypeInfo *info = &c_int_type_infos[i];
+ uint64_t size_in_bits = get_c_type_size_in_bits(g, info->id);
+ bool is_signed = info->is_signed;
+
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
+ entry->type_ref = LLVMIntType(size_in_bits);
+
+ buf_init_from_str(&entry->name, info->name);
+
+ entry->size_in_bits = size_in_bits;
+ entry->align_in_bits = size_in_bits;
+
+ entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+ entry->size_in_bits, entry->align_in_bits,
+ is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
+ entry->data.integral.is_signed = is_signed;
+ g->primitive_type_table.put(&entry->name, entry);
+ }
+
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
entry->type_ref = LLVMInt1Type();
@@ -2669,11 +2773,6 @@ static void define_builtin_types(CodeGen *g) {
entry->align_in_bits = g->pointer_size_bytes * 8;
entry->data.integral.is_signed = true;
- TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
- entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
- entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
- entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
-
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed());
@@ -2688,11 +2787,6 @@ static void define_builtin_types(CodeGen *g) {
entry->align_in_bits = g->pointer_size_bytes * 8;
entry->data.integral.is_signed = false;
- TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
- entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
- entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
- entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
-
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned());
test/run_tests.cpp
@@ -98,10 +98,10 @@ static void add_compiling_test_cases(void) {
add_simple_case("hello world with libc", R"SOURCE(
#link("c")
extern {
- fn puts(s: &const u8) -> i32;
+ fn puts(s: &const u8) -> c_int;
}
-export fn main(argc: i32, argv: &&u8) -> i32 {
+export fn main(argc: c_int, argv: &&u8) -> c_int {
puts(c"Hello, world!");
return 0;
}
@@ -483,10 +483,10 @@ pub fn main(args: [][]u8) -> %void {
add_simple_case("number literals", R"SOURCE(
#link("c")
extern {
- fn printf(__format: &const u8, ...) -> i32;
+ fn printf(__format: &const u8, ...) -> c_int;
}
-export fn main(argc: i32, argv: &&u8) -> i32 {
+export fn main(argc: c_int, argv: &&u8) -> c_int {
printf(c"\n");
printf(c"0: %llu\n",