IR: re-organize where state goes to prepare for generics

* Rip out legacy code for generics
 * put scope in instruction instead of AST nodes
 * separate top level decl stuff from AST nodes
   - remove the assumption that there is a 1:1 correspondence
     between an output instruction and an AST node
   - This way we won't have to clone AST nodes for generics.
This commit is contained in:
Andrew Kelley 2016-12-01 23:25:09 -05:00
parent f6cbb73c74
commit 2f259b8176
10 changed files with 1508 additions and 1899 deletions

View File

@ -20,6 +20,8 @@ struct AstNode;
struct ImportTableEntry;
struct FnTableEntry;
struct Scope;
struct ScopeBlock;
struct ScopeFnDef;
struct TypeTableEntry;
struct VariableTableEntry;
struct ErrorTableEntry;
@ -33,6 +35,13 @@ struct IrInstructionCast;
struct IrBasicBlock;
struct ScopeDecls;
struct IrGotoItem {
AstNode *source_node;
IrBasicBlock *bb;
size_t instruction_index;
Scope *scope;
};
struct IrExecutable {
ZigList<IrBasicBlock *> basic_block_list;
size_t mem_slot_count;
@ -41,8 +50,9 @@ struct IrExecutable {
size_t backward_branch_quota;
bool invalid;
ZigList<LabelTableEntry *> all_labels;
ZigList<AstNode *> goto_list;
ZigList<IrGotoItem> goto_list;
bool is_inline;
FnTableEntry *fn_entry;
};
enum OutType {
@ -129,36 +139,62 @@ enum ReturnKnowledge {
ReturnKnowledgeSkipDefers,
};
struct StructValExprCodeGen {
TypeTableEntry *type_entry;
LLVMValueRef ptr;
AstNode *source_node;
};
enum VisibMod {
VisibModPrivate,
VisibModPub,
VisibModExport,
};
enum TldId {
TldIdVar,
TldIdFn,
TldIdContainer,
TldIdTypeDef,
};
enum TldResolution {
TldResolutionUnresolved,
TldResolutionInvalid,
TldResolutionOk,
};
struct TopLevelDecl {
// populated by parser
struct Tld {
TldId id;
Buf *name;
VisibMod visib_mod;
AstNode *source_node;
// populated by semantic analyzer
ImportTableEntry *import;
Scope *parent_scope;
// set this flag temporarily to detect infinite loops
bool dep_loop_flag;
TldResolution resolution;
AstNode *parent_decl;
IrInstruction *value;
Tld *parent_tld;
};
struct TldVar {
Tld base;
VariableTableEntry *var;
};
struct TldFn {
Tld base;
FnTableEntry *fn_entry;
};
struct TldContainer {
Tld base;
ScopeDecls *decls_scope;
TypeTableEntry *type_entry;
};
struct TldTypeDef {
Tld base;
TypeTableEntry *type_entry;
};
struct TypeEnumField {
@ -223,7 +259,7 @@ struct AstNodeRoot {
};
struct AstNodeFnProto {
TopLevelDecl top_level_decl;
VisibMod visib_mod;
Buf *name;
ZigList<AstNode *> params;
AstNode *return_type;
@ -232,28 +268,12 @@ struct AstNodeFnProto {
bool is_inline;
bool is_coldcc;
bool is_nakedcc;
// populated by semantic analyzer:
// the function definition this fn proto is inside. can be null.
AstNode *fn_def_node;
FnTableEntry *fn_table_entry;
bool skip;
// computed from params field
size_t inline_arg_count;
size_t inline_or_var_type_arg_count;
// if this is a generic function implementation, this points to the generic node
AstNode *generic_proto_node;
};
struct AstNodeFnDef {
AstNode *fn_proto;
AstNode *body;
// populated by semantic analyzer
TypeTableEntry *implicit_return_type;
Scope *containing_scope;
Scope *child_scope;
};
struct AstNodeFnDecl {
@ -265,21 +285,10 @@ struct AstNodeParamDecl {
AstNode *type;
bool is_noalias;
bool is_inline;
// populated by semantic analyzer
VariableTableEntry *variable;
};
struct AstNodeBlock {
ZigList<AstNode *> statements;
// populated by semantic analyzer
// this one is the scope that the block itself introduces
Scope *child_block;
// this is the innermost scope created by defers and var decls.
// you can follow its parents up to child_block. it will equal
// child_block if there are no defers or var decls in the block.
Scope *nested_block;
};
enum ReturnKind {
@ -298,14 +307,13 @@ struct AstNodeDefer {
ReturnKind kind;
AstNode *expr;
// populated by semantic analyzer:
size_t index_in_block;
LLVMBasicBlockRef basic_block;
Scope *child_block;
// temporary data used in IR generation
// TODO populate during gen_defer
Scope *child_scope;
};
struct AstNodeVariableDeclaration {
TopLevelDecl top_level_decl;
VisibMod visib_mod;
Buf *symbol;
bool is_const;
bool is_inline;
@ -313,28 +321,19 @@ struct AstNodeVariableDeclaration {
// one or both of type and expr will be non null
AstNode *type;
AstNode *expr;
// populated by semantic analyzer
VariableTableEntry *variable;
};
struct AstNodeTypeDecl {
TopLevelDecl top_level_decl;
VisibMod visib_mod;
Buf *symbol;
AstNode *child_type;
// populated by semantic analyzer
// if this is set, don't process the node; we've already done so
// and here is the type (with id TypeTableEntryIdTypeDecl)
TypeTableEntry *override_type;
TypeTableEntry *child_type_entry;
};
struct AstNodeErrorValueDecl {
TopLevelDecl top_level_decl;
// always invalid if it's not VisibModPrivate but can be parsed that way
VisibMod visib_mod;
Buf *name;
// populated by semantic analyzer
ErrorTableEntry *err;
};
@ -388,19 +387,12 @@ struct AstNodeBinOpExpr {
AstNode *op1;
BinOpType bin_op;
AstNode *op2;
// populated by semantic analyzer:
// for when op is BinOpTypeAssign
VariableTableEntry *var_entry;
};
struct AstNodeUnwrapErrorExpr {
AstNode *op1;
AstNode *symbol; // can be null
AstNode *op2;
// populated by semantic analyzer:
VariableTableEntry *var;
};
enum CastOp {
@ -429,21 +421,11 @@ struct AstNodeFnCallExpr {
AstNode *fn_ref_expr;
ZigList<AstNode *> params;
bool is_builtin;
// populated by semantic analyzer:
BuiltinFnEntry *builtin_fn;
FnTableEntry *fn_entry;
CastOp cast_op;
// if cast_op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef tmp_ptr;
};
struct AstNodeArrayAccessExpr {
AstNode *array_ref_expr;
AstNode *subscript;
// populated by semantic analyzer:
};
struct AstNodeSliceExpr {
@ -451,22 +433,11 @@ struct AstNodeSliceExpr {
AstNode *start;
AstNode *end;
bool is_const;
// populated by semantic analyzer:
StructValExprCodeGen resolved_struct_val_expr;
};
struct AstNodeFieldAccessExpr {
AstNode *struct_expr;
Buf *field_name;
// populated by semantic analyzer
TypeStructField *type_struct_field;
TypeEnumField *type_enum_field;
StructValExprCodeGen resolved_struct_val_expr; // for enum values
TypeTableEntry *bare_container_type;
bool is_member_fn;
AstNode *container_init_expr_node;
};
enum PrefixOp {
@ -487,24 +458,21 @@ enum PrefixOp {
struct AstNodePrefixOpExpr {
PrefixOp prefix_op;
AstNode *primary_expr;
// populated by semantic analyzer
};
struct AstNodeUse {
VisibMod visib_mod;
AstNode *expr;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
TldResolution resolution;
IrInstruction *value;
};
struct AstNodeIfBoolExpr {
AstNode *condition;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
bool is_inline; // TODO
// populated by semantic analyzer
bool is_inline; // TODO parse inline if
};
struct AstNodeIfVarExpr {
@ -512,10 +480,7 @@ struct AstNodeIfVarExpr {
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
bool var_is_ptr;
bool is_inline; // TODO
// populated by semantic analyzer
TypeTableEntry *type;
bool is_inline; // TODO parse inline ?if?
};
struct AstNodeWhileExpr {
@ -523,11 +488,6 @@ struct AstNodeWhileExpr {
AstNode *continue_expr;
AstNode *body;
bool is_inline;
// populated by semantic analyzer
bool condition_always_true;
bool contains_break;
bool contains_continue;
};
struct AstNodeForExpr {
@ -537,20 +497,12 @@ struct AstNodeForExpr {
AstNode *body;
bool elem_is_ptr;
bool is_inline;
// populated by semantic analyzer
bool contains_break;
bool contains_continue;
VariableTableEntry *elem_var;
VariableTableEntry *index_var;
};
struct AstNodeSwitchExpr {
AstNode *expr;
ZigList<AstNode *> prongs;
bool is_inline;
// populated by semantic analyzer
};
struct AstNodeSwitchProng {
@ -573,10 +525,6 @@ struct AstNodeLabel {
struct AstNodeGoto {
Buf *name;
bool is_inline;
// populated by semantic analyzer
IrBasicBlock *bb;
size_t instruction_index;
};
struct AsmOutput {
@ -584,9 +532,6 @@ struct AsmOutput {
Buf *constraint;
Buf *variable_name;
AstNode *return_type; // null unless "=r" and return
// populated by semantic analyzer
VariableTableEntry *variable;
};
struct AsmInput {
@ -619,8 +564,6 @@ struct AstNodeAsmExpr {
ZigList<AsmOutput*> output_list;
ZigList<AsmInput*> input_list;
ZigList<Buf*> clobber_list;
// populated by semantic analyzer
};
enum ContainerKind {
@ -630,23 +573,17 @@ enum ContainerKind {
};
struct AstNodeStructDecl {
TopLevelDecl top_level_decl;
VisibMod visib_mod;
Buf *name;
ContainerKind kind;
ZigList<AstNode *> generic_params;
bool generic_params_is_var_args; // always an error but it can happen from parsing
ZigList<AstNode *> fields;
ZigList<AstNode *> decls;
// populated by semantic analyzer
ScopeDecls *decls_scope;
TypeTableEntry *type_entry;
TypeTableEntry *generic_fn_type;
bool skip;
};
struct AstNodeStructField {
TopLevelDecl top_level_decl;
VisibMod visib_mod;
Buf *name;
AstNode *type;
};
@ -654,14 +591,10 @@ struct AstNodeStructField {
struct AstNodeStringLiteral {
Buf *buf;
bool c;
// populated by semantic analyzer:
};
struct AstNodeCharLiteral {
uint8_t value;
// populated by semantic analyzer:
};
struct AstNodeNumberLiteral {
@ -670,16 +603,11 @@ struct AstNodeNumberLiteral {
// overflow is true if when parsing the number, we discovered it would not
// fit without losing data in a uint64_t or double
bool overflow;
// populated by semantic analyzer
};
struct AstNodeStructValueField {
Buf *name;
AstNode *expr;
// populated by semantic analyzer
TypeStructField *type_struct_field;
};
enum ContainerInitKind {
@ -691,68 +619,47 @@ struct AstNodeContainerInitExpr {
AstNode *type;
ZigList<AstNode *> entries;
ContainerInitKind kind;
// populated by semantic analyzer
StructValExprCodeGen resolved_struct_val_expr;
TypeTableEntry *enum_type;
};
struct AstNodeNullLiteral {
// populated by semantic analyzer
};
struct AstNodeUndefinedLiteral {
// populated by semantic analyzer
};
struct AstNodeZeroesLiteral {
// populated by semantic analyzer
};
struct AstNodeThisLiteral {
// populated by semantic analyzer
};
struct AstNodeSymbolExpr {
Buf *symbol;
// populated by semantic analyzer
TypeEnumField *enum_field;
uint32_t err_value;
};
struct AstNodeBoolLiteral {
bool value;
// populated by semantic analyzer
};
struct AstNodeBreakExpr {
// populated by semantic analyzer
};
struct AstNodeContinueExpr {
// populated by semantic analyzer
};
struct AstNodeArrayType {
AstNode *size;
AstNode *child_type;
bool is_const;
// populated by semantic analyzer
};
struct AstNodeErrorType {
// populated by semantic analyzer
};
struct AstNodeTypeLiteral {
// populated by semantic analyzer
};
struct AstNodeVarLiteral {
// populated by semantic analyzer
};
struct AstNode {
@ -761,9 +668,6 @@ struct AstNode {
size_t column;
uint32_t create_index; // for determinism purposes
ImportTableEntry *owner;
// the context in which this expression/node is evaluated.
// for blocks, this points to the containing scope, not the block's own scope for its children.
Scope *scope;
union {
AstNodeRoot root;
AstNodeFnDef fn_def;
@ -822,26 +726,12 @@ struct FnTypeParamInfo {
TypeTableEntry *type;
};
struct GenericParamValue {
TypeTableEntry *type;
AstNode *node;
size_t impl_index;
};
struct GenericFnTypeId {
AstNode *decl_node; // the generic fn or container decl node
GenericParamValue *generic_params;
size_t generic_param_count;
};
uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
struct FnTypeId {
TypeTableEntry *return_type;
FnTypeParamInfo *param_info;
size_t param_count;
size_t next_param_index;
bool is_var_args;
bool is_naked;
bool is_cold;
@ -945,6 +835,7 @@ struct FnGenParamInfo {
struct TypeTableEntryFn {
FnTypeId fn_type_id;
bool is_generic;
TypeTableEntry *gen_return_type;
size_t gen_param_count;
FnGenParamInfo *gen_param_info;
@ -955,10 +846,6 @@ struct TypeTableEntryFn {
TypeTableEntry *bound_fn_parent;
};
struct TypeTableEntryGenericFn {
AstNode *decl_node;
};
struct TypeTableEntryBoundFn {
TypeTableEntry *fn_type;
};
@ -993,7 +880,6 @@ enum TypeTableEntryId {
TypeTableEntryIdTypeDecl,
TypeTableEntryIdNamespace,
TypeTableEntryIdBlock,
TypeTableEntryIdGenericFn,
TypeTableEntryIdBoundFn,
};
@ -1018,7 +904,6 @@ struct TypeTableEntry {
TypeTableEntryUnion unionation;
TypeTableEntryFn fn;
TypeTableEntryTypeDecl type_decl;
TypeTableEntryGenericFn generic_fn;
TypeTableEntryBoundFn bound_fn;
} data;
@ -1056,10 +941,9 @@ enum FnAnalState {
FnAnalStateReady,
FnAnalStateProbing,
FnAnalStateComplete,
FnAnalStateSkipped,
FnAnalStateInvalid,
};
enum FnInline {
FnInlineAuto,
FnInlineAlways,
@ -1067,14 +951,18 @@ enum FnInline {
};
struct FnTableEntry {
LLVMValueRef fn_value;
LLVMValueRef llvm_value;
AstNode *proto_node;
AstNode *fn_def_node;
ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls
Scope *child_scope; // parent is scope for last parameter
ScopeBlock *def_scope; // parent is child_scope
ImportTableEntry *import_entry;
Buf symbol_name;
TypeTableEntry *type_entry; // function type
TypeTableEntry *implicit_return_type;
bool internal_linkage;
bool is_extern;
bool disable_export;
bool is_test;
FnInline fn_inline;
FnAnalState anal_state;
@ -1161,11 +1049,10 @@ struct CodeGen {
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
HashMap<GenericFnTypeId *, AstNode *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
ZigList<ImportTableEntry *> import_queue;
size_t import_queue_index;
ZigList<AstNode *> resolve_queue;
ZigList<Tld *> resolve_queue;
size_t resolve_queue_index;
ZigList<AstNode *> use_queue;
size_t use_queue_index;
@ -1249,6 +1136,7 @@ struct CodeGen {
// The function definitions this module includes. There must be a corresponding
// fn_protos entry.
ZigList<FnTableEntry *> fn_defs;
size_t fn_defs_index;
// The function prototypes this module includes. In the case of external declarations,
// there will not be a corresponding fn_defs entry.
ZigList<FnTableEntry *> fn_protos;
@ -1258,6 +1146,7 @@ struct CodeGen {
FnTableEntry *cur_fn;
FnTableEntry *main_fn;
LLVMValueRef cur_ret_ptr;
LLVMValueRef cur_fn_val;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
bool c_want_stdint;
@ -1295,6 +1184,7 @@ struct CodeGen {
IrInstruction *invalid_instruction;
};
// TODO after merging IR branch, we can probably delete some of these fields
struct VariableTableEntry {
Buf name;
TypeTableEntry *type;
@ -1304,8 +1194,6 @@ struct VariableTableEntry {
bool is_inline;
// which node is the declaration of the variable
AstNode *decl_node;
// which node contains the ConstExprValue for this variable's value
AstNode *val_node;
ZigLLVMDILocalVariable *di_loc_var;
size_t src_arg_index;
size_t gen_arg_index;
@ -1313,10 +1201,10 @@ struct VariableTableEntry {
Scope *child_scope;
LLVMValueRef param_value_ref;
bool force_depends_on_compile_var;
ImportTableEntry *import;
bool shadowable;
size_t mem_slot_index;
size_t ref_count;
ConstExprValue *value;
};
struct ErrorTableEntry {
@ -1339,9 +1227,6 @@ struct Scope {
Scope *parent;
ZigLLVMDIScope *di_scope;
bool safety_off;
AstNode *safety_set_node;
};
// This scope comes from global declarations or from
@ -1350,15 +1235,12 @@ struct Scope {
struct ScopeDecls {
Scope base;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
};
// This scope comes from a container declaration such as a struct,
// enum, or union.
struct ScopeContainer {
Scope base;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
bool safety_off;
AstNode *safety_set_node;
ImportTableEntry *import;
// If this is a scope from a container, this is the type entry, otherwise null
TypeTableEntry *container_type;
};
// This scope comes from a block expression in user code.
@ -1367,6 +1249,8 @@ struct ScopeBlock {
Scope base;
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
bool safety_off;
AstNode *safety_set_node;
};
// This scope is created from every defer expression.
@ -1401,7 +1285,7 @@ struct ScopeLoop {
// This scope is created for a function definition.
// NodeTypeFnDef
struct ScopeFnBody {
struct ScopeFnDef {
Scope base;
FnTableEntry *fn_entry;
@ -1479,6 +1363,7 @@ enum IrInstructionId {
struct IrInstruction {
IrInstructionId id;
Scope *scope;
AstNode *source_node;
ConstExprValue static_value;
TypeTableEntry *type_entry;
@ -1798,6 +1683,7 @@ struct IrInstructionAsm {
// Most information on inline assembly comes from the source node.
IrInstruction **input_list;
IrInstruction **output_types;
VariableTableEntry **output_vars;
size_t return_count;
bool has_side_effects;
};

File diff suppressed because it is too large Load Diff

View File

@ -22,11 +22,11 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits);
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info);
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *context,
TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope,
ContainerKind kind, AstNode *decl_node, const char *name);
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);
@ -49,9 +49,8 @@ AstNode *first_executing_node(AstNode *node);
// TODO move these over, these used to be static
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
AstNode *find_decl(Scope *context, Buf *name);
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
TopLevelDecl *get_as_top_level_decl(AstNode *node);
Tld *find_decl(Scope *scope, Buf *name);
void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only);
bool type_is_codegen_pointer(TypeTableEntry *type);
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
@ -61,16 +60,21 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node);
void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld);
void preview_use_decl(CodeGen *g, AstNode *node);
void resolve_use_decl(CodeGen *g, AstNode *node);
FnTableEntry *scope_fn_entry(Scope *scope);
ImportTableEntry *get_scope_import(Scope *scope);
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node,
Scope *parent_scope, Tld *parent_tld);
VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value);
ScopeDecls *create_decls_scope(AstNode *node, Scope *parent);
Scope *create_block_scope(AstNode *node, Scope *parent);
Scope *create_defer_scope(AstNode *node, Scope *parent);
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
Scope *create_cimport_scope(AstNode *node, Scope *parent);
Scope *create_loop_scope(AstNode *node, Scope *parent);
Scope *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
#endif

View File

@ -377,7 +377,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
break;
case NodeTypeFnProto:
{
const char *pub_str = visib_mod_string(node->data.fn_proto.top_level_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
const char *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *inline_str = inline_string(node->data.fn_proto.is_inline);
fprintf(ar->f, "%s%s%sfn ", pub_str, inline_str, extern_str);
@ -460,7 +460,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
case NodeTypeVariableDeclaration:
{
const char *pub_str = visib_mod_string(node->data.variable_declaration.top_level_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var);
@ -478,7 +478,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
case NodeTypeTypeDecl:
{
const char *pub_str = visib_mod_string(node->data.type_decl.top_level_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.type_decl.visib_mod);
const char *var_name = buf_ptr(node->data.type_decl.symbol);
fprintf(ar->f, "%stype %s = ", pub_str, var_name);
render_node_grouped(ar, node->data.type_decl.child_type);
@ -575,7 +575,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeContainerDecl:
{
const char *struct_name = buf_ptr(node->data.struct_decl.name);
const char *pub_str = visib_mod_string(node->data.struct_decl.top_level_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod);
const char *container_str = container_string(node->data.struct_decl.kind);
fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name);
ar->indent += ar->indent_size;

View File

@ -60,7 +60,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->primitive_type_table.init(32);
g->fn_type_table.init(32);
g->error_table.init(16);
g->generic_table.init(16);
g->is_release_build = false;
g->is_test_build = false;
g->want_h_file = true;
@ -227,13 +226,59 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
Buf *symbol_name;
if (!fn_table_entry->internal_linkage) {
symbol_name = &fn_table_entry->symbol_name;
} else {
symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
}
TypeTableEntry *fn_type = fn_table_entry->type_entry;
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
switch (fn_table_entry->fn_inline) {
case FnInlineAlways:
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMAlwaysInlineAttribute);
break;
case FnInlineNever:
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoInlineAttribute);
break;
case FnInlineAuto:
break;
}
if (fn_type->data.fn.fn_type_id.is_naked) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNakedAttribute);
}
LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage);
if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoReturnAttribute);
}
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
if (!fn_type->data.fn.fn_type_id.is_extern) {
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoUnwindAttribute);
}
if (!g->is_release_build && fn_table_entry->fn_inline != FnInlineAlways) {
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
}
return fn_table_entry->llvm_value;
}
static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
if (scope->di_scope)
return scope->di_scope;
if (scope->node->type == NodeTypeFnDef) {
assert(scope->parent);
ScopeFnBody *fn_scope = (ScopeFnBody *)scope;
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
FnTableEntry *fn_table_entry = fn_scope->fn_entry;
unsigned line_number = fn_table_entry->proto_node->line + 1;
unsigned scope_line = line_number;
@ -247,11 +292,13 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
is_definition, scope_line, flags, is_optimized, nullptr);
scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
} else if (scope->node->type == NodeTypeRoot ||
scope->node->type == NodeTypeContainerDecl)
{
ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
} else if (scope->node->type == NodeTypeRoot) {
scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);
} else if (scope->node->type == NodeTypeContainerDecl) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
assert(decls_scope->container_type);
scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
} else {
assert(scope->parent);
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
@ -265,11 +312,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
return scope->di_scope;
}
static void set_debug_source_node(CodeGen *g, AstNode *node) {
assert(node->scope);
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, get_di_scope(g, node->scope));
}
static void clear_debug_source_node(CodeGen *g) {
ZigLLVMClearCurrentDebugLocation(g->builder);
}
@ -350,24 +392,25 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr
}
}
static bool want_debug_safety_recursive(CodeGen *g, Scope *context) {
if (context->safety_set_node || !context->parent) {
return !context->safety_off;
}
context->safety_off = !want_debug_safety_recursive(g, context->parent);
context->safety_set_node = context->parent->safety_set_node;
return !context->safety_off;
}
static bool want_debug_safety(CodeGen *g, AstNode *node) {
if (g->is_release_build) {
return false;
}
return want_debug_safety_recursive(g, node->scope);
}
static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
return want_debug_safety(g, instruction->source_node);
if (g->is_release_build)
return false;
// TODO memoize
Scope *scope = instruction->scope;
while (scope) {
if (scope->node->type == NodeTypeBlock) {
ScopeBlock *block_scope = (ScopeBlock *)scope;
if (block_scope->safety_set_node)
return !block_scope->safety_off;
} else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
if (decls_scope->safety_set_node)
return !decls_scope->safety_off;
}
scope = scope->parent;
}
return true;
}
static void gen_debug_safety_crash(CodeGen *g) {
@ -388,10 +431,10 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
upper_value = nullptr;
}
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk");
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk");
LLVMBasicBlockRef lower_ok_block = upper_value ?
LLVMAppendBasicBlock(g->cur_fn->fn_value, "FirstBoundsCheckOk") : ok_block;
LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block;
LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, "");
LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block);
@ -408,7 +451,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon,
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type_non_canon,
TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val)
{
TypeTableEntry *actual_type = get_underlying_type(actual_type_non_canon);
@ -430,13 +473,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
if (actual_bits >= wanted_bits && actual_type->id == TypeTableEntryIdInt &&
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_debug_safety(g, source_node))
want_debug_safety)
{
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -464,7 +507,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
if (!want_debug_safety(g, source_node)) {
if (!want_debug_safety) {
return trunc_val;
}
LLVMValueRef orig_val;
@ -474,8 +517,8 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
}
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -502,8 +545,8 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -645,8 +688,8 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
}
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -656,11 +699,11 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
return result;
}
static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2,
TypeTableEntry *type_entry, bool exact)
{
if (want_debug_safety(g, source_node)) {
if (want_debug_safety) {
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
LLVMValueRef is_zero_bit;
if (type_entry->id == TypeTableEntryIdInt) {
@ -670,8 +713,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
} else {
zig_unreachable();
}
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");
LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -688,7 +731,7 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
assert(type_entry->id == TypeTableEntryIdInt);
if (exact) {
if (want_debug_safety(g, source_node)) {
if (want_debug_safety) {
LLVMValueRef remainder_val;
if (type_entry->data.integral.is_signed) {
remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
@ -698,8 +741,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -727,7 +770,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrBinOp op_id = bin_op_instruction->op_id;
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
AstNode *source_node = bin_op_instruction->base.source_node;
assert(op1->type_entry == op2->type_entry);
@ -801,7 +843,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
if (is_wrapping) {
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
@ -824,7 +866,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpSubWrap);
if (is_wrapping) {
return LLVMBuildSub(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
@ -842,7 +884,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
bool is_wrapping = (op_id == IrBinOpMultWrap);
if (is_wrapping) {
return LLVMBuildMul(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety(g, source_node)) {
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
@ -853,7 +895,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
case IrBinOpDiv:
return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false);
return gen_div(g, ir_want_debug_safety(g, &bin_op_instruction->base),
op1_value, op2_value, op1->type_entry, false);
case IrBinOpMod:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
@ -885,8 +928,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpErrToInt:
assert(actual_type->id == TypeTableEntryIdErrorUnion);
if (!type_has_bits(actual_type->data.error.child_type)) {
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
g->err_tag_type, wanted_type, expr_val);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
g->err_tag_type, wanted_type, expr_val);
} else {
zig_panic("TODO");
}
@ -954,7 +997,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpPointerReinterpret:
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpWidenOrShorten:
return gen_widen_or_shorten(g, cast_instruction->base.source_node, actual_type, wanted_type, expr_val);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type, wanted_type, expr_val);
case CastOpToUnknownSizeArray:
{
assert(cast_instruction->tmp_ptr);
@ -1021,8 +1065,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -1087,10 +1131,10 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntToEnum:
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type, wanted_type->data.enumeration.tag_type, expr_val);
case CastOpEnumToInt:
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type->data.enumeration.tag_type, wanted_type, expr_val);
}
zig_unreachable();
@ -1197,8 +1241,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
}
LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
LLVMPositionBuilderAtEnd(g->builder, err_block);
@ -1231,8 +1275,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, "");
}
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeNull");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull");
LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block);
LLVMPositionBuilderAtEnd(g->builder, null_block);
@ -1408,7 +1452,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
LLVMValueRef fn_val;
TypeTableEntry *fn_type;
if (instruction->fn_entry) {
fn_val = instruction->fn_entry->fn_value;
fn_val = fn_llvm_value(g, instruction->fn_entry);
fn_type = instruction->fn_entry->type_entry;
} else {
assert(instruction->fn_ref);
@ -1563,7 +1607,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
if (!is_return) {
VariableTableEntry *variable = asm_output->variable;
VariableTableEntry *variable = instruction->output_vars[i];
assert(variable);
param_types[param_index] = LLVMTypeOf(variable->value_ref);
param_values[param_index] = variable->value_ref;
@ -1638,8 +1682,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, fail_block);
@ -1730,8 +1774,18 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
}
}
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
assert(source_node);
assert(scope);
ZigLLVMSetCurrentDebugLocation(g->builder, source_node->line + 1, source_node->column + 1, get_di_scope(g, scope));
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
set_debug_location(g, instruction);
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -1961,7 +2015,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
}
case TypeTableEntryIdFn:
return const_val->data.x_fn->fn_value;
return fn_llvm_value(g, const_val->data.x_fn);
case TypeTableEntryIdPointer:
{
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
@ -2021,7 +2075,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
case TypeTableEntryIdNullLit:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
zig_unreachable();
@ -2107,7 +2160,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
LLVMValueRef name_val = LLVMConstStruct(name_fields, 2, false);
LLVMValueRef fields[] = {
name_val,
fn_entry->fn_value,
fn_llvm_value(g, fn_entry),
};
return LLVMConstStruct(fields, 2, false);
}
@ -2157,7 +2210,7 @@ static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
assert(executable->basic_block_list.length > 0);
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
IrBasicBlock *bb = executable->basic_block_list.at(block_i);
bb->llvm_block = LLVMAppendBasicBlock(fn->fn_value, bb->name_hint);
bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint);
}
IrBasicBlock *entry_bb = executable->basic_block_list.at(0);
LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
@ -2167,11 +2220,14 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini
TypeTableEntry *type_entry)
{
assert(var->gen_is_const);
assert(var->import);
assert(type_entry);
ImportTableEntry *import = get_scope_import(var->parent_scope);
assert(import);
bool is_local_to_unit = true;
ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1,
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
type_entry->di_type, is_local_to_unit, init_val);
}
@ -2187,7 +2243,7 @@ static void do_code_gen(CodeGen *g) {
if (var->type->id == TypeTableEntryIdNumLitFloat) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = g->builtin_types.entry_f64;
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
@ -2197,7 +2253,7 @@ static void do_code_gen(CodeGen *g) {
if (var->type->id == TypeTableEntryIdNumLitInt) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
@ -2222,13 +2278,12 @@ static void do_code_gen(CodeGen *g) {
LLVMSetLinkage(global_value, LLVMExternalLinkage);
} else {
IrInstruction *instruction = var->decl_node->data.variable_declaration.top_level_decl.value;
render_const_val(g, instruction->type_entry, &instruction->static_value);
render_const_val_global(g, instruction->type_entry, &instruction->static_value);
global_value = instruction->static_value.llvm_global;
render_const_val(g, var->type, var->value);
render_const_val_global(g, var->type, var->value);
global_value = var->value->llvm_global;
// TODO debug info for function pointers
if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, instruction->static_value.llvm_value, var->type);
gen_global_var(g, var, var->value->llvm_value, var->type);
}
}
@ -2246,12 +2301,8 @@ static void do_code_gen(CodeGen *g) {
// Generate function prototypes
for (size_t fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
LLVMDeleteFunction(fn_table_entry->fn_value);
fn_table_entry->fn_value = nullptr;
if (should_skip_fn_codegen(g, fn_table_entry))
continue;
}
AstNode *proto_node = fn_table_entry->proto_node;
assert(proto_node->type == NodeTypeFnProto);
@ -2259,16 +2310,18 @@ static void do_code_gen(CodeGen *g) {
TypeTableEntry *fn_type = fn_table_entry->type_entry;
LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry);
if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
// nothing to do
} else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 0);
ZigLLVMAddNonNullAttr(fn_val, 0);
} else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
!fn_type->data.fn.fn_type_id.is_extern)
{
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
LLVMValueRef first_arg = LLVMGetParam(fn_val, 0);
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1);
ZigLLVMAddNonNullAttr(fn_val, 1);
}
@ -2286,7 +2339,7 @@ static void do_code_gen(CodeGen *g) {
}
TypeTableEntry *param_type = info->type;
LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_index);
LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index);
bool param_is_noalias = param_node->data.param_decl.is_noalias;
if (param_is_noalias) {
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
@ -2295,7 +2348,7 @@ static void do_code_gen(CodeGen *g) {
LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
}
if (param_type->id == TypeTableEntryIdPointer) {
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, gen_index + 1);
ZigLLVMAddNonNullAttr(fn_val, gen_index + 1);
}
if (is_byval) {
// TODO
@ -2345,14 +2398,13 @@ static void do_code_gen(CodeGen *g) {
// Generate function definitions.
for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
if (should_skip_fn_codegen(g, fn_table_entry)) {
// huge time saver
if (should_skip_fn_codegen(g, fn_table_entry))
continue;
}
ImportTableEntry *import = fn_table_entry->import_entry;
LLVMValueRef fn = fn_table_entry->fn_value;
LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
g->cur_fn = fn_table_entry;
g->cur_fn_val = fn;
if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
g->cur_ret_ptr = LLVMGetParam(fn, 0);
} else {
@ -2401,7 +2453,18 @@ static void do_code_gen(CodeGen *g) {
if (var->is_inline)
continue;
if (var->parent_scope->node->type == NodeTypeFnDef) {
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0);
} else {
assert(var->gen_arg_index != SIZE_MAX);
TypeTableEntry *gen_type;
if (handle_is_ptr(var->type)) {
@ -2417,31 +2480,21 @@ static void do_code_gen(CodeGen *g) {
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1);
} else {
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0);
}
}
// create debug variable declarations for parameters
// rely on the first variables in the variable_list being parameters.
size_t next_var_i = 0;
for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
AstNode *param_decl = fn_proto->params.at(param_i);
assert(param_decl->type == NodeTypeParamDecl);
FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
if (info->gen_index == SIZE_MAX) {
if (info->gen_index == SIZE_MAX)
continue;
}
VariableTableEntry *variable = param_decl->data.param_decl.variable;
VariableTableEntry *variable = fn_table_entry->variable_list.at(next_var_i);
assert(variable->src_arg_index != SIZE_MAX);
next_var_i += 1;
assert(variable);
assert(variable->value_ref);
@ -3308,7 +3361,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
zig_panic("TODO");
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@ -3343,7 +3395,7 @@ void codegen_generate_h_file(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
if (fn_proto->top_level_decl.visib_mod != VisibModExport)
if (fn_proto->visib_mod != VisibModExport)
continue;
FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;

View File

@ -55,7 +55,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
zig_panic("TODO");
case TypeTableEntryIdBlock:
zig_panic("TODO");
case TypeTableEntryIdGenericFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdUnreachable:

1356
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -140,14 +140,6 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path));
return;
}
case TypeTableEntryIdGenericFn:
{
TypeTableEntry *type_entry = const_val->data.x_type;
AstNode *decl_node = type_entry->data.generic_fn.decl_node;
assert(decl_node->type == NodeTypeFnProto);
fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name));
return;
}
case TypeTableEntryIdBoundFn:
{
FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn;

View File

@ -121,7 +121,7 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char
AstNode *node = create_node(c, NodeTypeVariableDeclaration);
node->data.variable_declaration.symbol = buf_create_from_str(var_name);
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod;
node->data.variable_declaration.visib_mod = c->visib_mod;
node->data.variable_declaration.expr = init_node;
node->data.variable_declaration.type = type_node;
return node;
@ -139,16 +139,6 @@ static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node)
return node;
}
static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *type_node) {
assert(type_node);
AstNode *node = create_node(c, NodeTypeStructField);
node->data.struct_field.name = buf_create_from_str(name);
node->data.struct_field.top_level_decl.visib_mod = VisibModPub;
node->data.struct_field.type = type_node;
return node;
}
static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) {
assert(type_node);
AstNode *node = create_node(c, NodeTypeParamDecl);
@ -214,15 +204,6 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) {
return create_prefix_node(c, PrefixOpNegation, num_lit_node);
}
static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) {
AstNode *node = create_node(c, NodeTypeTypeDecl);
node->data.type_decl.symbol = buf_create_from_str(name);
node->data.type_decl.top_level_decl.visib_mod = c->visib_mod;
node->data.type_decl.child_type = child_type_node;
return node;
}
static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) {
zig_panic("TODO bypass AST in parseh");
}
@ -231,7 +212,7 @@ static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_t
assert(fn_type->id == TypeTableEntryIdFn);
AstNode *node = create_node(c, NodeTypeFnProto);
node->data.fn_proto.is_inline = true;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
node->data.fn_proto.visib_mod = c->visib_mod;
node->data.fn_proto.name = name;
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
@ -280,25 +261,40 @@ static const char *decl_name(const Decl *decl) {
return (const char *)named_decl->getName().bytes_begin();
}
static AstNode *add_typedef_node(Context *c, TypeTableEntry *type_decl) {
static void add_typedef_node(Context *c, TypeTableEntry *type_decl) {
assert(type_decl);
assert(type_decl->id == TypeTableEntryIdTypeDecl);
AstNode *node = create_type_decl_node(c, buf_ptr(&type_decl->name),
make_type_node(c, type_decl->data.type_decl.child_type));
node->data.type_decl.override_type = type_decl;
ScopeDecls *decls_scope = c->import->decls_scope;
TldTypeDef *tld_typedef = allocate<TldTypeDef>(1);
init_tld(&tld_typedef->base, TldIdTypeDef, &type_decl->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
tld_typedef->type_entry = type_decl;
decls_scope->decl_table.put(&type_decl->name, &tld_typedef->base);
c->global_type_table.put(&type_decl->name, type_decl);
c->root->data.root.top_level_decls.append(node);
return node;
}
static AstNode *add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) {
AstNode *node = create_var_decl_node(c, buf_ptr(name), make_type_node(c, type_entry));
static void add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) {
ScopeDecls *decls_scope = c->import->decls_scope;
TldVar *tld_var = allocate<TldVar>(1);
init_tld(&tld_var->base, TldIdVar, name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
bool is_const = true;
ConstExprValue *init_value = allocate<ConstExprValue>(1);
init_value->special = ConstValSpecialStatic;
init_value->data.x_type = type_entry;
tld_var->var = add_variable(c->codegen, c->source_node, &decls_scope->base, name, type_entry, is_const, init_value);
decls_scope->decl_table.put(name, &tld_var->base);
c->global_type_table.put(name, type_entry);
c->root->data.root.top_level_decls.append(node);
return node;
}
static void add_container_tld(Context *c, TypeTableEntry *type_entry) {
ScopeDecls *decls_scope = c->import->decls_scope;
TldContainer *tld_container = allocate<TldContainer>(1);
init_tld(&tld_container->base, TldIdContainer, &type_entry->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
tld_container->type_entry = type_entry;
decls_scope->decl_table.put(&type_entry->name, &tld_container->base);
}
static AstNode *create_ap_num_lit_node(Context *c, const Decl *source_decl,
@ -617,7 +613,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
param_info->is_noalias = qt.isRestrictQualified();
}
return get_fn_type(c->codegen, &fn_type_id, true);
return get_fn_type(c->codegen, &fn_type_id);
}
case Type::Record:
{
@ -724,7 +720,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
node->data.fn_proto.name = fn_name;
node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
node->data.fn_proto.visib_mod = c->visib_mod;
node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
@ -939,9 +935,8 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
TypeTableEntry *enum_type = resolve_enum_decl(c, enum_decl);
if (enum_type->id == TypeTableEntryIdInvalid) {
if (enum_type->id == TypeTableEntryIdInvalid)
return;
}
// make an alias without the "enum_" prefix. this will get emitted at the
// end if it doesn't conflict with anything else
@ -951,21 +946,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
if (enum_type->id == TypeTableEntryIdEnum) {
if (enum_type->data.enumeration.complete) {
// now create top level decl for the type
AstNode *enum_node = create_node(c, NodeTypeContainerDecl);
enum_node->data.struct_decl.name = &enum_type->name;
enum_node->data.struct_decl.kind = ContainerKindEnum;
enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
enum_node->data.struct_decl.type_entry = enum_type;
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
AstNode *type_node = make_type_node(c, type_enum_field->type_entry);
AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node);
enum_node->data.struct_decl.fields.append(field_node);
}
c->root->data.root.top_level_decls.append(enum_node);
add_container_tld(c, enum_type);
} else {
TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&enum_type->name),
c->codegen->builtin_types.entry_u8);
@ -1127,21 +1108,7 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
}
if (struct_type->data.structure.complete) {
// now create a top level decl node for the type
AstNode *struct_node = create_node(c, NodeTypeContainerDecl);
struct_node->data.struct_decl.name = &struct_type->name;
struct_node->data.struct_decl.kind = ContainerKindStruct;
struct_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
struct_node->data.struct_decl.type_entry = struct_type;
for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
struct_node->data.struct_decl.fields.append(field_node);
}
c->root->data.root.top_level_decls.append(struct_node);
add_container_tld(c, struct_type);
} else {
TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name),
c->codegen->builtin_types.entry_u8);

