Browse Source

Improve array arithmetic inlining

gingerBill 7 years ago
parent
commit
e515220694
1 changed files with 96 additions and 60 deletions
  1. 96 60
      src/ir.cpp

+ 96 - 60
src/ir.cpp

@@ -160,8 +160,6 @@ gbAllocator ir_allocator(void) {
 }
 
 
-
-
 #define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
 #define IR_TYPE_INFO_DATA_NAME       "__$type_info_data"
 #define IR_TYPE_INFO_TYPES_NAME      "__$type_info_types_data"
@@ -2190,12 +2188,53 @@ irValue *ir_map_cap(irProcedure *proc, irValue *value) {
 }
 
 
-
 void ir_emit_increment(irProcedure *proc, irValue *addr);
 irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index);
 irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index);
 irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index);
 
+struct irLoopData {
+	irValue *idx_addr;
+	irValue *idx;
+	irBlock *body;
+	irBlock *done;
+	irBlock *loop;
+};
+
+irLoopData ir_loop_start(irProcedure *proc, isize count) {
+	irLoopData data = {};
+
+	irValue *max = ir_const_int(count);
+
+	data.idx_addr = ir_add_local_generated(proc, t_int);
+
+	data.body = ir_new_block(proc, nullptr, "loop.body");
+	data.done = ir_new_block(proc, nullptr, "loop.done");
+	data.loop = ir_new_block(proc, nullptr, "loop.loop");
+
+	ir_emit_jump(proc, data.loop);
+	ir_start_block(proc, data.loop);
+
+	data.idx = ir_emit_load(proc, data.idx_addr);
+
+	irValue *cond = ir_emit_comp(proc, Token_Lt, data.idx, max);
+	ir_emit_if(proc, cond, data.body, data.done);
+	ir_start_block(proc, data.body);
+
+	return data;
+}
+
+void ir_loop_end(irProcedure *proc, irLoopData const &data) {
+	if (data.idx_addr != nullptr) {
+		ir_emit_increment(proc, data.idx_addr);
+		ir_emit_jump(proc, data.loop);
+		ir_start_block(proc, data.done);
+	}
+}
+
+
+
+
 irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset) {
 	offset = ir_emit_conv(proc, offset, t_int);
 	return ir_emit(proc, ir_instr_ptr_offset(proc, ptr, offset));
@@ -2223,10 +2262,26 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type *
 		Type *elem_type = base_array_type(type);
 
 		irValue *res = ir_add_local_generated(proc, type);
-		for (i32 i = 0; i < tl->Array.count; i++) {
-			irValue *e = ir_emit_load(proc, ir_emit_array_epi(proc, val, i));
+
+		bool inline_array_arith = type_size_of(type) <= build_context.max_align;
+
+		i32 count = cast(i32)tl->Array.count;
+
+		if (inline_array_arith) {
+			// inline
+			for (i32 i = 0; i < count; i++) {
+				irValue *e = ir_emit_load(proc, ir_emit_array_epi(proc, val, i));
+				irValue *z = ir_emit_unary_arith(proc, op, e, elem_type);
+				ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
+			}
+		} else {
+			auto loop_data = ir_loop_start(proc, count);
+
+			irValue *e = ir_emit_load(proc, ir_emit_array_ep(proc, val, loop_data.idx));
 			irValue *z = ir_emit_unary_arith(proc, op, e, elem_type);
-			ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
+			ir_emit_store(proc, ir_emit_array_ep(proc, res, loop_data.idx), z);
+
+			ir_loop_end(proc, loop_data);
 		}
 		ir_emit_comment(proc, str_lit("array.arith.end"));
 		return ir_emit_load(proc, res);
@@ -2266,31 +2321,14 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 				ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
 			}
 		} else {
-			irValue *idx_addr = ir_add_local_generated(proc, t_int);
-			irValue *max = ir_const_int(count);
-
-			irBlock *body = ir_new_block(proc, nullptr, "array.arith.body");
-			irBlock *done = ir_new_block(proc, nullptr, "array.arith.done");
-			irBlock *loop = ir_new_block(proc, nullptr, "array.arith.loop");
+			auto loop_data = ir_loop_start(proc, count);
 
-			ir_emit_jump(proc, loop);
-			ir_start_block(proc, loop);
-
-			irValue *idx = ir_emit_load(proc, idx_addr);
-
-			irValue *cond = ir_emit_comp(proc, Token_Lt, idx, max);
-			ir_emit_if(proc, cond, body, done);
-			ir_start_block(proc, body);
-
-			irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, idx));
-			irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, idx));
+			irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
+			irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
 			irValue *z = ir_emit_arith(proc, op, x, y, elem_type);
-			ir_emit_store(proc, ir_emit_array_ep(proc, res, idx), z);
-
-			ir_emit_increment(proc, idx_addr);
-			ir_emit_jump(proc, loop);
+			ir_emit_store(proc, ir_emit_array_ep(proc, res, loop_data.idx), z);
 
-			ir_start_block(proc, done);
+			ir_loop_end(proc, loop_data);
 		}
 		ir_emit_comment(proc, str_lit("array.arith.end"));
 		return ir_emit_load(proc, res);
@@ -2353,6 +2391,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 	}
 
 
+#if 0
 	if (op == Token_Add) {
 		if (is_type_pointer(t_left)) {
 			irValue *ptr = ir_emit_conv(proc, left, type);
@@ -2381,7 +2420,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 			return ir_emit_arith(proc, Token_Quo, diff, elem_size, type);
 		}
 	}
-
+#endif
 
 	switch (op) {
 	case Token_Shl:
@@ -2416,14 +2455,13 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 	}
 
 	if (op == Token_ModMod) {
-		irValue *n = left;
-		irValue *m = right;
 		if (is_type_unsigned(type)) {
-			return ir_emit_arith(proc, Token_Mod, n, m, type);
+			op = Token_Mod;
+		} else {
+			irValue *a = ir_emit_arith(proc, Token_Mod, left, right, type);
+			irValue *b = ir_emit_arith(proc, Token_Add, a,    right, type);
+			return ir_emit_arith(proc, Token_Mod, b, right, type);
 		}
-		irValue *a = ir_emit_arith(proc, Token_Mod, n, m, type);
-		irValue *b = ir_emit_arith(proc, Token_Add, a, m, type);
-		return ir_emit_arith(proc, Token_Mod, b, m, type);
 	}
 
 	return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
@@ -2550,12 +2588,26 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
 			cmp_op = Token_Or;
 		}
 
-		// IMPORTANT TODO(bill): Make this much more efficient
-		for (i32 i = 0; i < tl->Array.count; i++) {
-			irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i));
-			irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i));
+		bool inline_array_arith = type_size_of(tl) <= build_context.max_align;
+		i32 count = cast(i32)tl->Array.count;
+
+		if (inline_array_arith) {
+			// inline
+			for (i32 i = 0; i < count; i++) {
+				irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i));
+				irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i));
+				irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
+				res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
+			}
+		} else {
+			auto loop_data = ir_loop_start(proc, count);
+
+			irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
+			irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
 			irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
 			res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
+
+			ir_loop_end(proc, loop_data);
 		}
 
 		return ir_emit_conv(proc, res, t_bool);
@@ -6610,34 +6662,13 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
 	case_ast_node(bs, EmptyStmt, node);
 	case_end;
 
-	// case_ast_node(fb, ForeignBlockDecl, node);
-	// 	ir_build_stmt_list(proc, fb->decls);
-	// case_end;
-
 	case_ast_node(us, UsingStmt, node);
-		for_array(i, us->list) {
-			Ast *decl = unparen_expr(us->list[i]);
-			// if (decl->kind == Ast_GenDecl) {
-				// ir_build_stmt(proc, decl);
-			// }
-		}
 	case_end;
 
 	case_ast_node(ws, WhenStmt, node);
 		ir_build_when_stmt(proc, ws);
 	case_end;
 
-	#if 0
-	case_ast_node(s, IncDecStmt, node);
-		TokenKind op = Token_Add;
-		if (s->op.kind == Token_Dec) {
-			op = Token_Sub;
-		}
-		irAddr const &addr = ir_build_addr(proc, s->expr);
-		ir_build_assign_op(proc, addr, v_one, op);
-	case_end;
-	#endif
-
 	case_ast_node(vd, ValueDecl, node);
 		if (vd->is_mutable) {
 			irModule *m = proc->module;
@@ -6853,9 +6884,12 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
 	case_ast_node(is, IfStmt, node);
 		ir_emit_comment(proc, str_lit("IfStmt"));
 		if (is->init != nullptr) {
+			// TODO(bill): Should this have a separate block to begin with?
+		#if 1
 			irBlock *init = ir_new_block(proc, node, "if.init");
 			ir_emit_jump(proc, init);
 			ir_start_block(proc, init);
+		#endif
 			ir_build_stmt(proc, is->init);
 		}
 		irBlock *then = ir_new_block(proc, node, "if.then");
@@ -6891,9 +6925,11 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
 		ir_emit_comment(proc, str_lit("ForStmt"));
 
 		if (fs->init != nullptr) {
+		#if 1
 			irBlock *init = ir_new_block(proc, node, "for.init");
 			ir_emit_jump(proc, init);
 			ir_start_block(proc, init);
+		#endif
 			ir_build_stmt(proc, fs->init);
 		}
 		irBlock *body = ir_new_block(proc, node, "for.body");