add the C integer types

This commit is contained in:
Andrew Kelley 2016-01-25 23:21:13 -07:00
parent 01428d4a72
commit a37bb4a4da
7 changed files with 150 additions and 56 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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 {

View File

@ -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());

View File

@ -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",