View File

@ -1501,7 +1501,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
node->data.variable_declaration.is_inline = is_inline;
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = visib_mod;
node->data.variable_declaration.visib_mod = visib_mod;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.variable_declaration.symbol = token_buf(name_token);
@ -2079,7 +2079,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
}
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
node->data.fn_proto.top_level_decl.visib_mod = visib_mod;
node->data.fn_proto.visib_mod = visib_mod;
node->data.fn_proto.is_coldcc = is_coldcc;
node->data.fn_proto.is_nakedcc = is_nakedcc;
@ -2144,6 +2144,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
AstNode *node = ast_create_node(pc, NodeTypeFnDef, first_token);
node->data.fn_def.fn_proto = fn_proto;
node->data.fn_def.body = ast_parse_block(pc, token_index, true);
fn_proto->data.fn_proto.fn_def_node = node;
return node;
}
@ -2193,7 +2194,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
node->data.use.top_level_decl.visib_mod = visib_mod;
node->data.use.visib_mod = visib_mod;
node->data.use.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdSemicolon);
@ -2227,7 +2228,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
node->data.struct_decl.kind = kind;
node->data.struct_decl.name = token_buf(struct_name);
node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
node->data.struct_decl.visib_mod = visib_mod;
Token *paren_or_brace = &pc->tokens->at(*token_index);
if (paren_or_brace->id == TokenIdLParen) {
@ -2281,7 +2282,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod;
field_node->data.struct_field.visib_mod = visib_mod;
field_node->data.struct_field.name = token_buf(token);
Token *expr_or_comma = &pc->tokens->at(*token_index);
@ -2318,7 +2319,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index
ast_eat_token(pc, token_index, TokenIdSemicolon);
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
node->data.error_value_decl.top_level_decl.visib_mod = visib_mod;
node->data.error_value_decl.visib_mod = visib_mod;
node->data.error_value_decl.name = token_buf(name_tok);
return node;
@ -2344,7 +2345,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, Visib
ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.type_decl.top_level_decl.visib_mod = visib_mod;
node->data.type_decl.visib_mod = visib_mod;
return node;
}