Browse Source

Improve `wasm-import` semantics to allow procedures from different import paths

gingerBill 3 years ago
parent
commit
c5cd97dd89
5 changed files with 66 additions and 30 deletions
  1. 2 0
      src/build_settings.cpp
  2. 25 4
      src/check_decl.cpp
  3. 4 8
      src/llvm_backend.cpp
  4. 2 18
      src/llvm_backend_proc.cpp
  5. 33 0
      src/llvm_backend_utility.cpp

+ 2 - 0
src/build_settings.cpp

@@ -516,6 +516,8 @@ bool allow_check_foreign_filepath(void) {
 String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
 String const NIX_SEPARATOR_STRING   = {cast(u8 *)"/",  1};
 
+String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
+
 String internal_odin_root_dir(void);
 String odin_root_dir(void) {
 	if (global_module_path_set) {

+ 25 - 4
src/check_decl.cpp

@@ -594,7 +594,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
 	return true;
 }
 
-void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
+Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
 	Ast *ident = nullptr;
 	Entity **foreign_library = nullptr;
 
@@ -608,7 +608,7 @@ void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
 		foreign_library = &e->Variable.foreign_library;
 		break;
 	default:
-		return;
+		return nullptr;
 	}
 
 	if (ident == nullptr) {
@@ -631,8 +631,10 @@ void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
 			*foreign_library = found;
 			found->flags |= EntityFlag_Used;
 			add_entity_use(ctx, ident, found);
+			return found;
 		}
 	}
+	return nullptr;
 }
 
 String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
@@ -836,11 +838,27 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		if (e->Procedure.link_name.len > 0) {
 			name = e->Procedure.link_name;
 		}
+		Entity *foreign_library = init_entity_foreign_library(ctx, e);
+		
+		if (is_arch_wasm()) {
+			String module_name = str_lit("env");
+			if (foreign_library != nullptr) {
+				GB_ASSERT (foreign_library->kind == Entity_LibraryName);
+				if (foreign_library->LibraryName.paths.count != 1) {
+					error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", 
+					      LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
+				}
+				
+				if (foreign_library->LibraryName.paths.count >= 1) {
+					module_name = foreign_library->LibraryName.paths[0];
+				}
+			}
+			name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
+		}
+		
 		e->Procedure.is_foreign = true;
 		e->Procedure.link_name = name;
 
-		init_entity_foreign_library(ctx, e);
-
 		mutex_lock(&ctx->info->foreign_mutex);
 
 		auto *fp = &ctx->info->foreigns;
@@ -962,6 +980,9 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
 			error(e->token, "A foreign variable declaration cannot have a default value");
 		}
 		init_entity_foreign_library(ctx, e);
+		if (is_arch_wasm()) {
+			error(e->token, "A foreign variable declaration are not allowed for the '%.*s' architecture", LIT(target_arch_names[build_context.metrics.arch]));
+		}
 	}
 	if (ac.link_name.len > 0) {
 		e->Variable.link_name = ac.link_name;

+ 4 - 8
src/llvm_backend.cpp

@@ -895,15 +895,9 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 	lb_end_procedure_body(p);
 	
 
+	LLVMSetLinkage(p->value, LLVMExternalLinkage);
 	if (is_arch_wasm()) {
-		LLVMSetLinkage(p->value, LLVMDLLExportLinkage);
-		LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass);
-		LLVMSetVisibility(p->value, LLVMDefaultVisibility);
-		
-		char const *export_name = alloc_cstring(permanent_allocator(), p->name);
-		LLVMAddTargetDependentFunctionAttr(p->value, "wasm-export-name", export_name);
-	} else {
-		LLVMSetLinkage(p->value, LLVMExternalLinkage);
+		lb_set_wasm_export_attributes(p->value, p->name);
 	}
 	
 
@@ -1489,6 +1483,8 @@ void lb_generate_code(lbGenerator *gen) {
 			LLVMSetLinkage(g.value, LLVMExternalLinkage);
 			LLVMSetExternallyInitialized(g.value, true);
 			lb_add_foreign_library_path(m, e->Variable.foreign_library);
+			
+			lb_set_wasm_import_attributes(g.value, e, name);
 		} else {
 			LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
 		}

+ 2 - 18
src/llvm_backend_proc.cpp

@@ -57,7 +57,6 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
 	LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
 }
 
-
 lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
 	GB_ASSERT(entity != nullptr);
 	GB_ASSERT(entity->kind == Entity_Procedure);
@@ -183,10 +182,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
 		LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass);
 		LLVMSetVisibility(p->value, LLVMDefaultVisibility);
 
-		if (is_arch_wasm()) {
-			char const *export_name = alloc_cstring(permanent_allocator(), p->name);
-			LLVMAddTargetDependentFunctionAttr(p->value, "wasm-export-name", export_name);
-		}
+		lb_set_wasm_export_attributes(p->value, p->name);
 	} else if (!p->is_foreign) {
 		if (!USE_SEPARATE_MODULES) {
 			LLVMSetLinkage(p->value, LLVMInternalLinkage);
@@ -209,19 +205,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
 	}
 	
 	if (p->is_foreign) {
-		if (is_arch_wasm()) {
-			char const *import_name = alloc_cstring(permanent_allocator(), p->name);
-			char const *module_name = "env";
-			if (entity->Procedure.foreign_library != nullptr) {
-				Entity *foreign_library = entity->Procedure.foreign_library;
-				GB_ASSERT(foreign_library->kind == Entity_LibraryName);
-				if (foreign_library->LibraryName.paths.count > 0)  {
-					module_name = alloc_cstring(permanent_allocator(), foreign_library->LibraryName.paths[0]);
-				}
-			}
-			LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-name",   import_name);
-			LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-module", module_name);
-		}
+		lb_set_wasm_import_attributes(p->value, entity, p->name);
 	}
 	
 

+ 33 - 0
src/llvm_backend_utility.cpp

@@ -1770,3 +1770,36 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
 	#endif
 	);
 }
+
+
+void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) {
+	if (!is_arch_wasm()) {
+		return;
+	}
+	String module_name = str_lit("env");
+	if (entity->Procedure.foreign_library != nullptr) {
+		Entity *foreign_library = entity->Procedure.foreign_library;
+		GB_ASSERT(foreign_library->kind == Entity_LibraryName);
+		GB_ASSERT(foreign_library->LibraryName.paths.count == 1);
+		
+		module_name = foreign_library->LibraryName.paths[0];
+		
+		if (string_starts_with(import_name, module_name)) {
+			import_name = substring(import_name, module_name.len+WASM_MODULE_NAME_SEPARATOR.len, import_name.len);
+		}
+		
+	}
+	LLVMAddTargetDependentFunctionAttr(value, "wasm-import-module", alloc_cstring(permanent_allocator(), module_name));
+	LLVMAddTargetDependentFunctionAttr(value, "wasm-import-name",   alloc_cstring(permanent_allocator(), import_name));
+}
+
+
+void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
+	if (!is_arch_wasm()) {
+		return;
+	}
+	LLVMSetLinkage(value, LLVMDLLExportLinkage);
+	LLVMSetDLLStorageClass(value, LLVMDLLExportStorageClass);
+	LLVMSetVisibility(value, LLVMDefaultVisibility);
+	LLVMAddTargetDependentFunctionAttr(value, "wasm-export-name",   alloc_cstring(permanent_allocator(), export_name));
+}