diff options
| author | gingerBill <bill@gingerbill.org> | 2022-05-30 14:53:12 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-05-30 14:53:12 +0100 |
| commit | f3aefbc4434b92fc3fda74c942c953b08dd18a62 (patch) | |
| tree | d13281680a7cd14ce92630cb9d3a49c984b2a888 /src | |
| parent | cef022539ebd41a4a80707f1a702e09e6748ade0 (diff) | |
`@(require_target_feature=<string>)` `@(enable_target_feature=<string>)`
require_target_feature - required by the target micro-architecture
enable_target_feature - will be enabled for the specified procedure only
Diffstat (limited to 'src')
| -rw-r--r-- | src/build_settings.cpp | 109 | ||||
| -rw-r--r-- | src/check_decl.cpp | 12 | ||||
| -rw-r--r-- | src/checker.cpp | 16 | ||||
| -rw-r--r-- | src/checker.hpp | 3 | ||||
| -rw-r--r-- | src/entity.cpp | 8 | ||||
| -rw-r--r-- | src/llvm_backend.cpp | 4 | ||||
| -rw-r--r-- | src/llvm_backend_proc.cpp | 13 | ||||
| -rw-r--r-- | src/main.cpp | 4 | ||||
| -rw-r--r-- | src/string.cpp | 9 |
9 files changed, 169 insertions, 9 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 27e09a0db..65470749f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -256,7 +256,6 @@ struct BuildContext { String extra_linker_flags; String extra_assembler_flags; String microarch; - String target_features; BuildModeKind build_mode; bool generate_docs; i32 optimization_level; @@ -320,6 +319,10 @@ struct BuildContext { PtrMap<char const *, ExactValue> defined_values; + BlockingMutex target_features_mutex; + StringSet target_features_set; + String target_features_string; + }; gb_global BuildContext build_context = {0}; @@ -1197,6 +1200,100 @@ void init_build_context(TargetMetrics *cross_target) { #include "microsoft_craziness.h" #endif + +Array<String> split_by_comma(String const &list) { + isize n = 1; + for (isize i = 0; i < list.len; i++) { + if (list.text[i] == ',') { + n++; + } + } + auto res = array_make<String>(heap_allocator(), n); + + String s = list; + for (isize i = 0; i < n; i++) { + isize m = string_index_byte(s, ','); + if (m < 0) { + res[i] = s; + break; + } + res[i] = substring(s, 0, m); + s = substring(s, m+1, s.len); + } + return res; +} + +bool check_target_feature_is_valid(TokenPos pos, String const &feature) { + // TODO(bill): check_target_feature_is_valid + return true; +} + +bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) { + BuildContext *bc = &build_context; + mutex_lock(&bc->target_features_mutex); + defer (mutex_unlock(&bc->target_features_mutex)); + + auto items = split_by_comma(target_feature_list); + array_free(&items); + for_array(i, items) { + String const &item = items.data[i]; + if (!check_target_feature_is_valid(pos, item)) { + error(pos, "Target feature '%.*s' is not valid", LIT(item)); + return false; + } + if (!string_set_exists(&bc->target_features_set, item)) { + error(pos, "Target feature '%.*s' is not enabled", LIT(item)); + return false; + } + } + + return true; +} + +void enable_target_feature(TokenPos pos, String const &target_feature_list) { + BuildContext *bc = &build_context; + mutex_lock(&bc->target_features_mutex); + defer (mutex_unlock(&bc->target_features_mutex)); + + auto items = split_by_comma(target_feature_list); + array_free(&items); + for_array(i, items) { + String const &item = items.data[i]; + if (!check_target_feature_is_valid(pos, item)) { + error(pos, "Target feature '%.*s' is not valid", LIT(item)); + } + } +} + + +char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) { + isize len = 0; + for_array(i, build_context.target_features_set.entries) { + if (i != 0) { + len += 1; + } + String feature = build_context.target_features_set.entries[i].value; + len += feature.len; + if (with_quotes) len += 2; + } + char *features = gb_alloc_array(allocator, char, len+1); + len = 0; + for_array(i, build_context.target_features_set.entries) { + if (i != 0) { + features[len++] = ','; + } + + if (with_quotes) features[len++] = '"'; + String feature = build_context.target_features_set.entries[i].value; + gb_memmove(features, feature.text, feature.len); + len += feature.len; + if (with_quotes) features[len++] = '"'; + } + features[len++] = 0; + + return features; +} + // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. // We've previously called `parse_build_flags`, so `out_filepath` should be set. bool init_build_paths(String init_filename) { @@ -1206,6 +1303,9 @@ bool init_build_paths(String init_filename) { // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); + string_set_init(&bc->target_features_set, heap_allocator(), 1024); + mutex_init(&bc->target_features_mutex); + // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); @@ -1382,5 +1482,10 @@ bool init_build_paths(String init_filename) { return false; } + if (bc->target_features_string.len != 0) { + enable_target_feature({}, bc->target_features_string); + } + return true; -}
\ No newline at end of file +} + diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 62a1e2555..d4818892b 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -899,6 +899,18 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } + if (ac.require_target_feature.len != 0 && ac.enable_target_feature.len != 0) { + error(e->token, "Attributes @(require_target_feature=...) and @(enable_target_feature=...) cannot be used together"); + } else if (ac.require_target_feature.len != 0) { + if (check_target_feature_is_enabled(e->token.pos, ac.require_target_feature)) { + e->Procedure.target_feature = ac.require_target_feature; + } else { + e->Procedure.target_feature_disabled = true; + } + } else if (ac.enable_target_feature.len != 0) { + enable_target_feature(e->token.pos, ac.enable_target_feature); + e->Procedure.target_feature = ac.enable_target_feature; + } switch (e->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: diff --git a/src/checker.cpp b/src/checker.cpp index 8afc6eb14..874839ece 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3207,6 +3207,22 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } } return true; + } else if (name == "require_target_feature") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + ac->require_target_feature = ev.value_string; + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "enable_target_feature") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + ac->enable_target_feature = ev.value_string; + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index 1c9ffd8c7..8fc9e54c8 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -124,6 +124,9 @@ struct AttributeContext { String objc_name; bool objc_is_class_method; Type * objc_type; + + String require_target_feature; // required by the target micro-architecture + String enable_target_feature; // will be enabled for the procedure only }; AttributeContext make_attribute_context(String link_prefix) { diff --git a/src/entity.cpp b/src/entity.cpp index 904a630fb..76e6912b9 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -233,10 +233,12 @@ struct Entity { String link_name; String link_prefix; DeferredProcedure deferred_procedure; - bool is_foreign; - bool is_export; - bool generated_from_polymorphic; ProcedureOptimizationMode optimization_mode; + bool is_foreign : 1; + bool is_export : 1; + bool generated_from_polymorphic : 1; + bool target_feature_disabled : 1; + String target_feature; } Procedure; struct { Array<Entity *> entities; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7cf588853..cf7389ec1 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1332,8 +1332,8 @@ void lb_generate_code(lbGenerator *gen) { } } - if (build_context.target_features.len != 0) { - llvm_features = alloc_cstring(permanent_allocator(), build_context.target_features); + if (build_context.target_features_set.entries.count != 0) { + llvm_features = target_features_set_to_cstring(permanent_allocator(), false); } // GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target)); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 1e3591bf1..296a7fa6b 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -169,6 +169,19 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) } } + if (!entity->Procedure.target_feature_disabled && + entity->Procedure.target_feature.len != 0) { + auto features = split_by_comma(entity->Procedure.target_feature); + for_array(i, features) { + String feature = features[i]; + LLVMAttributeRef ref = LLVMCreateStringAttribute( + m->ctx, + cast(char const *)feature.text, cast(unsigned)feature.len, + "", 0); + LLVMAddAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, ref); + } + } + if (entity->flags & EntityFlag_Cold) { lb_add_attribute_to_proc(m, p->value, "cold"); } diff --git a/src/main.cpp b/src/main.cpp index 13c8bd74d..ee71b91df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1376,8 +1376,8 @@ bool parse_build_flags(Array<String> args) { } case BuildFlag_TargetFeatures: { GB_ASSERT(value.kind == ExactValue_String); - build_context.target_features = value.value_string; - string_to_lower(&build_context.target_features); + build_context.target_features_string = value.value_string; + string_to_lower(&build_context.target_features_string); break; } case BuildFlag_RelocMode: { diff --git a/src/string.cpp b/src/string.cpp index 616761265..44eccd2d2 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -157,6 +157,15 @@ int string_compare(String const &x, String const &y) { return 0; } +isize string_index_byte(String const &s, u8 x) { + for (isize i = 0; i < s.len; i++) { + if (s.text[i] == x) { + return i; + } + } + return -1; +} + GB_COMPARE_PROC(string_cmp_proc) { String x = *(String *)a; String y = *(String *)b; |