diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 498cde196..e74504a1a 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -707,6 +707,18 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { e->flags |= EntityFlag_Cold; } + e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode; + + + switch (e->Procedure.optimization_mode) { + case ProcedureOptimizationMode_None: + case ProcedureOptimizationMode_Minimal: + if (pl->inlining == ProcInlining_inline) { + error(e->token, "#force_inline cannot be used in conjunction with the attribute 'optimization_mode' with neither \"none\" nor \"minimal\""); + } + break; + } + e->Procedure.is_export = ac.is_export; e->deprecated_message = ac.deprecated_message; ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); diff --git a/src/checker.cpp b/src/checker.cpp index 9233ad61e..10376b149 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2572,6 +2572,29 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } } return true; + } else if (name == "optimization_mode") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + String mode = ev.value_string; + if (mode == "none") { + ac->optimization_mode = ProcedureOptimizationMode_None; + } else if (mode == "minimal") { + ac->optimization_mode = ProcedureOptimizationMode_Minimal; + } else if (mode == "size") { + ac->optimization_mode = ProcedureOptimizationMode_Size; + } else if (mode == "speed") { + ac->optimization_mode = ProcedureOptimizationMode_Speed; + } else { + error(elem, "Invalid optimization_mode for '%.*s'. Valid modes:", LIT(name)); + error_line("\tnone\n"); + error_line("\tminimal\n"); + error_line("\tsize\n"); + error_line("\tspeed\n"); + } + } else { + error(elem, "Expected a string for '%.*s'", LIT(name)); + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index fe6fb1585..76c528dfb 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -112,6 +112,7 @@ struct AttributeContext { String thread_local_model; String deprecated_message; DeferredProcedure deferred_procedure; + u32 optimization_mode; // ProcedureOptimizationMode struct TypeAtomOpTable *atom_op_table; }; diff --git a/src/entity.cpp b/src/entity.cpp index 633576e25..d1f4c78e6 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -99,6 +99,14 @@ enum EntityConstantFlags : u32 { EntityConstantFlag_ImplicitEnumValue = 1<<0, }; +enum ProcedureOptimizationMode : u32 { + ProcedureOptimizationMode_Default, + ProcedureOptimizationMode_None, + ProcedureOptimizationMode_Minimal, + ProcedureOptimizationMode_Size, + ProcedureOptimizationMode_Speed, +}; + // An Entity is a named "thing" in the language struct Entity { EntityKind kind; @@ -165,6 +173,7 @@ struct Entity { DeferredProcedure deferred_procedure; bool is_foreign; bool is_export; + ProcedureOptimizationMode optimization_mode; } Procedure; struct { Array entities; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1a4e5db55..fc29be59c 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2523,7 +2523,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { p->type = entity->type; p->type_expr = decl->type_expr; p->body = pl->body; - p->inlining = ProcInlining_none; + p->inlining = pl->inlining; p->is_foreign = entity->Procedure.is_foreign; p->is_export = entity->Procedure.is_export; p->is_entry_point = false; @@ -2558,9 +2558,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { LLVMSetFunctionCallConv(p->value, cc_kind); } - if (entity->flags & EntityFlag_Cold) { - lb_add_attribute_to_proc(m, p->value, "cold"); - } if (pt->Proc.diverging) { lb_add_attribute_to_proc(m, p->value, "noreturn"); @@ -2575,6 +2572,27 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { break; } + if (entity->flags & EntityFlag_Cold) { + lb_add_attribute_to_proc(m, p->value, "cold"); + } + + switch (entity->Procedure.optimization_mode) { + case ProcedureOptimizationMode_None: + lb_add_attribute_to_proc(m, p->value, "optnone"); + break; + case ProcedureOptimizationMode_Minimal: + lb_add_attribute_to_proc(m, p->value, "optnone"); + break; + case ProcedureOptimizationMode_Size: + lb_add_attribute_to_proc(m, p->value, "optsize"); + break; + case ProcedureOptimizationMode_Speed: + // TODO(bill): handle this correctly + lb_add_attribute_to_proc(m, p->value, "optsize"); + break; + } + + // lbCallingConventionKind cc_kind = lbCallingConvention_C; // // TODO(bill): Clean up this logic // if (build_context.metrics.os != TargetOs_js) {