Răsfoiți Sursa

Update gb.h

Ginger Bill 8 ani în urmă
părinte
comite
32150e401e
11 a modificat fișierele cu 434 adăugiri și 221 ștergeri
  1. 4 1
      build.bat
  2. 1 8
      code/demo.odin
  3. 0 1
      core/os_windows.odin
  4. 10 7
      core/sys/windows.odin
  5. 6 6
      src/check_expr.c
  6. 286 113
      src/gb/gb.h
  7. 4 4
      src/ir.c
  8. 1 1
      src/ir_print.c
  9. 3 2
      src/parser.c
  10. 104 67
      src/ssa.c
  11. 15 11
      src/types.c

+ 4 - 1
build.bat

@@ -44,7 +44,10 @@ del *.ilk > NUL 2> NUL
 
 cl %compiler_settings% "src\main.c" ^
 	/link %linker_settings% -OUT:%exe_name% ^
-	&& odin run code/demo.odin
+	&& odin build code/metagen.odin ^
+	&& call "code\metagen.exe" "src\ast_nodes.metagen"
+	rem && odin build code/markdown.odin ^
+	rem && call "code\markdown.exe" "misc\example.md"
 	rem && odin run code/Jaze/src/main.odin
 
 del *.obj > NUL 2> NUL

+ 1 - 8
code/demo.odin

