Browse Source

Improve support for `freestanding_wasm32`

gingerBill 3 years ago
parent
commit
dc2edd3e79

+ 11 - 8
core/runtime/core.odin

@@ -516,14 +516,17 @@ __init_context :: proc "contextless" (c: ^Context) {
 }
 }
 
 
 default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
 default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
-	print_caller_location(loc)
-	print_string(" ")
-	print_string(prefix)
-	if len(message) > 0 {
-		print_string(": ")
-		print_string(message)
+	when ODIN_OS == "freestanding" {
+		// Do nothing
+	} else {
+		print_caller_location(loc)
+		print_string(" ")
+		print_string(prefix)
+		if len(message) > 0 {
+			print_string(": ")
+			print_string(message)
+		}
+		print_byte('\n')
 	}
 	}
-	print_byte('\n')
-	// intrinsics.debug_trap();
 	intrinsics.trap()
 	intrinsics.trap()
 }
 }

+ 24 - 17
core/runtime/internal.odin

@@ -3,7 +3,14 @@ package runtime
 import "core:intrinsics"
 import "core:intrinsics"
 
 
 @(private)
 @(private)
-RUNTIME_LINKAGE :: "strong" when (ODIN_USE_SEPARATE_MODULES || ODIN_BUILD_MODE == "dynamic" || !ODIN_NO_CRT) else "internal"
+RUNTIME_LINKAGE :: "strong" when (
+	(ODIN_USE_SEPARATE_MODULES || 
+	ODIN_BUILD_MODE == "dynamic" || 
+	!ODIN_NO_CRT) &&
+	!(ODIN_ARCH == "wasm32" || 
+	  ODIN_ARCH == "wasm64")) else "internal"
+RUNTIME_REQUIRE :: !(ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64")
+
 
 
 @(private)
 @(private)
 byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
 byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
@@ -649,7 +656,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
 	return quaternion(t0, t1, t2, t3)
 	return quaternion(t0, t1, t2, t3)
 }
 }
 
 
-@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 truncsfhf2 :: proc "c" (value: f32) -> u16 {
 truncsfhf2 :: proc "c" (value: f32) -> u16 {
 	v: struct #raw_union { i: u32, f: f32 }
 	v: struct #raw_union { i: u32, f: f32 }
 	i, s, e, m: i32
 	i, s, e, m: i32
@@ -707,12 +714,12 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
 }
 }
 
 
 
 
-@(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 truncdfhf2 :: proc "c" (value: f64) -> u16 {
 truncdfhf2 :: proc "c" (value: f64) -> u16 {
 	return truncsfhf2(f32(value))
 	return truncsfhf2(f32(value))
 }
 }
 
 
-@(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
 gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
 	fp32 :: struct #raw_union { u: u32, f: f32 }
 	fp32 :: struct #raw_union { u: u32, f: f32 }
 
 
@@ -731,19 +738,19 @@ gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
 }
 }
 
 
 
 
-@(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
 gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
 	return truncsfhf2(value)
 	return truncsfhf2(value)
 }
 }
 
 
