mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
add the C integer types
This commit is contained in:
parent
01428d4a72
commit
a37bb4a4da
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
184
src/codegen.cpp
184
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());
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user