Browse Source

Add intrinsics.{ptr_offset, ptr_sub}

gingerBill 4 years ago
parent
commit
0f91ffe28f
3 changed files with 138 additions and 0 deletions
  1. 101 0
      src/check_builtin.cpp
  2. 6 0
      src/checker_builtin_procs.hpp
  3. 31 0
      src/llvm_backend.cpp

+ 101 - 0
src/check_builtin.cpp

@@ -2148,6 +2148,107 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		}
 		break;
 
+	case BuiltinProc_ptr_offset:
+		{
+			Operand ptr = {};
+			Operand offset = {};
+			check_expr(c, &ptr, ce->args[0]);
+			check_expr(c, &offset, ce->args[1]);
+			if (ptr.mode == Addressing_Invalid) {
+				operand->mode = Addressing_Invalid;
+				operand->type = t_invalid;
+				return false;
+			}
+			if (offset.mode == Addressing_Invalid) {
+				operand->mode = Addressing_Invalid;
+				operand->type = t_invalid;
+				return false;
+			}
+
+			operand->mode = Addressing_Value;
+			operand->type = ptr.type;
+
+			if (!is_type_pointer(ptr.type)) {
+				gbString str = type_to_string(ptr.type);
+				error(ptr.expr, "Expected a pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+			if (are_types_identical(core_type(ptr.type), t_rawptr)) {
+				gbString str = type_to_string(ptr.type);
+				error(ptr.expr, "Expected a dereferenceable pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+			if (!is_type_integer(offset.type)) {
+				gbString str = type_to_string(offset.type);
+				error(offset.expr, "Expected an integer value for the offset parameter for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+		}
+		break;
+	case BuiltinProc_ptr_sub:
+		{
+			operand->mode = Addressing_NoValue;
+			operand->type = t_invalid;
+
+			Operand ptr0 = {};
+			Operand ptr1 = {};
+			check_expr(c, &ptr0, ce->args[0]);
+			check_expr(c, &ptr1, ce->args[1]);
+			if (ptr0.mode == Addressing_Invalid) {
+				operand->mode = Addressing_Invalid;
+				operand->type = t_invalid;
+				return false;
+			}
+			if (ptr1.mode == Addressing_Invalid) {
+				operand->mode = Addressing_Invalid;
+				operand->type = t_invalid;
+				return false;
+			}
+
+			operand->mode = Addressing_Value;
+			operand->type = t_int;
+
+			if (!is_type_pointer(ptr0.type)) {
+				gbString str = type_to_string(ptr0.type);
+				error(ptr0.expr, "Expected a pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+			if (are_types_identical(core_type(ptr0.type), t_rawptr)) {
+				gbString str = type_to_string(ptr0.type);
+				error(ptr0.expr, "Expected a dereferenceable pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+
+			if (!is_type_pointer(ptr1.type)) {
+				gbString str = type_to_string(ptr1.type);
+				error(ptr1.expr, "Expected a pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+			if (are_types_identical(core_type(ptr1.type), t_rawptr)) {
+				gbString str = type_to_string(ptr1.type);
+				error(ptr1.expr, "Expected a dereferenceable pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str);
+				gb_string_free(str);
+				return false;
+			}
+
+			if (!are_types_identical(ptr0.type, ptr1.type)) {
+				gbString xts = type_to_string(ptr0.type);
+				gbString yts = type_to_string(ptr1.type);
+				error(ptr0.expr, "Mismatched types for '%.*s', %s vs %s", LIT(builtin_procs[id].name), xts, yts);
+				gb_string_free(yts);
+				gb_string_free(xts);
+				return false;
+			}
+
+		}
+		break;
+
 
 	case BuiltinProc_atomic_fence:
 	case BuiltinProc_atomic_fence_acq:

+ 6 - 0
src/checker_builtin_procs.hpp

@@ -62,6 +62,9 @@ enum BuiltinProcId {
 	BuiltinProc_mem_copy_non_overlapping,
 	BuiltinProc_mem_zero,
 
+	BuiltinProc_ptr_offset,
+	BuiltinProc_ptr_sub,
+
 	BuiltinProc_volatile_store,
 	BuiltinProc_volatile_load,
 
@@ -290,6 +293,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("mem_copy_non_overlapping"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT("mem_zero"),                 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 
+	{STR_LIT("ptr_offset"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("ptr_sub"),    2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
 	{STR_LIT("volatile_store"),  2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT("volatile_load"),   1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 

+ 31 - 0
src/llvm_backend.cpp

@@ -9580,6 +9580,37 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 			return {};
 		}
 
+	case BuiltinProc_ptr_offset:
+		{
+			lbValue ptr = lb_build_expr(p, ce->args[0]);
+			lbValue len = lb_build_expr(p, ce->args[1]);
+			len = lb_emit_conv(p, len, t_int);
+
+			LLVMValueRef indices[1] = {
+				len.value,
+			};
+
+			lbValue res = {};
+			res.type = tv.type;
+			res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), "");
+			return res;
+		}
+	case BuiltinProc_ptr_sub:
+		{
+			lbValue ptr0 = lb_build_expr(p, ce->args[0]);
+			lbValue ptr1 = lb_build_expr(p, ce->args[1]);
+
+			LLVMTypeRef type_int = lb_type(p->module, t_int);
+			LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, "");
+			diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, "");
+
+			lbValue res = {};
+			res.type = t_int;
+			res.value = diff;
+			return res;
+		}
+
+
 
 	case BuiltinProc_atomic_fence:
 		LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, "");