-@(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 extendhfsf2 :: proc "c" (value: u16) -> f32 {
 extendhfsf2 :: proc "c" (value: u16) -> f32 {
 	return gnu_h2f_ieee(value)
 	return gnu_h2f_ieee(value)
 }
 }
 
 
 
 
 
 
-@(link_name="__floattidf", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__floattidf", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 floattidf :: proc "c" (a: i128) -> f64 {
 floattidf :: proc "c" (a: i128) -> f64 {
 	DBL_MANT_DIG :: 53
 	DBL_MANT_DIG :: 53
 	if a == 0 {
 	if a == 0 {
@@ -786,7 +793,7 @@ floattidf :: proc "c" (a: i128) -> f64 {
 }
 }
 
 
 
 
-@(link_name="__floattidf_unsigned", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__floattidf_unsigned", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 floattidf_unsigned :: proc "c" (a: u128) -> f64 {
 floattidf_unsigned :: proc "c" (a: u128) -> f64 {
 	DBL_MANT_DIG :: 53
 	DBL_MANT_DIG :: 53
 	if a == 0 {
 	if a == 0 {
@@ -828,14 +835,14 @@ floattidf_unsigned :: proc "c" (a: u128) -> f64 {
 
 
 
 
 
 
-@(link_name="__fixunsdfti", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__fixunsdfti", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 fixunsdfti :: #force_no_inline proc "c" (a: f64) -> u128 {
 fixunsdfti :: #force_no_inline proc "c" (a: f64) -> u128 {
 	// TODO(bill): implement `fixunsdfti` correctly
 	// TODO(bill): implement `fixunsdfti` correctly
 	x := u64(a)
 	x := u64(a)
 	return u128(x)
 	return u128(x)
 }
 }
 
 
-@(link_name="__fixunsdfdi", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__fixunsdfdi", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 fixunsdfdi :: #force_no_inline proc "c" (a: f64) -> i128 {
 fixunsdfdi :: #force_no_inline proc "c" (a: f64) -> i128 {
 	// TODO(bill): implement `fixunsdfdi` correctly
 	// TODO(bill): implement `fixunsdfdi` correctly
 	x := i64(a)
 	x := i64(a)
@@ -845,7 +852,7 @@ fixunsdfdi :: #force_no_inline proc "c" (a: f64) -> i128 {
 
 
 
 
 
 
-@(link_name="__umodti3", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__umodti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 umodti3 :: proc "c" (a, b: u128) -> u128 {
 umodti3 :: proc "c" (a, b: u128) -> u128 {
 	r: u128 = ---
 	r: u128 = ---
 	_ = udivmod128(a, b, &r)
 	_ = udivmod128(a, b, &r)
@@ -853,18 +860,18 @@ umodti3 :: proc "c" (a, b: u128) -> u128 {
 }
 }
 
 
 
 
-@(link_name="__udivmodti4", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__udivmodti4", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
 udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
 	return udivmod128(a, b, rem)
 	return udivmod128(a, b, rem)
 }
 }
 
 
-@(link_name="__udivti3", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__udivti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 udivti3 :: proc "c" (a, b: u128) -> u128 {
 udivti3 :: proc "c" (a, b: u128) -> u128 {
 	return udivmodti4(a, b, nil)
 	return udivmodti4(a, b, nil)
 }
 }
 
 
 
 
-@(link_name="__modti3", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__modti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 modti3 :: proc "c" (a, b: i128) -> i128 {
 modti3 :: proc "c" (a, b: i128) -> i128 {
 	s_a := a >> (128 - 1)
 	s_a := a >> (128 - 1)
 	s_b := b >> (128 - 1)
 	s_b := b >> (128 - 1)
@@ -877,20 +884,20 @@ modti3 :: proc "c" (a, b: i128) -> i128 {
 }
 }
 
 
 
 
-@(link_name="__divmodti4", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__divmodti4", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 {
 divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 {
 	u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem)
 	u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem)
 	return transmute(i128)u
 	return transmute(i128)u
 }
 }
 
 
-@(link_name="__divti3", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__divti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 divti3 :: proc "c" (a, b: i128) -> i128 {
 divti3 :: proc "c" (a, b: i128) -> i128 {
 	u := udivmodti4(transmute(u128)a, transmute(u128)b, nil)
 	u := udivmodti4(transmute(u128)a, transmute(u128)b, nil)
 	return transmute(i128)u
 	return transmute(i128)u
 }
 }
 
 
 
 
-@(link_name="__fixdfti", linkage=RUNTIME_LINKAGE, require)
+@(link_name="__fixdfti", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
 fixdfti :: proc(a: u64) -> i128 {
 fixdfti :: proc(a: u64) -> i128 {
 	significandBits :: 52
 	significandBits :: 52
 	typeWidth       :: (size_of(u64)*8)
 	typeWidth       :: (size_of(u64)*8)

+ 13 - 2
core/runtime/procs_wasm32.odin

@@ -3,6 +3,17 @@ package runtime
 
 
 @(link_name="__ashlti3", linkage="strong")
 @(link_name="__ashlti3", linkage="strong")
 __ashlti3 :: proc "c" (a: i64, b: i32) -> i64 {
 __ashlti3 :: proc "c" (a: i64, b: i32) -> i64 {
-	// TODO(bill): __ashlti3 on wasm32
-	return a
+	input: transmute([2]i32)a
+	result: [2]i32
+	if b & 32 != 0 {
+		result[0] = 0
+		result[1] = input[0] << (b - 32)
+	} else {
+		if b == 0 {
+			return a
+		}
+		result[0] = input[0]<<b
+		result[1] = (input[1]<<b) | (input[0]>>(32-b))
+	}
+	return transmute(i64)result
 }
 }

+ 2 - 2
core/runtime/udivmod128.odin

@@ -8,7 +8,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
 
 
 	n := transmute([2]u64)a
 	n := transmute([2]u64)a
 	d := transmute([2]u64)b
 	d := transmute([2]u64)b
-	q, r: [2]u64 = ---, ---
+	q, r: [2]u64
 	sr: u32 = 0
 	sr: u32 = 0
 
 
 	low  :: 1 when ODIN_ENDIAN == "big" else 0
 	low  :: 1 when ODIN_ENDIAN == "big" else 0
@@ -132,7 +132,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
 	}
 	}
 
 
 	carry: u32 = 0
 	carry: u32 = 0
-	r_all: u128 = ---
+	r_all: u128
 
 
 	for ; sr > 0; sr -= 1 {
 	for ; sr > 0; sr -= 1 {
 		r[high] = (r[high] << 1) | (r[low]  >> (U64_BITS - 1))
 		r[high] = (r[high] << 1) | (r[low]  >> (U64_BITS - 1))

+ 7 - 3
src/checker.cpp

@@ -2660,10 +2660,14 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 		}
 		}
 		return true;
 		return true;
 	} else if (name == "require") {
 	} else if (name == "require") {
-		if (value != nullptr) {
-			error(elem, "'require' does not have any parameters");
+		ExactValue ev = check_decl_attribute_value(c, value);
+		if (ev.kind == ExactValue_Invalid) {
+			ac->require_declaration = true;
+		} else if (ev.kind == ExactValue_Bool) {
+			ac->require_declaration = ev.value_bool;
+		} else {
+			error(value, "Expected either a boolean or no parameter for 'require'");
 		}
 		}
-		ac->require_declaration = true;
 		return true;
 		return true;
 	} else if (name == "init") {
 	} else if (name == "init") {
 		if (value != nullptr) {
 		if (value != nullptr) {

+ 1 - 0
src/llvm_backend.cpp

@@ -1676,6 +1676,7 @@ void lb_generate_code(lbGenerator *gen) {
 		lbModule *m = gen->modules.entries[i].value;
 		lbModule *m = gen->modules.entries[i].value;
 		
 		
 		lb_run_remove_unused_function_pass(m);
 		lb_run_remove_unused_function_pass(m);
+		lb_run_remove_unused_globals_pass(m);
 
 
 		auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
 		auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
 		wd->m = m;
 		wd->m = m;

+ 64 - 4
src/llvm_backend_opt.cpp

@@ -373,6 +373,20 @@ void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
 	lb_run_remove_dead_instruction_pass(p);
 	lb_run_remove_dead_instruction_pass(p);
 }
 }
 
 
+void llvm_delete_function(LLVMValueRef func) {
+	// for (LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(func); block != nullptr; /**/) {
+	// 	LLVMBasicBlockRef curr_block = block;
+	// 	block = LLVMGetNextBasicBlock(block);
+	// 	for (LLVMValueRef instr = LLVMGetFirstInstruction(curr_block); instr != nullptr; /**/) {
+	// 		LLVMValueRef curr_instr = instr;
+	// 		instr = LLVMGetNextInstruction(instr);
+			
+	// 		LLVMInstructionEraseFromParent(curr_instr);
+	// 	}
+	// 	LLVMRemoveBasicBlockFromParent(curr_block);
+	// }
+	LLVMDeleteFunction(func);
+}
 
 
 void lb_run_remove_unused_function_pass(lbModule *m) {
 void lb_run_remove_unused_function_pass(lbModule *m) {
 	isize removal_count = 0;
 	isize removal_count = 0;
@@ -380,7 +394,7 @@ void lb_run_remove_unused_function_pass(lbModule *m) {
 	isize const max_pass_count = 10;
 	isize const max_pass_count = 10;
 	// Custom remove dead function pass
 	// Custom remove dead function pass
 	for (; pass_count < max_pass_count; pass_count++) {
 	for (; pass_count < max_pass_count; pass_count++) {
-		bool was_dead_function = false;	
+		bool was_dead = false;	
 		for (LLVMValueRef func = LLVMGetFirstFunction(m->mod);
 		for (LLVMValueRef func = LLVMGetFirstFunction(m->mod);
 		     func != nullptr;
 		     func != nullptr;
 		     /**/
 		     /**/
@@ -412,12 +426,58 @@ void lb_run_remove_unused_function_pass(lbModule *m) {
 					continue;
 					continue;
 				}
 				}
 			}
 			}
+			
+			llvm_delete_function(curr_func);
+			was_dead = true;
+			removal_count += 1;
+		}
+		if (!was_dead) {
+			break;
+		}
+	}
+}
+
+
+void lb_run_remove_unused_globals_pass(lbModule *m) {
+	isize removal_count = 0;
+	isize pass_count = 0;
+	isize const max_pass_count = 10;
+	// Custom remove dead function pass
+	for (; pass_count < max_pass_count; pass_count++) {
+		bool was_dead = false;	
+		for (LLVMValueRef global = LLVMGetFirstGlobal(m->mod);
+		     global != nullptr;
+		     /**/
+		     ) {
+		     	LLVMValueRef curr_global = global;
+		     	global = LLVMGetNextGlobal(global);
+		     	
+			LLVMUseRef first_use = LLVMGetFirstUse(curr_global);
+			if (first_use != nullptr)  {
+				continue;
+			}
+			String name = {};
+			name.text = cast(u8 *)LLVMGetValueName2(curr_global, cast(size_t *)&name.len);
+						
+			LLVMLinkage linkage = LLVMGetLinkage(curr_global);
+			if (linkage != LLVMInternalLinkage) {
+				continue;
+			}
+			
+			Entity **found = map_get(&m->procedure_values, curr_global);
+			if (found && *found) {
+				Entity *e = *found;
+				bool is_required = (e->flags & EntityFlag_Require) == EntityFlag_Require;
+				if (is_required) {
+					continue;
+				}
+			}
 
 
-			LLVMDeleteFunction(curr_func);
-			was_dead_function = true;
+			LLVMDeleteGlobal(curr_global);
+			was_dead = true;
 			removal_count += 1;
 			removal_count += 1;
 		}
 		}
-		if (!was_dead_function) {
+		if (!was_dead) {
 			break;
 			break;
 		}
 		}
 	}
 	}