Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions src/mono/mono/arch/arm64/arm64-codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,18 +523,19 @@ arm_encode_arith_imm (int imm, guint32 *shift)
/* Logical (immediate) */

// FIXME: imm
#if 0
#define arm_format_and(p, sf, opc, rd, rn, imm) arm_emit ((p), ((sf) << 31) | ((opc) << 29) | (0x24 << 23) | ((0) << 22) | ((imm) << 10) | ((rn) << 5) | ((rd) << 0))

#define arm_andx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x0, (rd), (rn), (imm))
#define arm_andw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x0, (rd), (rn), (imm))
#define arm_andsx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x3, (rd), (rn), (imm))
#define arm_andsw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x3, (rd), (rn), (imm))
#define arm_eorx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x2, (rd), (rn), (imm))
#define arm_eorw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x2, (rd), (rn), (imm))
#define arm_orrx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x1, (rd), (rn), (imm))
#define arm_orrw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x1, (rd), (rn), (imm))
#define arm_format_and(p, sf, opc, rd, rn, n, immr, imms) arm_emit ((p), 0b00010010000000000000000000000000 | ((sf) << 31) | ((opc) << 29) | ((n) << 22) | ((immr) << 16) | ((imms) << 10) | ((rn) << 5) | ((rd) << 0))

#define arm_andw_imm(p, rd, rn, immr, imms) arm_format_and ((p), 0b0, 0b00, (rd), (rn), 0b0, (immr), (imms))
#define arm_andx_imm(p, rd, rn, n, immr, imms) arm_format_and ((p), 0b1, 0b00, (rd), (rn), (n), (immr), (imms))
#define arm_andsw_imm(p, rd, rn, immr, imms) arm_format_and ((p), 0b0, 0b11, (rd), (rn), 0b0, (immr), (imms))
#define arm_andsx_imm(p, rd, rn, n, immr, imms) arm_format_and ((p), 0b1, 0b11, (rd), (rn), (n), (immr), (imms))
#define arm_eorw_imm(p, rd, rn, immr, imms) arm_format_and ((p), 0b0, 0b10, (rd), (rn), 0b0, (immr), (imms))
#define arm_eorx_imm(p, rd, rn, n, immr, imms) arm_format_and ((p), 0b1, 0b10, (rd), (rn), (n), (immr), (imms))
#define arm_orrw_imm(p, rd, rn, immr, imms) arm_format_and ((p), 0b0, 0b01, (rd), (rn), 0b0, (immr), (imms))
#define arm_orrx_imm(p, rd, rn, n, immr, imms) arm_format_and ((p), 0b1, 0b01, (rd), (rn), (n), (immr), (imms))

#if 0
#define arm_tstx_imm(p, rn, imm) arm_andsx_imm ((p), ARMREG_RZR, (rn), (imm))
#define arm_tstw_imm(p, rn, imm) arm_andsw_imm ((p), ARMREG_RZR, (rn), (imm))
#endif
Expand Down
106 changes: 88 additions & 18 deletions src/mono/mono/mini/mini-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-hwcap.h>
#include <mono/utils/mono-bitutils.h>
#include <mono/metadata/abi-details.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/marshal-shared.h>
#include "llvm-intrinsics-types.h"

#include "interp/interp.h"


// The following defines are here to support the inclusion of simd-arm64.h
#define EXPAND(x) x
#define PARENTHESIZE(...) (__VA_ARGS__)
Expand Down Expand Up @@ -620,62 +622,130 @@ emit_subx_sp_imm (guint8 *code, int imm)
return code;
}

static gboolean
encode_arm64_logical_imm (guint64 imm, gboolean islong, int* pn, int* pimms, int* pimmr)
{
if (imm == 0)
return FALSE;

// We recongnize the pattern 0*1+0* for 32- and 64-bit immediates.
// TODO: expand to full specification
int lsb_zero, band_one, msb_zero;
if (islong) {
lsb_zero = mono_tzcnt64 (imm);
msb_zero = mono_lzcnt64 (imm);
band_one = 64 - lsb_zero - msb_zero;

if (band_one == 0 || band_one == 64)
return FALSE;
} else {
lsb_zero = mono_tzcnt32 ((guint32)imm);
msb_zero = mono_lzcnt32 ((guint32)imm);
band_one = 32 - lsb_zero - msb_zero;

if (band_one == 0 || band_one == 32)
return FALSE;
}

guint64 expected_imm = ((1 << band_one) - 1) << lsb_zero;
if(imm != expected_imm)
return FALSE;

int imms = band_one - 1;
int immr = lsb_zero == 0 ? 0 : (msb_zero + band_one);
int n = islong ? 1 : 0;

g_assert (imms >= 0 && imms < 128);
g_assert (immr >= 0 && immr < 128);

if (pn) *pn = n;
if (pimms) *pimms = imms;
if (pimmr) *pimmr = immr;

return TRUE;
}


static WARN_UNUSED_RESULT guint8*
emit_andw_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_andw (code, dreg, sreg, ARMREG_LR);
int imms, immr;
if (encode_arm64_logical_imm (imm, FALSE, NULL, &imms, &immr)) {
arm_andw_imm (code, dreg, sreg, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_andw (code, dreg, sreg, ARMREG_LR);
}

return code;
}

static WARN_UNUSED_RESULT guint8*
emit_andx_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_andx (code, dreg, sreg, ARMREG_LR);
int n, imms, immr;
if (encode_arm64_logical_imm (imm, TRUE, &n, &imms, &immr)) {
arm_andx_imm (code, dreg, sreg, n, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_andx (code, dreg, sreg, ARMREG_LR);
}

return code;
}

static WARN_UNUSED_RESULT guint8*
emit_orrw_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_orrw (code, dreg, sreg, ARMREG_LR);
int imms, immr;
if (encode_arm64_logical_imm (imm, FALSE, NULL, &imms, &immr)) {
arm_orrw_imm (code, dreg, sreg, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_orrw (code, dreg, sreg, ARMREG_LR);
}

return code;
}

static WARN_UNUSED_RESULT guint8*
emit_orrx_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_orrx (code, dreg, sreg, ARMREG_LR);
int n, imms, immr;
if (encode_arm64_logical_imm (imm, TRUE, &n, &imms, &immr)) {
arm_orrx_imm (code, dreg, sreg, n, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_orrx (code, dreg, sreg, ARMREG_LR);
}

return code;
}

static WARN_UNUSED_RESULT guint8*
emit_eorw_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_eorw (code, dreg, sreg, ARMREG_LR);
int imms, immr;
if (encode_arm64_logical_imm (imm, FALSE, NULL, &imms, &immr)) {
arm_eorw_imm (code, dreg, sreg, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_eorw (code, dreg, sreg, ARMREG_LR);
}

return code;
}

static WARN_UNUSED_RESULT guint8*
emit_eorx_imm (guint8 *code, int dreg, int sreg, int imm)
{
// FIXME:
code = emit_imm (code, ARMREG_LR, imm);
arm_eorx (code, dreg, sreg, ARMREG_LR);
int n, imms, immr;
if (encode_arm64_logical_imm (imm, TRUE, &n, &imms, &immr)) {
arm_eorx_imm (code, dreg, sreg, n, immr, imms);
} else {
code = emit_imm (code, ARMREG_LR, imm);
arm_eorx (code, dreg, sreg, ARMREG_LR);
}

return code;
}
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ set(utils_common_sources
ftnptr.h
wasm-module-reader.h
wasm-module-reader.c
mono-bitutils.h
mono-bitutils.c
)

if(MONO_CROSS_COMPILE)
Expand Down
80 changes: 80 additions & 0 deletions src/mono/mono/utils/mono-bitutils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* \file
*/

#include "mono/utils/mono-bitutils.h"

#ifdef _MSC_VER
#include <intrin.h>
#endif

#define LOW32(x) ((guint32)(x & 0xffffffff))
#define HIGH32(x) ((guint32)((x >> 32) & 0xffffffff))

int mono_lzcnt32 (guint32 x)
{
#ifdef _MSC_VER
unsigned long index = 0;
if ( _BitScanReverse( &index, x ) )
return (int)index;
else
return 32;
#else
return __builtin_clz(x);
#endif
}

int mono_lzcnt64 (guint64 x)
{
#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined (_M_X64))
unsigned long index = 0;
if ( _BitScanReverse64( &index, x ) )
return (int)index;
else
return 64;
#elif defined(_MSC_VER)
guint32 high = HIGH32 (x);
if (x == 0)
return 64;
else if (high == 0)
return mono_lzcnt32 (LOW32 (x)) + 32;
else
return mono_lzcnt32 (high);
#else
return __builtin_clzll(x);
#endif
}

int mono_tzcnt32 (guint32 x)
{
#ifdef _MSC_VER
unsigned long index = 0;
if ( _BitScanForward( &index, x ) )
return (int)index;
else
return 32;
#else
return __builtin_ctz(x);
#endif
}

int mono_tzcnt64 (guint64 x)
{
#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined (_M_X64))
unsigned long index = 0;
if ( _BitScanForward64( &index, x ) )
return (int)index;
else
return 64;
#elif defined(_MSC_VER)
guint32 low = LOW32 (x);
if (x == 0)
return 64;
else if (low == 0)
return mono_tzcnt32 (HIGH32 (x)) + 32;
else
return mono_tzcnt32 (low);
#else
return __builtin_ctzll(x);
#endif
}
11 changes: 11 additions & 0 deletions src/mono/mono/utils/mono-bitutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef __MONO_BITUTILS_H__
#define __MONO_BITUTILS_H__

#include <glib.h>

int mono_lzcnt32 (guint32 x);
int mono_lzcnt64 (guint64 x);
int mono_tzcnt32 (guint32 x);
int mono_tzcnt64 (guint64 x);

#endif