From dad01daffc3fa4e257abe8e33cb9f80fbaff71d7 Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:31:59 -0400 Subject: [PATCH] Intrinsify SpanHelper API's (#101622) --- src/mono/mono/mini/intrinsics.c | 37 ++++++++++++++++++++++++++++++++- src/mono/mono/mini/mini-llvm.c | 32 +++++++++++++++++++++------- src/mono/mono/mini/mini-ops.h | 1 + 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 4835a84e2c911..2c629adf59662 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -283,7 +283,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } - if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "Buffer")) { + if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "SpanHelpers")) { if (!strcmp (cmethod->name, "Memmove") && fsig->param_count == 3 && m_type_is_byref (fsig->params [0]) && m_type_is_byref (fsig->params [1]) && !cmethod->is_inflated) { MonoBasicBlock *end_bb; NEW_BBLOCK (cfg, end_bb); @@ -304,6 +304,41 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign ins->sreg3 = args [2]->dreg; // i32/i64 len MONO_ADD_INS (cfg->cbb, ins); MONO_START_BB (cfg, end_bb); + } else if (!strcmp (cmethod->name, "ClearWithoutReferences") && fsig->param_count == 2 && m_type_is_byref (fsig->params [0]) && !cmethod->is_inflated) { + MonoBasicBlock *end_bb; + NEW_BBLOCK (cfg, end_bb); + + // do nothing if len == 0 (even if src is null) + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [1]->dreg, 0); + MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, end_bb); + + // throw NRE if src is null + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [0]->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + + MONO_INST_NEW (cfg, ins, OP_MEMSET_ZERO); + ins->sreg1 = args [0]->dreg; // i1* dst + ins->sreg2 = args [1]->dreg; // i32/i64 len + MONO_ADD_INS (cfg->cbb, ins); + MONO_START_BB (cfg, end_bb); + } else if (!strcmp (cmethod->name, "Fill") && fsig->param_count == 3 && m_type_is_byref (fsig->params [0]) && !cmethod->is_inflated) { + MonoBasicBlock *end_bb; + NEW_BBLOCK (cfg, end_bb); + + // do nothing if len == 0 (even if src is null) + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [1]->dreg, 0); + MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, end_bb); + + // throw NRE if src is null + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [0]->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + + MONO_INST_NEW (cfg, ins, OP_MEMSET); + ins->sreg1 = args [0]->dreg; // i1* dst + ins->sreg2 = args [1]->dreg; // i8 value + ins->sreg3 = args [2]->dreg; // i32/i64 len + MONO_ADD_INS (cfg->cbb, ins); + MONO_START_BB (cfg, end_bb); } } diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 07bbe7d4e0037..0c0f4e0cb1f2e 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -1427,15 +1427,18 @@ convert (EmitContext *ctx, LLVMValueRef v, LLVMTypeRef dtype) } static void -emit_memset (EmitContext *ctx, LLVMValueRef v, LLVMValueRef size, int alignment) +emit_memset (EmitContext *ctx, LLVMValueRef dest, LLVMValueRef val, LLVMValueRef size, int alignment) { LLVMValueRef args [5]; int aindex = 0; - args [aindex ++] = v; - args [aindex ++] = LLVMConstInt (LLVMInt8Type (), 0, FALSE); + args [aindex ++] = dest; + if (val) + args [aindex ++] = val; + else + args [aindex ++] = LLVMConstInt (LLVMInt8Type (), 0, FALSE); args [aindex ++] = size; - args [aindex ++] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); + args [aindex ++] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); // is_volatile call_intrins (ctx, INTRINS_MEMSET, args, ""); } @@ -6159,7 +6162,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) * load it into registers. */ LLVMValueRef buf = build_alloca_llvm_type_name (ctx, pointer_type (ret_type), 0, "ret_buf"); - emit_memset (ctx, buf, LLVMSizeOf (ret_type), 1); + emit_memset (ctx, buf, NULL, LLVMSizeOf (ret_type), 1); int width = mono_type_size (sig->ret, NULL); LLVMValueRef args [] = { @@ -7000,7 +7003,7 @@ MONO_RESTORE_WARNING v = mono_llvm_build_alloca (builder, LLVMInt8Type (), const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT, ""); if (ins->flags & MONO_INST_INIT) - emit_memset (ctx, v, const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT); + emit_memset (ctx, v, NULL, const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT); values [ins->dreg] = v; break; @@ -7013,7 +7016,7 @@ MONO_RESTORE_WARNING v = mono_llvm_build_alloca (builder, LLVMInt8Type (), size, MONO_ARCH_FRAME_ALIGNMENT, ""); if (ins->flags & MONO_INST_INIT) - emit_memset (ctx, v, size, MONO_ARCH_FRAME_ALIGNMENT); + emit_memset (ctx, v, NULL, size, MONO_ARCH_FRAME_ALIGNMENT); values [ins->dreg] = v; break; } @@ -7231,6 +7234,19 @@ MONO_RESTORE_WARNING call_intrins (ctx, INTRINS_MEMMOVE, args, ""); break; } + case OP_MEMSET_ZERO: { + LLVMValueRef dest = convert (ctx, values [ins->sreg1], pointer_type (LLVMInt8Type ())); + LLVMValueRef size = convert (ctx, values [ins->sreg2], LLVMInt64Type ()); + emit_memset (ctx, dest, NULL, size, MONO_ARCH_FRAME_ALIGNMENT); + break; + } + case OP_MEMSET: { + LLVMValueRef dest = convert (ctx, values [ins->sreg1], pointer_type (LLVMInt8Type ())); + LLVMValueRef val = convert (ctx, values [ins->sreg2], LLVMInt8Type ()); + LLVMValueRef size = convert (ctx, values [ins->sreg3], LLVMInt64Type ()); + emit_memset (ctx, dest, val, size, MONO_ARCH_FRAME_ALIGNMENT); + break; + } case OP_NOT_REACHED: LLVMBuildUnreachable (builder); has_terminator = TRUE; @@ -7863,7 +7879,7 @@ MONO_RESTORE_WARNING addresses [ins->dreg] = create_address (ctx, build_named_alloca (ctx, m_class_get_byval_arg (klass), "vzero"), etype); } LLVMValueRef ptr = build_ptr_cast (builder, addresses [ins->dreg]->value, pointer_type (LLVMInt8Type ())); - emit_memset (ctx, ptr, const_int32 (mono_class_value_size (klass, NULL)), 0); + emit_memset (ctx, ptr, NULL, const_int32 (mono_class_value_size (klass, NULL)), 0); break; } case OP_DUMMY_VZERO: diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index ec82dd5de8a8c..edf7d1b3930db 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -775,6 +775,7 @@ MINI_OP(OP_LDELEMA2D, "ldelema2d", NONE, NONE, NONE) MINI_OP(OP_MEMCPY, "memcpy", NONE, NONE, NONE) /* inlined small memset with constant length */ MINI_OP(OP_MEMSET, "memset", NONE, NONE, NONE) +MINI_OP(OP_MEMSET_ZERO, "memset_zero", NONE, IREG, IREG) /* * A RuntimeType object, the result ldtoken+GetTypeFromHandle. * inst_p0 is a MonoClass.