un-special case constant global strings
This commit is contained in:
parent
1158bc3ead
commit
21fc5a6402
|
@ -49,6 +49,16 @@ struct ConstStructValue {
|
|||
ConstExprValue **fields;
|
||||
};
|
||||
|
||||
struct ConstArrayValue {
|
||||
ConstExprValue **fields;
|
||||
};
|
||||
|
||||
struct ConstPtrValue {
|
||||
ConstExprValue **ptr;
|
||||
// len should almost always be 1. exceptions include C strings
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
struct ConstExprValue {
|
||||
bool ok; // true if constant expression evalution worked
|
||||
bool depends_on_compile_var;
|
||||
|
@ -61,6 +71,8 @@ struct ConstExprValue {
|
|||
ConstExprValue *x_maybe;
|
||||
ConstEnumValue x_enum;
|
||||
ConstStructValue x_struct;
|
||||
ConstArrayValue x_array;
|
||||
ConstPtrValue x_ptr;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -900,7 +912,6 @@ struct CodeGen {
|
|||
ZigList<Buf *> lib_search_paths;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
|
||||
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
|
||||
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
|
||||
|
@ -924,7 +935,6 @@ struct CodeGen {
|
|||
TypeTableEntry *entry_usize;
|
||||
TypeTableEntry *entry_f32;
|
||||
TypeTableEntry *entry_f64;
|
||||
TypeTableEntry *entry_c_string_literal;
|
||||
TypeTableEntry *entry_void;
|
||||
TypeTableEntry *entry_unreachable;
|
||||
TypeTableEntry *entry_type;
|
||||
|
|
|
@ -1795,6 +1795,46 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node,
|
|||
return type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) {
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->const_val.ok = true;
|
||||
|
||||
int len_with_null = buf_len(str) + 1;
|
||||
expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null);
|
||||
expr->const_val.data.x_ptr.len = len_with_null;
|
||||
|
||||
ConstExprValue *all_chars = allocate<ConstExprValue>(len_with_null);
|
||||
for (int i = 0; i < buf_len(str); i += 1) {
|
||||
ConstExprValue *this_char = &all_chars[i];
|
||||
this_char->ok = true;
|
||||
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
|
||||
expr->const_val.data.x_ptr.ptr[i] = this_char;
|
||||
}
|
||||
|
||||
ConstExprValue *null_char = &all_chars[len_with_null - 1];
|
||||
null_char->ok = true;
|
||||
bignum_init_unsigned(&null_char->data.x_bignum, 0);
|
||||
expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char;
|
||||
|
||||
return get_pointer_to_type(g, g->builtin_types.entry_u8, true);
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) {
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->const_val.ok = true;
|
||||
expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str));
|
||||
|
||||
ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str));
|
||||
for (int i = 0; i < buf_len(str); i += 1) {
|
||||
ConstExprValue *this_char = &all_chars[i];
|
||||
this_char->ok = true;
|
||||
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
|
||||
expr->const_val.data.x_array.fields[i] = this_char;
|
||||
}
|
||||
return get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
|
||||
}
|
||||
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
|
||||
TypeTableEntry *expected_type, uint64_t x)
|
||||
{
|
||||
|
@ -2737,8 +2777,28 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
|
|||
*const_val = *other_val;
|
||||
break;
|
||||
case CastOpToUnknownSizeArray:
|
||||
zig_panic("TODO CastOpToUnknownSizeArray");
|
||||
break;
|
||||
{
|
||||
TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
|
||||
assert(other_type->id == TypeTableEntryIdArray);
|
||||
|
||||
ConstExprValue *all_fields = allocate<ConstExprValue>(2);
|
||||
ConstExprValue *ptr_field = &all_fields[0];
|
||||
ConstExprValue *len_field = &all_fields[1];
|
||||
|
||||
const_val->data.x_struct.fields = allocate<ConstExprValue*>(2);
|
||||
const_val->data.x_struct.fields[0] = ptr_field;
|
||||
const_val->data.x_struct.fields[1] = len_field;
|
||||
|
||||
ptr_field->ok = true;
|
||||
ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields;
|
||||
ptr_field->data.x_ptr.len = other_type->data.array.len;
|
||||
|
||||
len_field->ok = true;
|
||||
bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
|
||||
|
||||
const_val->ok = true;
|
||||
break;
|
||||
}
|
||||
case CastOpMaybeWrap:
|
||||
const_val->data.x_maybe = other_val;
|
||||
const_val->ok = true;
|
||||
|
@ -3422,6 +3482,16 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
|
|||
return g->builtin_types.entry_unreachable;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
if (node->data.string_literal.c) {
|
||||
return resolve_expr_const_val_as_c_string_lit(g, node, &node->data.string_literal.buf);
|
||||
} else {
|
||||
return resolve_expr_const_val_as_string_lit(g, node, &node->data.string_literal.buf);
|
||||
}
|
||||
}
|
||||
|
||||
// When you call analyze_expression, the node you pass might no longer be the child node
|
||||
// you thought it was due to implicit casting rewriting the AST.
|
||||
static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
|
@ -3544,12 +3614,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||
return_type = analyze_error_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeStringLiteral:
|
||||
if (node->data.string_literal.c) {
|
||||
return_type = g->builtin_types.entry_c_string_literal;
|
||||
} else {
|
||||
return_type = get_array_type(g, g->builtin_types.entry_u8,
|
||||
buf_len(&node->data.string_literal.buf));
|
||||
}
|
||||
return_type = analyze_string_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeCharLiteral:
|
||||
return_type = g->builtin_types.entry_u8;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
CodeGen *codegen_create(Buf *root_source_dir) {
|
||||
CodeGen *g = allocate<CodeGen>(1);
|
||||
g->str_table.init(32);
|
||||
g->link_table.init(32);
|
||||
g->import_table.init(32);
|
||||
g->builtin_fn_table.init(32);
|
||||
|
@ -92,22 +91,6 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) {
|
|||
g->cur_block_context->di_scope);
|
||||
}
|
||||
|
||||
static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
|
||||
auto entry = g->str_table.maybe_get(str);
|
||||
if (entry) {
|
||||
return entry->value;
|
||||
}
|
||||
LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c);
|
||||
LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");
|
||||
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
|
||||
LLVMSetInitializer(global_value, text);
|
||||
LLVMSetGlobalConstant(global_value, true);
|
||||
LLVMSetUnnamedAddr(global_value, true);
|
||||
g->str_table.put(str, global_value);
|
||||
|
||||
return global_value;
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_expr_type(AstNode *node) {
|
||||
return get_resolved_expr(node)->type_entry;
|
||||
}
|
||||
|
@ -1993,17 +1976,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
return gen_asm_expr(g, node);
|
||||
case NodeTypeErrorLiteral:
|
||||
return gen_error_literal(g, node);
|
||||
case NodeTypeStringLiteral:
|
||||
{
|
||||
Buf *str = &node->data.string_literal.buf;
|
||||
LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
|
||||
LLVMValueRef indices[] = {
|
||||
LLVMConstNull(g->builtin_types.entry_isize->type_ref),
|
||||
LLVMConstNull(g->builtin_types.entry_isize->type_ref),
|
||||
};
|
||||
LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, "");
|
||||
return ptr_val;
|
||||
}
|
||||
case NodeTypeCharLiteral:
|
||||
return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false);
|
||||
case NodeTypeSymbol:
|
||||
|
@ -2035,6 +2007,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
return gen_switch_expr(g, node);
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
case NodeTypeRoot:
|
||||
|
@ -2117,7 +2090,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
|||
}
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
|
||||
} else if (type_entry->id == TypeTableEntryIdArray) {
|
||||
zig_panic("TODO");
|
||||
TypeTableEntry *child_type = type_entry->data.array.child_type;
|
||||
uint64_t len = type_entry->data.array.len;
|
||||
LLVMValueRef *values = allocate<LLVMValueRef>(len);
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
ConstExprValue *field_value = const_val->data.x_array.fields[i];
|
||||
values[i] = gen_const_val(g, child_type, field_value);
|
||||
}
|
||||
return LLVMConstArray(child_type->type_ref, values, len);
|
||||
} else if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
|
||||
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
|
||||
|
@ -2135,6 +2115,32 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
|||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFn) {
|
||||
return const_val->data.x_fn->fn_value;
|
||||
} else if (type_entry->id == TypeTableEntryIdPointer) {
|
||||
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
|
||||
int len = const_val->data.x_ptr.len;
|
||||
LLVMValueRef target_val;
|
||||
if (len == 1) {
|
||||
target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]);
|
||||
} else if (len > 1) {
|
||||
LLVMValueRef *values = allocate<LLVMValueRef>(len);
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]);
|
||||
}
|
||||
target_val = LLVMConstArray(child_type->type_ref, values, len);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), "");
|
||||
LLVMSetInitializer(global_value, target_val);
|
||||
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
|
||||
LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const);
|
||||
LLVMSetUnnamedAddr(global_value, true);
|
||||
|
||||
if (len > 1) {
|
||||
return LLVMConstBitCast(global_value, type_entry->type_ref);
|
||||
} else {
|
||||
return global_value;
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -2532,8 +2538,6 @@ static void define_builtin_types(CodeGen *g) {
|
|||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, get_int_type(g, false, 8), true);
|
||||
|
||||
g->builtin_types.entry_u8 = get_int_type(g, false, 8);
|
||||
g->builtin_types.entry_u16 = get_int_type(g, false, 16);
|
||||
g->builtin_types.entry_u32 = get_int_type(g, false, 32);
|
||||
|
|
Loading…
Reference in New Issue
Block a user