@@ -10,14 +10,7 @@
 #import win32 "sys/windows.odin";
 
 main :: proc() {
-	a := 1;
-	b := 2;
-	c := a + b;
-
-	if c > 0 {
-		c = 0;
-	}
-
+	fmt.println("Here");
 when false {
 /*
 	Version 0.1.1

+ 0 - 1
core/os_windows.odin

@@ -247,7 +247,6 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
 
 
 heap_alloc :: proc(size: int) -> rawptr {
-	assert(size > 0);
 	return w.HeapAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, size);
 }
 heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {

+ 10 - 7
core/sys/windows.odin

@@ -2,6 +2,7 @@
 #foreign_system_library "user32.lib"   when ODIN_OS == "windows";
 #foreign_system_library "gdi32.lib"    when ODIN_OS == "windows";
 #foreign_system_library "winmm.lib"    when ODIN_OS == "windows";
+#foreign_system_library "shell32.lib"  when ODIN_OS == "windows";
 
 Handle    :: rawptr;
 Hwnd      :: Handle;
@@ -181,15 +182,17 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
 	return r;
 }
 
-GetCommandLineA    :: proc() -> ^u8 #foreign kernel32;
-GetSystemMetrics   :: proc(index: i32) -> i32 #foreign kernel32;
-GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
+GetCommandLineA    :: proc() -> ^u8                                 #foreign kernel32;
+GetCommandLineW    :: proc() -> ^u16                                #foreign kernel32;
+GetSystemMetrics   :: proc(index: i32) -> i32                       #foreign kernel32;
+GetCurrentThreadId :: proc() -> u32                                 #foreign kernel32;
+CommandLineToArgvW :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #foreign shell32;
 
-timeGetTime             :: proc() -> u32 #foreign winmm;
-GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime) #foreign kernel32;
+timeGetTime             :: proc() -> u32                                                  #foreign winmm;
+GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime)                      #foreign kernel32;
 FileTimeToLocalFileTime :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #foreign kernel32;
-FileTimeToSystemTime    :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #foreign kernel32;
-SystemTimeToFileTime    :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #foreign kernel32;
+FileTimeToSystemTime    :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool   #foreign kernel32;
+SystemTimeToFileTime    :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool   #foreign kernel32;
 
 // File Stuff
 

+ 6 - 6
src/check_expr.c

@@ -1112,7 +1112,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
 	e->flags |= EntityFlag_Used;
 
 	Entity *original_e = e;
-	while (e->kind == Entity_Alias && e->Alias.original != NULL) {
+	while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) {
 		e = e->Alias.original;
 	}
 
@@ -1672,7 +1672,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 		return true;
 	}
 
-	type = base_type(base_enum_type(type));
+	type = core_type(type);
 
 	if (is_type_boolean(type)) {
 		return in_value.kind == ExactValue_Bool;
@@ -2118,8 +2118,8 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
 	}
 
 	Type *x = operand->type;
-	Type *src = base_type(base_enum_type(x));
-	Type *dst = base_type(base_enum_type(y));
+	Type *src = core_type(x);
+	Type *dst = core_type(y);
 	if (are_types_identical(src, dst)) {
 		return true;
 	}
@@ -2527,7 +2527,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
 		return;
 	}
 
-	Type *t = base_type(base_enum_type(target_type));
+	Type *t = core_type(target_type);
 	switch (t->kind) {
 	case Type_Basic:
 		if (operand->mode == Addressing_Constant) {
@@ -2689,7 +2689,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		expr_entity = e;
 
 		Entity *original_e = e;
-		while (e->kind == Entity_Alias && e->Alias.original != NULL) {
+		while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) {
 			e = e->Alias.original;
 		}
 

Fișier diff suprimat deoarece este prea mare
+ 286 - 113
src/gb/gb.h


+ 4 - 4
src/ir.c

@@ -1328,8 +1328,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na
 irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
 #if 1
 	// NOTE(bill): Sanity check
-	Type *a = base_type(base_enum_type(type_deref(ir_type(address))));
-	Type *b = base_type(base_enum_type(ir_type(value)));
+	Type *a = core_type(type_deref(ir_type(address)));
+	Type *b = core_type(ir_type(value));
 	if (!is_type_untyped(b)) {
 		GB_ASSERT_MSG(are_types_identical(a, b), "%s %s", type_to_string(a), type_to_string(b));
 	}
@@ -2218,8 +2218,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 		return value;
 	}
 
-	Type *src = base_type(base_enum_type(src_type));
-	Type *dst = base_type(base_enum_type(t));
+	Type *src = core_type(src_type);
+	Type *dst = core_type(t);
 
 
 	// if (is_type_untyped_nil(src) && type_has_nil(dst)) {

+ 1 - 1
src/ir_print.c

@@ -306,7 +306,7 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
 }
 
 void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
-	type = base_type(base_enum_type(type));
+	type = core_type(type);
 	if (is_type_float(type)) {
 		value = exact_value_to_float(value);
 	} else if (is_type_integer(type)) {

+ 3 - 2
src/parser.c

@@ -402,7 +402,6 @@ String const ast_node_strings[] = {
 
 typedef struct AstNode {
 	AstNodeKind kind;
-	// AstNode *prev, *next; // NOTE(bill): allow for Linked list
 	u32 stmt_state_flags;
 	union {
 #define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
@@ -414,7 +413,9 @@ typedef struct AstNode {
 
 #define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
 #define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
+#ifndef case_end
 #define case_end } break;
+#endif
 
 
 gb_inline bool is_ast_node_expr(AstNode *node) {
@@ -3841,7 +3842,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
 				gb_printf_err("File permissions problem");
 				break;
 			case ParseFile_NotFound:
-				gb_printf_err("File cannot be found");
+				gb_printf_err("File cannot be found (`%.*s`)", LIT(import_path));
 				break;
 			case ParseFile_InvalidToken:
 				gb_printf_err("Invalid token found in file");

+ 104 - 67
src/ssa.c

@@ -1,6 +1,7 @@
 typedef enum   ssaOp               ssaOp;
 typedef struct ssaModule           ssaModule;
 typedef struct ssaValue            ssaValue;
+typedef struct ssaValueArgs        ssaValueArgs;
 typedef struct ssaBlock            ssaBlock;
 typedef struct ssaProc             ssaProc;
 typedef struct ssaEdge             ssaEdge;
@@ -294,7 +295,15 @@ String const ssa_op_strings[] = {
 #undef SSA_OP
 };
 
-#define SSA_MAX_ARGS 4
+
+#define SSA_DEFAULT_VALUE_ARG_CAPACITY 8
+struct ssaValueArgs {
+	ssaValue ** e;
+	isize       count;
+	isize       capacity;
+	ssaValue *  backing[SSA_DEFAULT_VALUE_ARG_CAPACITY];
+	gbAllocator allocator;
+};
 
 struct ssaValue {
 	i32           id;    // Unique identifier but the pointer could be used too
@@ -303,13 +312,7 @@ struct ssaValue {
 	ssaBlock *    block; // Containing basic block
 
 	i32           uses;
-	// Most values will only a few number of arguments
-	// Procedure calls may need a lot more so they will use the `var_args` parameter instead
-	ssaValue *    args[SSA_MAX_ARGS];
-	isize         arg_count;
-
-	ssaValueArray var_args; // Only used in procedure calls as the SSA_MAX_ARGS may be too small
-
+	ssaValueArgs  args;
 	ExactValue    exact_value; // Used for constants
 
 	String        comment_string;
@@ -501,30 +504,39 @@ void ssa_emit_jump(ssaProc *p, ssaBlock *edge) {
 	ssa_add_edge_to(ssa_end_block(p), edge);
 }
 
+void ssa_init_value_args(ssaValueArgs *va, gbAllocator a) {
+	va->e              = va->backing;
+	va->count          = 0;
+	va->capacity       = gb_count_of(va->backing);
+	va->allocator      = a;
+}
 
-bool ssa_op_uses_var_args(ssaOp op) {
-	switch (op) {
-	case ssaOp_CallOdin:
-	case ssaOp_CallC:
-	case ssaOp_CallStd:
-	case ssaOp_CallFast:
-		return true;
-
-	case ssaOp_Phi:
-		return true;
+void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) {
+	if (va->count >= va->capacity) {
+		isize capacity = 2*va->capacity;
+		if (va->e == va->backing) { // Replace the backing with an allocated version instead
+			ssaValue **new_args = gb_alloc_array(va->allocator, ssaValue *, capacity);
+			gb_memcopy_array(new_args, va->e, va->count);
+			va->e = new_args;
+		} else {
+			isize old_cap_size = va->capacity * gb_size_of(ssaValue *);
+			isize new_cap_size = capacity * gb_size_of(ssaValue *);
+			va->e = gb_resize(va->allocator, va->e, old_cap_size, new_cap_size);
+		}
+		va->capacity = capacity;
 	}
-	return false;
+	va->e[va->count++] = arg; arg->uses++;
 }
 
 
 
-
 ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) {
 	ssaValue *v = gb_alloc_item(p->module->allocator, ssaValue);
 	v->id    = p->value_id++;
 	v->op    = op;
 	v->type  = t;
 	v->block = b;
+	ssa_init_value_args(&v->args, p->module->allocator);
 	array_add(&b->values, v);
 	return v;
 }
@@ -541,7 +553,7 @@ ssaValue *ssa_new_value0v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value
 
 ssaValue *ssa_new_value1(ssaBlock *b, ssaOp op, Type *t, ssaValue *arg) {
 	ssaValue *v = ssa_new_value(b->proc, op, t, b);
-	v->args[v->arg_count++] = arg; arg->uses++;
+	ssa_add_arg(&v->args, arg);
 	return v;
 }
 ssaValue *ssa_new_value1v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg) {
@@ -552,8 +564,8 @@ ssaValue *ssa_new_value1v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value
 
 ssaValue *ssa_new_value2(ssaBlock *b, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1) {
 	ssaValue *v = ssa_new_value(b->proc, op, t, b);
-	v->args[v->arg_count++] = arg0; arg0->uses++;
-	v->args[v->arg_count++] = arg1; arg1->uses++;
+	ssa_add_arg(&v->args, arg0);
+	ssa_add_arg(&v->args, arg1);
 	return v;
 }
 ssaValue *ssa_new_value2v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1) {
@@ -564,9 +576,9 @@ ssaValue *ssa_new_value2v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value
 
 ssaValue *ssa_new_value3(ssaBlock *b, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) {
 	ssaValue *v = ssa_new_value(b->proc, op, t, b);
-	v->args[v->arg_count++] = arg0; arg0->uses++;
-	v->args[v->arg_count++] = arg1; arg1->uses++;
-	v->args[v->arg_count++] = arg2; arg2->uses++;
+	ssa_add_arg(&v->args, arg0);
+	ssa_add_arg(&v->args, arg1);
+	ssa_add_arg(&v->args, arg2);
 	return v;
 }
 ssaValue *ssa_new_value3v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) {
@@ -577,10 +589,10 @@ ssaValue *ssa_new_value3v(ssaBlock *b, ssaOp op, Type *t, ExactValue exact_value
 
 ssaValue *ssa_new_value4(ssaBlock *b, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2, ssaValue *arg3) {
 	ssaValue *v = ssa_new_value(b->proc, op, t, b);
-	v->args[v->arg_count++] = arg0; arg0->uses++;
-	v->args[v->arg_count++] = arg1; arg1->uses++;
-	v->args[v->arg_count++] = arg2; arg2->uses++;
-	v->args[v->arg_count++] = arg3; arg3->uses++;
+	ssa_add_arg(&v->args, arg0);
+	ssa_add_arg(&v->args, arg1);
+	ssa_add_arg(&v->args, arg2);
+	ssa_add_arg(&v->args, arg3);
 	return v;
 }
 
@@ -612,17 +624,10 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
 }
 
 void ssa_reset_value_args(ssaValue *v) {
-	if (ssa_op_uses_var_args(v->op)) {
-		for_array(i, v->var_args) {
-			v->var_args.e[i]->uses--;
-		}
-		v->var_args.count = 0;
-	} else {
-		for (isize i = 0; i < v->arg_count; i++) {
-			v->args[i]->uses--;
-		}
-		v->arg_count = 0;
+	for_array(i, v->args) {
+		v->args.e[i]->uses--;
 	}
+	v->args.count = 0;
 }
 
 
@@ -721,6 +726,55 @@ void ssa_emit_comment(ssaProc *p, String s) {
 	// ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s));
 }
 
+#define SSA_MAX_STRUCT_FIELD_COUNT 4
+
+bool can_ssa_type(Type *t) {
+	i64 s = type_size_of(heap_allocator(), t);
+	if (s > 4*build_context.word_size) {
+		return false;
+	}
+	t = core_type(t);
+
+	switch (t->kind) {
+	case Type_Array:
+		return t->Array.count == 0;
+	case Type_Vector:
+		return s < 2*build_context.word_size;
+
+	case Type_DynamicArray:
+		return false;
+	case Type_Map:
+		return false;
+	case Type_Tuple:
+		if (t->Tuple.variable_count > SSA_MAX_STRUCT_FIELD_COUNT) {
+			return false;
+		}
+		for (isize i = 0; i < t->Tuple.variable_count; i++) {
+			if (!can_ssa_type(t->Tuple.variables[i]->type)) {
+				return false;
+			}
+		}
+		return true;
+	case Type_Record:
+		if (t->Record.kind == TypeRecord_Union) {
+			return false;
+		} else if (t->Record.kind == TypeRecord_Struct) {
+			if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
+				return false;
+			}
+			for (isize i = 0; i < t->Record.field_count; i++) {
+				if (!can_ssa_type(t->Record.fields[i]->type)) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	return true;
+}
+
+
+
 void ssa_build_stmt(ssaProc *p, AstNode *node);
 void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes);
 
@@ -815,7 +869,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
 
 
 Type *ssa_proper_type(Type *t) {
-	t = default_type(base_type(base_enum_type(t)));
+	t = default_type(core_type(t));
 
 	if (t->kind == Type_Basic) {
 		switch (t->Basic.kind) {
@@ -1041,7 +1095,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
 	GB_ASSERT_NOT_NULL(tv);
 
 	if (tv->value.kind != ExactValue_Invalid) {
-		Type *t = base_type(base_enum_type(tv->type));
+		Type *t = core_type(tv->type);
 		if (is_type_boolean(t)) {
 			return ssa_const_bool(p, tv->type, tv->value.value_bool);
 		} else if (is_type_string(t)) {
@@ -1675,16 +1729,9 @@ void ssa_print_reg_value(gbFile *f, ssaValue *v) {
 
 	ssa_print_exact_value(f, v);
 
-	if (ssa_op_uses_var_args(v->op)) {
-		for_array(i, v->var_args) {
-			gb_fprintf(f, " ");
-			ssa_print_value(f, v->var_args.e[i]);
-		}
-	} else {
-		for (isize i = 0; i < v->arg_count; i++) {
-			gb_fprintf(f, " ");
-			ssa_print_value(f, v->args[i]);
-		}
+	for_array(i, v->args) {
+		gb_fprintf(f, " ");
+		ssa_print_value(f, v->args.e[i]);
 	}
 
 	if (v->comment_string.len > 0) {
@@ -1733,21 +1780,11 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
 					continue;
 				}
 				bool skip = false;
-				if (ssa_op_uses_var_args(v->op)) {
-					for_array(k, v->var_args) {
-						ssaValue *w = v->var_args.e[k];
-						if (w != NULL && w->block == b && !printed[w->id]) {
-							skip = true;
-							break;
-						}
-					}
-				} else {
-					for (isize k = 0; k < v->arg_count; k++) {
-						ssaValue *w = v->args[k];
-						if (w != NULL && w->block == b && !printed[w->id]) {
-							skip = true;
-							break;
-						}
+				for_array(k, v->args) {
+					ssaValue *w = v->args.e[k];
+					if (w != NULL && w->block == b && !printed[w->id]) {
+						skip = true;
+						break;
 					}
 				}
 

+ 15 - 11
src/types.c

@@ -375,6 +375,10 @@ Type *base_enum_type(Type *t) {
 	return t;
 }
 
+Type *core_type(Type *t) {
+	return base_type(base_enum_type(t));
+}
+
 void set_base_type(Type *t, Type *base) {
 	if (t && t->kind == Type_Named) {
 		t->Named.base = base;
@@ -530,28 +534,28 @@ bool is_type_named(Type *t) {
 	return t->kind == Type_Named;
 }
 bool is_type_boolean(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Boolean) != 0;
 	}
 	return false;
 }
 bool is_type_integer(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Integer) != 0;
 	}
 	return false;
 }
 bool is_type_unsigned(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Unsigned) != 0;
 	}
 	return false;
 }
 bool is_type_numeric(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Numeric) != 0;
 	}
@@ -586,7 +590,7 @@ bool is_type_untyped(Type *t) {
 	return false;
 }
 bool is_type_ordered(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	switch (t->kind) {
 	case Type_Basic:
 		return (t->Basic.flags & BasicFlag_Ordered) != 0;
@@ -598,28 +602,28 @@ bool is_type_ordered(Type *t) {
 	return false;
 }
 bool is_type_constant_type(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_ConstantType) != 0;
 	}
 	return false;
 }
 bool is_type_float(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Float) != 0;
 	}
 	return false;
 }
 bool is_type_f32(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return t->Basic.kind == Basic_f32;
 	}
 	return false;
 }
 bool is_type_f64(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (t->kind == Type_Basic) {
 		return t->Basic.kind == Basic_f64;
 	}
@@ -737,7 +741,7 @@ bool is_type_untyped_nil(Type *t) {
 
 
 bool is_type_valid_for_keys(Type *t) {
-	t = base_type(base_enum_type(t));
+	t = core_type(t);
 	if (is_type_untyped(t)) {
 		return false;
 	}
@@ -798,7 +802,7 @@ bool is_type_comparable(Type *t) {
 		return true;
 	case Type_Record: {
 		if (is_type_enum(t)) {
-			return is_type_comparable(base_enum_type(t));
+			return is_type_comparable(core_type(t));
 		}
 		return false;
 	} break;

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff