From a37bb4a4dafa8e3e3b1e9e3bbd07e5cf4eee129b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 25 Jan 2016 23:21:13 -0700 Subject: add the C integer types --- src/codegen.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 45 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index b01c4a423f..cf76c6ce15 100644 --- a/src/codegen.cpp +++ b/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()); -- cgit v1.2.3