Browse Source

Improve logic for intrinsics.{mem_copy, mem_copy_non_overlapping, mem_zero} to use the `*.inline` LLVM variants when possible

gingerBill 4 years ago
parent
commit
4b46d691f8
1 changed files with 65 additions and 10 deletions
  1. 65 10
      src/llvm_backend.cpp

+ 65 - 10
src/llvm_backend.cpp

@@ -3483,6 +3483,40 @@ lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *f
 	return v;
 }
 
+void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment) {
+	bool is_inlinable = false;
+
+	i64 const_len = 0;
+	if (LLVMIsConstant(len)) {
+		const_len = cast(i64)LLVMConstIntGetSExtValue(len);
+		// TODO(bill): Determine when it is better to do the `*.inline` versions
+		if (const_len <= 4*build_context.word_size) {
+			is_inlinable = true;
+		}
+	}
+
+	char const *name = "llvm.memset";
+	if (is_inlinable) {
+		name = "llvm.memset.inline";
+	}
+
+	LLVMTypeRef types[2] = {
+		lb_type(p->module, t_rawptr),
+		lb_type(p->module, t_int)
+	};
+	unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+	GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
+	LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+	LLVMValueRef args[4] = {};
+	args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
+	args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false);
+	args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
+	args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, false); // is_volatile parameter
+
+	LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+}
+
 void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
 	LLVMTypeRef llvm_type = lb_type(p->module, type);
 
@@ -3493,10 +3527,8 @@ void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alig
 	case LLVMArrayTypeKind:
 		{
 			// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
-			LLVMTypeRef type_i8 = LLVMInt8TypeInContext(p->module->ctx);
-			LLVMTypeRef type_i32 = LLVMInt32TypeInContext(p->module->ctx);
 			i32 sz = cast(i32)type_size_of(type);
-			LLVMBuildMemSet(p->builder, ptr, LLVMConstNull(type_i8), LLVMConstInt(type_i32, sz, false), alignment);
+			lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment);
 		}
 		break;
 	default:
@@ -4953,10 +4985,12 @@ lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, A
 	p->copy_elision_hint.used = false;
 	p->copy_elision_hint.ptr = {};
 	p->copy_elision_hint.ast = nullptr;
+#if 0
 	if (addr.kind == lbAddr_Default && addr.addr.value != nullptr) {
 		p->copy_elision_hint.ptr = lb_addr_get_ptr(p, addr);
 		p->copy_elision_hint.ast = unparen_expr(ast);
 	}
+#endif
 	return prev;
 }
 
@@ -5056,12 +5090,12 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
 				array_add(&inits, v);
 			}
 		} else {
-			// auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
+			auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
 			lbValue init = lb_build_expr(p, rhs);
 			if (p->copy_elision_hint.used) {
 				lvals[inits.count] = {}; // zero lval
 			}
-			// lb_reset_copy_elision_hint(p, prev_hint);
+			lb_reset_copy_elision_hint(p, prev_hint);
 			array_add(&inits, init);
 		}
 	}
@@ -9485,10 +9519,33 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 			src = lb_emit_conv(p, src, t_rawptr);
 			len = lb_emit_conv(p, len, t_int);
 
+			bool is_inlinable = false;
+
+			if (ce->args[2]->tav.mode == Addressing_Constant) {
+				ExactValue ev = exact_value_to_integer(ce->args[2]->tav.value);
+				i64 const_len = exact_value_to_i64(ev);
+				// TODO(bill): Determine when it is better to do the `*.inline` versions
+				if (const_len <= 4*build_context.word_size) {
+					is_inlinable = true;
+				}
+			}
+
 			char const *name = nullptr;
 			switch (id) {
-			case BuiltinProc_mem_copy:                 name = "llvm.memmove"; break;
-			case BuiltinProc_mem_copy_non_overlapping: name = "llvm.memcpy";  break;
+			case BuiltinProc_mem_copy:
+				if (is_inlinable) {
+					name = "llvm.memmove.inline";
+				} else {
+					name = "llvm.memmove";
+				}
+				break;
+			case BuiltinProc_mem_copy_non_overlapping:
+				if (is_inlinable) {
+					name = "llvm.memcpy.line";
+				} else {
+					name = "llvm.memcpy";
+				}
+				break;
 			}
 
 			LLVMTypeRef types[3] = {
@@ -9518,10 +9575,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 			ptr = lb_emit_conv(p, ptr, t_rawptr);
 			len = lb_emit_conv(p, len, t_int);
 
-			LLVMTypeRef type_i8 = LLVMInt8TypeInContext(p->module->ctx);
 			unsigned alignment = 1;
-			LLVMBuildMemSet(p->builder, ptr.value, LLVMConstNull(type_i8), len.value, alignment);
-
+			lb_mem_zero_ptr_internal(p, ptr.value, len.value, alignment);
 			return {};
 		}