Commit a37bb4a4da

Andrew Kelley <superjoe30@gmail.com>
2016-01-26 07:21:13
add the C integer types
1 parent 01428d4
Changed files (7)
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",