Skip to content

Commit

Permalink
More aggressive DCE, remove unused globals/constants
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafaquraish committed Nov 8, 2024
1 parent 8d2abc4 commit d4e21dc
Show file tree
Hide file tree
Showing 22 changed files with 4,674 additions and 4,426 deletions.
8,771 changes: 4,479 additions & 4,292 deletions bootstrap/stage0.c

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions compiler/ast/nodes.oc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ struct Variable {

//* Original parsed type, for keeping track of locations
parsed_type: &Type

is_dead: bool
}

def Variable::new(type: &Type): &Variable {
Expand All @@ -75,11 +77,6 @@ def Variable::new(type: &Type): &Variable {
return var
}

struct VarDeclaration {
var: &Variable
init: &AST
}

struct Structure {
sym: &Symbol
fields: &Vector<&Variable>
Expand Down Expand Up @@ -475,7 +472,7 @@ union ASTUnion {
char_literal: str
unary: Unary
operator_span: Span
var_decl: VarDeclaration
var_decl: &Variable
fmt_str: FormatString
size_of_type: &Type
match_stmt: Match
Expand Down
13 changes: 9 additions & 4 deletions compiler/ast/program.oc
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ def Namespace::dump(&this) {
}
println(f" Constants:")
for c in .constants.iter() {
println(f" - {c.u.var_decl.var.sym.display}")
println(f" - {c.u.var_decl.sym.display}")
}
println(f" Variables:")
for v in .variables.iter() {
println(f" - {v.u.var_decl.var.sym.display}")
println(f" - {v.u.var_decl.sym.display}")
}
println(f" Typedefs:")
for td in .typedefs.iter() {
Expand All @@ -111,12 +111,12 @@ def Namespace::find_importable_symbol(&this, name: str): &Symbol {
if item? then return item.sym

for node : .constants.iter() {
let var = node.u.var_decl.var
let var = node.u.var_decl
if var.sym.name.eq(name) return var.sym
}

for node : .variables.iter() {
let var = node.u.var_decl.var
let var = node.u.var_decl
if var.sym.name.eq(name) return var.sym
}

Expand Down Expand Up @@ -176,12 +176,16 @@ struct Program {
error_level: u32

cached_symbols: CachedSymbols
did_cache_symbols: bool
err_jmp_stack: &Vector<ErrorContext>

explicit_alive_symbols: &Vector<&Symbol>

// Configs
check_doc_links: bool
gen_debug_info: bool
keep_all_code: bool
include_stdlib: bool
}

def Program::new(): &Program {
Expand All @@ -207,6 +211,7 @@ def Program::new(): &Program {
prog.library_paths = Vector<str>::new()
prog.operator_overloads = Map<OperatorOverload, &Function>::new()
prog.err_jmp_stack = Vector<ErrorContext>::new()
prog.explicit_alive_symbols = Vector<&Symbol>::new()
return prog
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/attributes.oc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum AttributeType {
Formatting // [formatting <specifiers> <args>] to specify formatting for an object
Operator // [operator <op>] to specify an operator overload
Atomic // [atomic] to mark a type as Atomic
Alive // [alive] to explicitly mark a function as not dead

Invalid // used for error reporting
}
Expand All @@ -32,6 +33,7 @@ def AttributeType::from_str(s: str): AttributeType => match s {
"formatting" => Formatting
"operator" => Operator
"atomic" => Atomic
"alive" => Alive
else => Invalid
}

Expand Down Expand Up @@ -95,11 +97,11 @@ def Attribute::validate(&this, parser_for_errors: &Parser): bool {
.args.push("$")
}
}
Exits | VariadicFormat | Export | Atomic => {
Exits | VariadicFormat | Export | Atomic | Alive => {
if .args.size > 0 {
parser_for_errors.error(Error::new(
this.span,
"Exits attribute takes no arguments"
f"{.type} attribute takes no arguments"
))
return false
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/docgen.oc
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def DocGenerator::gen_ns(&this, ns: &Namespace): &Value {
if not ns.variables.is_empty() {
let vars_doc = Value::new(Dictionary)
for node : ns.variables.iter() {
let var = node.u.var_decl.var
let var = node.u.var_decl
let var_doc = Value::new(Dictionary)
var_doc["id"] = `{var:x}`
if var.sym.comment? {
Expand All @@ -355,7 +355,7 @@ def DocGenerator::gen_ns(&this, ns: &Namespace): &Value {
if not ns.constants.is_empty() {
let consts_doc = Value::new(Dictionary)
for node : ns.constants.iter() {
let var = node.u.var_decl.var
let var = node.u.var_decl
let const_doc = Value::new(Dictionary)
const_doc["id"] = `{var:x}`
if var.sym.comment? {
Expand Down
27 changes: 13 additions & 14 deletions compiler/lsp/finder.oc
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,22 @@ def Finder::find_signature_help(&this, node: &AST, args: &Vector<&Argument>, par
let func = node.u.call.callee.resolved_symbol
if not func? return false

let func_sym = match func.type {
Function => func.u.func.sym
Structure => func.u.struc.sym
else => {
return false
}
}
let params = match func.type {
Function => func.u.func.params
Structure => func.u.struc.fields
Variable => {
let var_type = func.u.var.type
if not var_type? or var_type.base != Function return false
yield func.u.var.type.u.func.params
}
else => {
return false
}
}

if param_idx > params.size return false

// TODO: Highlight correct arg based on label? We now allow unordered arguments
if {
(param_idx == 0) => {
let open_paren_span = node.u.call.open_paren_span
Expand Down Expand Up @@ -329,9 +328,9 @@ def Finder::find_in_statement(&this, node: &AST): bool {
if loop.body? and .find_in_statement(loop.body) return true
}
VarDeclaration => {
let decl = &node.u.var_decl
if decl.var? and .find_in_var(decl.var, node) return true
if decl.init? and .find_in_expression(decl.init) return true
let decl = node.u.var_decl
if decl? and .find_in_var(decl, node) return true
if decl.default_value? and .find_in_expression(decl.default_value) return true
}
Block => return .find_in_block(node)
Return => return node.u.ret.expr? and .find_in_expression(node.u.ret.expr)
Expand Down Expand Up @@ -461,18 +460,18 @@ def Finder::find_in_program(&this, ns: &Namespace): bool {
}

for vardecl in ns.variables.iter() {
let var = vardecl.u.var_decl.var
let var = vardecl.u.var_decl
if var.sym.span.contains_loc(.loc) return .set_usage(var.sym, node: null)

let init = vardecl.u.var_decl.init
let init = vardecl.u.var_decl.default_value
if init? and .find_in_expression(init) return true
}

for vardecl in ns.constants.iter() {
let var = vardecl.u.var_decl.var
let var = vardecl.u.var_decl
if var.sym.span.contains_loc(.loc) return .set_usage(var.sym, node: null)

let init = vardecl.u.var_decl.init
let init = vardecl.u.var_decl.default_value
if init? and .find_in_expression(init) return true
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/lsp/mod.oc
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,16 @@ def lsp_main(argc: i32, argv: &str) {
// Load the program
let program = Program::new()
program.setup_library_paths()
// Always try to load stdlib for LSP
program.include_stdlib = true

let contents = fs::read_file(file_path).str()
// For references and renames we want to look at all files in the workspace
let include_workspace_main = match cmd_type {
References | Renames => true
else => false
}
Parser::parse_toplevel(program, show_path, true, contents, include_workspace_main)
Parser::parse_toplevel(program, show_path, contents, include_workspace_main)

match cmd_type {
DocumentSymbols => handle_document_symbols(program, show_path)
Expand Down
13 changes: 11 additions & 2 deletions compiler/lsp/utils.oc
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,11 @@ def gen_namespace_json(ns: &Namespace): &Value {
}

for var : ns.variables.iter() {
children += gen_variable_json(var.u.var_decl.var)
children += gen_variable_json(var.u.var_decl)
}

for var : ns.constants.iter() {
children += gen_variable_json(var.u.var_decl.var)
children += gen_variable_json(var.u.var_decl)
}

for func : ns.functions.iter() {
Expand Down Expand Up @@ -477,6 +477,15 @@ def gen_signature_help(node: &AST, active_param: u32): &Value {
is_non_static_method = func.is_method and not func.is_static
yield func.params
}
Variable => {
let var = callee_sym.u.var
if var.type.base != Function {
if verbose then println(f"gen_signature_help: variable is not a function: {var.type}")
return obj
}
obj["label"] = gen_type_string(var.type)
yield var.type.u.func.params
}
Structure => {
let struc = callee_sym.u.struc
let struc_func_label = Buffer::make()
Expand Down
3 changes: 2 additions & 1 deletion compiler/main.oc
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ def main(argc: i32, argv: &str) {

program.error_level = error_level
program.gen_debug_info = debug
Parser::parse_toplevel(program, filename, include_stdlib, null, include_workspace_main: true)
program.include_stdlib = include_stdlib
Parser::parse_toplevel(program, filename, file_contents: null, include_workspace_main: true)

run_typecheck_passes(program)

Expand Down
30 changes: 16 additions & 14 deletions compiler/parser.oc
Original file line number Diff line number Diff line change
Expand Up @@ -637,9 +637,9 @@ def Parser::parse_var_declaration(&this): &AST {

let var = Variable::new(type)
var.sym = Symbol::from_local_variable(name.text, var, name.span)
var.default_value = init

node.u.var_decl.var = var
node.u.var_decl.init = init
node.u.var_decl = var
return node
}

Expand Down Expand Up @@ -679,13 +679,12 @@ def Parser::parse_global_value(&this, is_const: bool): &AST {
}
}

node.u.var_decl.var = var

node.u.var_decl = var
if .consume_if(TokenType::Equals) {
if is_const {
node.u.var_decl.init = .parse_expression(end_type: TokenType::Newline)
var.default_value = .parse_expression(end_type: TokenType::Newline)
} else {
node.u.var_decl.init = .parse_var_initializer()
var.default_value = .parse_var_initializer()
}
}
.consume_newline_or(TokenType::Semicolon)
Expand Down Expand Up @@ -1256,10 +1255,9 @@ def Parser::parse_for_each(&this, start_span: Span): &AST {
let node = AST::new(VarDeclaration, start_span)
let var = Variable::new(null)
var.sym = Symbol::from_local_variable(iter_var_name, var, start_span)
var.default_value = expr

node.u.var_decl.var = var
node.u.var_decl.init = expr

node.u.var_decl = var
yield node
}

Expand Down Expand Up @@ -1317,9 +1315,8 @@ def Parser::parse_for_each(&this, start_span: Span): &AST {
call.u.call.close_paren_span = name.span

let node = AST::new(VarDeclaration, start_span)
node.u.var_decl.var = var
node.u.var_decl.init = call

var.default_value = call
node.u.var_decl = var
yield node
}

Expand Down Expand Up @@ -1669,6 +1666,7 @@ def Parser::parse_function(&this): &Function {
}
func.operator_overloads.push(op)
}
Alive => .program.explicit_alive_symbols.push(func.sym)
else => .error(Error::new(attr.span, f"Invalid attribute for function: {attr.type}"))
}
}
Expand Down Expand Up @@ -2545,6 +2543,10 @@ def Parser::include_prelude_only(&this) {
//! consider it a project, and load the file as such. If we don't, we consider it a standalone file.
//! In the future, we need to add flags to the compiler to be able to specify this.
def Parser::create_namespaces_for_initial_file(&this, filename: str, single_file: bool) {
if not .program.include_stdlib {
.include_prelude_only()
return
}

// NOTE: We currently special-case the standard library path, since it's also a "project root"
// for the standard library. We want to do this for all external libraries in the future, and have
Expand Down Expand Up @@ -2650,7 +2652,7 @@ def Parser::create_namespaces_for_initial_file(&this, filename: str, single_file
.ns = child_ns
}

def Parser::parse_toplevel(program: &Program, filename: str, include_stdlib: bool, file_contents: str = null, include_workspace_main: bool = true) {
def Parser::parse_toplevel(program: &Program, filename: str, file_contents: str = null, include_workspace_main: bool = true) {
// Fallback for any unhandled errors...
let ctx = program.add_error_context()
if ctx.set_jump_point() > 0 {
Expand All @@ -2659,7 +2661,7 @@ def Parser::parse_toplevel(program: &Program, filename: str, include_stdlib: boo
}

let parser = Parser::make(program, program.global)
if include_stdlib {
if program.include_stdlib {
parser.find_and_import_stdlib()
} else {
parser.include_prelude_only()
Expand Down
Loading

0 comments on commit d4e21dc

Please sign in to comment.