Add inlined memcpy and memset builtins and macros. (#668)

This commit is contained in:
Dmitry Atamanov
2022-12-12 15:45:01 +05:00
committed by GitHub
parent 50d2a04c48
commit 8b0d409695
11 changed files with 74 additions and 35 deletions

View File

@@ -850,8 +850,10 @@ typedef enum
BUILTIN_LOG2,
BUILTIN_MAX,
BUILTIN_MEMCOPY,
BUILTIN_MEMCOPY_INLINE,
BUILTIN_MEMMOVE,
BUILTIN_MEMSET,
BUILTIN_MEMSET_INLINE,
BUILTIN_MIN,
BUILTIN_NEARBYINT,
BUILTIN_OVERFLOW_ADD,

View File

@@ -658,8 +658,10 @@ static void llvm_codegen_setup()
intrinsic_id.maximum = lookup_intrinsic("llvm.maximum");
intrinsic_id.maxnum = lookup_intrinsic("llvm.maxnum");
intrinsic_id.memcpy = lookup_intrinsic("llvm.memcpy");
intrinsic_id.memset = lookup_intrinsic("llvm.memset");
intrinsic_id.memcpy_inline = lookup_intrinsic("llvm.memcpy.inline");
intrinsic_id.memmove = lookup_intrinsic("llvm.memmove");
intrinsic_id.memset = lookup_intrinsic("llvm.memset");
intrinsic_id.memset_inline = lookup_intrinsic("llvm.memset.inline");
intrinsic_id.minimum = lookup_intrinsic("llvm.minimum");
intrinsic_id.minnum = lookup_intrinsic("llvm.minnum");
intrinsic_id.fmuladd = lookup_intrinsic("llvm.fmuladd");

View File

@@ -215,7 +215,7 @@ INLINE void llvm_emit_intrinsic_args(GenContext *c, Expr **args, LLVMValueRef *s
}
}
INLINE void llvm_emit_memcpy_builtin(GenContext *c, BEValue *be_value, Expr *expr)
INLINE void llvm_emit_memcpy_builtin(GenContext *c, unsigned intrinsic, BEValue *be_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
LLVMValueRef arg_slots[4];
@@ -225,7 +225,7 @@ INLINE void llvm_emit_memcpy_builtin(GenContext *c, BEValue *be_value, Expr *exp
LLVMTypeRef call_type[3];
call_type[0] = call_type[1] = llvm_get_type(c, type_voidptr);
call_type[2] = llvm_get_type(c, type_usize);
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic_id.memcpy, call_type, 3, arg_slots, 4);
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, call_type, 3, arg_slots, 4);
assert(args[4]->const_expr.const_kind == CONST_INTEGER);
assert(args[5]->const_expr.const_kind == CONST_INTEGER);
uint64_t dst_align = int_to_u64(args[4]->const_expr.ixx);
@@ -235,20 +235,6 @@ INLINE void llvm_emit_memcpy_builtin(GenContext *c, BEValue *be_value, Expr *exp
llvm_value_set(be_value, result, type_void);
}
INLINE void llvm_emit_memset_builtin(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
LLVMValueRef arg_slots[4];
llvm_emit_intrinsic_args(c, args, arg_slots, 4);
arg_slots[0] = llvm_emit_bitcast(c, arg_slots[0], type_voidptr);
LLVMTypeRef call_type[2] = { llvm_get_type(c, type_voidptr), llvm_get_type(c, type_usize) };
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic_id.memset, call_type, 2, arg_slots, 4);
assert(args[4]->const_expr.const_kind == CONST_INTEGER);
uint64_t dst_align = int_to_u64(args[4]->const_expr.ixx);
if (dst_align > 0) llvm_attribute_add_call(c, result, attribute_id.align, 1, dst_align);
llvm_value_set(be_value, result, type_void);
}
INLINE void llvm_emit_memmove_builtin(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
@@ -268,6 +254,21 @@ INLINE void llvm_emit_memmove_builtin(GenContext *c, BEValue *be_value, Expr *ex
if (src_align > 0) llvm_attribute_add_call(c, result, attribute_id.align, 2, src_align);
llvm_value_set(be_value, result, type_void);
}
INLINE void llvm_emit_memset_builtin(GenContext *c, unsigned intrinsic, BEValue *be_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
LLVMValueRef arg_slots[4];
llvm_emit_intrinsic_args(c, args, arg_slots, 4);
arg_slots[0] = llvm_emit_bitcast(c, arg_slots[0], type_voidptr);
LLVMTypeRef call_type[2] = { llvm_get_type(c, type_voidptr), llvm_get_type(c, type_usize) };
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, call_type, 2, arg_slots, 4);
assert(args[4]->const_expr.const_kind == CONST_INTEGER);
uint64_t dst_align = int_to_u64(args[4]->const_expr.ixx);
if (dst_align > 0) llvm_attribute_add_call(c, result, attribute_id.align, 1, dst_align);
llvm_value_set(be_value, result, type_void);
}
INLINE void llvm_emit_prefetch(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
@@ -473,14 +474,20 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
llvm_emit_syscall(c, result_value, expr);
return;
case BUILTIN_MEMCOPY:
llvm_emit_memcpy_builtin(c, result_value, expr);
llvm_emit_memcpy_builtin(c, intrinsic_id.memcpy, result_value, expr);
return;
case BUILTIN_MEMSET:
llvm_emit_memset_builtin(c, result_value, expr);
case BUILTIN_MEMCOPY_INLINE:
llvm_emit_memcpy_builtin(c, intrinsic_id.memcpy_inline, result_value, expr);
return;
case BUILTIN_MEMMOVE:
llvm_emit_memmove_builtin(c, result_value, expr);
return;
case BUILTIN_MEMSET:
llvm_emit_memset_builtin(c, intrinsic_id.memset, result_value, expr);
return;
case BUILTIN_MEMSET_INLINE:
llvm_emit_memset_builtin(c, intrinsic_id.memset_inline, result_value, expr);
return;
case BUILTIN_SYSCLOCK:
llvm_value_set(result_value, llvm_emit_call_intrinsic(c, intrinsic_id.readcyclecounter, NULL, 0, NULL, 0), expr->type);
return;

View File

@@ -134,6 +134,7 @@ typedef struct
unsigned floor;
unsigned flt_rounds;
unsigned fma;
unsigned fmuladd;
unsigned frameaddress;
unsigned fshl;
unsigned fshr;
@@ -149,11 +150,12 @@ typedef struct
unsigned maximum;
unsigned maxnum;
unsigned memcpy;
unsigned memset;
unsigned memcpy_inline;
unsigned memmove;
unsigned memset;
unsigned memset_inline;
unsigned minimum;
unsigned minnum;
unsigned fmuladd;
unsigned nearbyint;
unsigned pow;
unsigned powi;

View File

@@ -349,6 +349,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
rtype = type_no_optional(args[0]->type->canonical);
break;
case BUILTIN_MEMCOPY:
case BUILTIN_MEMCOPY_INLINE:
case BUILTIN_MEMMOVE:
if (!sema_check_builtin_args(args,
(BuiltinArg[]) { BA_POINTER, BA_POINTER, BA_SIZE, BA_BOOL, BA_SIZE, BA_SIZE },
@@ -357,6 +358,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
rtype = type_void;
break;
case BUILTIN_MEMSET:
case BUILTIN_MEMSET_INLINE:
if (!sema_check_builtin_args(args,
(BuiltinArg[]) { BA_POINTER, BA_CHAR, BA_SIZE, BA_BOOL, BA_SIZE },
arg_count)) return false;
@@ -620,11 +622,13 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
case BUILTIN_OVERFLOW_SUB:
case BUILTIN_PREFETCH:
return 3;
case BUILTIN_MEMSET:
return 5;
case BUILTIN_MEMCOPY:
case BUILTIN_MEMCOPY_INLINE:
case BUILTIN_MEMMOVE:
return 6;
case BUILTIN_MEMSET:
case BUILTIN_MEMSET_INLINE:
return 5;
case BUILTIN_SHUFFLEVECTOR:
case BUILTIN_NONE:
UNREACHABLE

View File

@@ -211,8 +211,10 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_LOG2] = KW_DEF("log2");
builtin_list[BUILTIN_LOG10] = KW_DEF("log10");
builtin_list[BUILTIN_MEMCOPY] = KW_DEF("memcpy");
builtin_list[BUILTIN_MEMSET] = KW_DEF("memset");
builtin_list[BUILTIN_MEMCOPY_INLINE] = KW_DEF("memcpy_inline");
builtin_list[BUILTIN_MEMMOVE] = KW_DEF("memmove");
builtin_list[BUILTIN_MEMSET] = KW_DEF("memset");
builtin_list[BUILTIN_MEMSET_INLINE] = KW_DEF("memset_inline");
builtin_list[BUILTIN_NEARBYINT] = KW_DEF("nearbyint");
builtin_list[BUILTIN_OVERFLOW_ADD] = KW_DEF("overflow_add");
builtin_list[BUILTIN_OVERFLOW_SUB] = KW_DEF("overflow_sub");