Browse Source

Add `optimization_mode` attribute for procedures

Allowed modes: "none", "minimal", "size", "speed"
Currently: none == minimal and size == speed
gingerBill 4 years ago
parent
commit
65551ba8fb
5 changed files with 67 additions and 4 deletions
  1. 12 0
      src/check_decl.cpp
  2. 23 0
      src/checker.cpp
  3. 1 0
      src/checker.hpp
  4. 9 0
      src/entity.cpp
  5. 22 4
      src/llvm_backend.cpp

+ 12 - 0
src/check_decl.cpp

@@ -707,6 +707,18 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		e->flags |= EntityFlag_Cold;
 		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->Procedure.is_export = ac.is_export;
 	e->deprecated_message = ac.deprecated_message;
 	e->deprecated_message = ac.deprecated_message;
 	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
 	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);

+ 23 - 0
src/checker.cpp

@@ -2572,6 +2572,29 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 			}
 			}
 		}
 		}
 		return true;
 		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;
 	return false;
 }
 }

+ 1 - 0
src/checker.hpp

@@ -112,6 +112,7 @@ struct AttributeContext {
 	String  thread_local_model;
 	String  thread_local_model;
 	String  deprecated_message;
 	String  deprecated_message;
 	DeferredProcedure deferred_procedure;
 	DeferredProcedure deferred_procedure;
+	u32 optimization_mode; // ProcedureOptimizationMode
 	struct TypeAtomOpTable *atom_op_table;
 	struct TypeAtomOpTable *atom_op_table;
 };
 };
 
 

+ 9 - 0
src/entity.cpp

@@ -99,6 +99,14 @@ enum EntityConstantFlags : u32 {
 	EntityConstantFlag_ImplicitEnumValue = 1<<0,
 	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
 // An Entity is a named "thing" in the language
 struct Entity {
 struct Entity {
 	EntityKind  kind;
 	EntityKind  kind;
@@ -165,6 +173,7 @@ struct Entity {
 			DeferredProcedure deferred_procedure;
 			DeferredProcedure deferred_procedure;
 			bool    is_foreign;
 			bool    is_foreign;
 			bool    is_export;
 			bool    is_export;
+			ProcedureOptimizationMode optimization_mode;
 		} Procedure;
 		} Procedure;
 		struct {
 		struct {
 			Array<Entity *> entities;
 			Array<Entity *> entities;

+ 22 - 4
src/llvm_backend.cpp

@@ -2523,7 +2523,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 	p->type           = entity->type;
 	p->type           = entity->type;
 	p->type_expr      = decl->type_expr;
 	p->type_expr      = decl->type_expr;
 	p->body           = pl->body;
 	p->body           = pl->body;
-	p->inlining       = ProcInlining_none;
+	p->inlining       = pl->inlining;
 	p->is_foreign     = entity->Procedure.is_foreign;
 	p->is_foreign     = entity->Procedure.is_foreign;
 	p->is_export      = entity->Procedure.is_export;
 	p->is_export      = entity->Procedure.is_export;
 	p->is_entry_point = false;
 	p->is_entry_point = false;
@@ -2558,9 +2558,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 		LLVMSetFunctionCallConv(p->value, cc_kind);
 		LLVMSetFunctionCallConv(p->value, cc_kind);
 	}
 	}
 
 
-	if (entity->flags & EntityFlag_Cold) {
-		lb_add_attribute_to_proc(m, p->value, "cold");
-	}
 
 
 	if (pt->Proc.diverging) {
 	if (pt->Proc.diverging) {
 		lb_add_attribute_to_proc(m, p->value, "noreturn");
 		lb_add_attribute_to_proc(m, p->value, "noreturn");
@@ -2575,6 +2572,27 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 		break;
 		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;
 	// lbCallingConventionKind cc_kind = lbCallingConvention_C;
 	// // TODO(bill): Clean up this logic
 	// // TODO(bill): Clean up this logic
 	// if (build_context.metrics.os != TargetOs_js)  {
 	// if (build_context.metrics.os != TargetOs_js)  {