Browse Source

Improve emit store for large constants

gingerBill 3 years ago
parent
commit
03f683f9e7
1 changed files with 36 additions and 10 deletions
  1. 36 10
      src/llvm_backend_general.cpp

+ 36 - 10
src/llvm_backend_general.cpp

@@ -567,6 +567,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu
 	}
 }
 
+unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) {
+	if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
+		return LLVMGetAlignment(addr_ptr);
+	}
+	return default_alignment;
+}
+
 bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) {
 	if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
 		if (LLVMGetAlignment(addr_ptr) < alignment) {
@@ -914,16 +921,35 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
 
 	enum {MAX_STORE_SIZE = 64};
 
-	if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
-		LLVMValueRef dst_ptr = ptr.value;
-		LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0);
-		src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
-
-		LLVMBuildMemMove(p->builder,
-		                 dst_ptr, 1,
-		                 src_ptr, 1,
-		                 LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
-		return;
+	if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
+		if (LLVMIsALoadInst(value.value)) {
+			LLVMValueRef dst_ptr = ptr.value;
+			LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0);
+			LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
+
+			LLVMBuildMemMove(p->builder,
+			                 dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+			                 src_ptr, lb_try_get_alignment(src_ptr_original, 1),
+			                 LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+			return;
+		} else if (LLVMIsConstant(value.value)) {
+			lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
+			LLVMValueRef global_data = addr.addr.value;
+			// make it truly private data
+			LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+			LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+			LLVMSetGlobalConstant(global_data, true);
+
+			LLVMValueRef dst_ptr = ptr.value;
+			LLVMValueRef src_ptr = global_data;
+			src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
+
+			LLVMBuildMemMove(p->builder,
+			                 dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+			                 src_ptr, lb_try_get_alignment(global_data, 1),
+			                 LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+			return;
+		}
 	}
 
 	if (lb_is_type_proc_recursive(a)) {