-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This change adds AdvSimd and AdvSimd.Arm64 support to LLVM-enabled Mono. Most aarch64 LLVM intrinsic functions are overloaded and have names determined by an invariant base string prepended to a string representation of one or two type parameters. Intrinsic functions used by an LLVM module must have a declaration somewhere in memory when JITting or somewhere in the output bitcode file when AOTing. Currently Mono maintains a hash table that maps internal intrinsic IDs to LLVM intrinsic declarations. These IDs have been extended: a simplified type representation is added to the key's upper bits. This representation is not especially compact, and currently uses 9 bits to label 18 states, but it's easy to look at in a debugger. (A simple base-18 encoding could encode three parameters in 13 bits.) These overload-tagged IDs can be passed to `OP_XOP_OVR{_,_SCALAR,_BYSCALAR}X_{X,X_X,X_X_X}`. The return type of the intrinsic that generates these mini ops is used to derive the overload tag to find the corresponding LLVM intrinsic function declaration. `MonoLLVMModule::intrins_by_id` is removed, because LLVM intrinsic lookup keys are no longer small contiguous integers. It only seemed to serve as a lookup table for data already contained in a hash table. The corresponding instructions for some of these .NET-level intrinsics take immediate parameters. For some of these instructions, the LLVM IR code that selects these immediate-argument instructions can emit a fallback for non-constant parameters, either by using an equivalent instruction with a register operand or by using a longer and less-efficient instruction sequence. For the rest, a branching code sequence is emitted. Helper functions (`immediate_unroll_begin` etc.) are added to make this a little less repetitious. Some operations take an immediate operand denoting a lane to select in a vector before proceeding with another generic vector or scalar operation. These are decomposed into a sequence of `OP_ARM64_SELECT_SCALAR` followed by the non-lane-specific operation. LLVM can still optimize this to the lane-selecting instruction when possible, and can generate fallback code for non-immediate lane selection. The tables describing the intrinsics supported by the runtime are extended to support intrinsics with different target instructions for signed, unsigned and floating point parameters. Whenever possible, .NET-level intrinsics that correspond to a single LLVM intrinsic function are stored as a single entry in these tables. Unfortunately many intrinsics need to be translated into a sequence of LLVM IR operations; for these, new mini IR opcodes are added to select the LLVM IR builder code that should run.
- Loading branch information
Showing
10 changed files
with
3,421 additions
and
355 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#ifndef __MONO_MINI_LLVM_INTRINSICS_TYPES_H__ | ||
#define __MONO_MINI_LLVM_INTRINSICS_TYPES_H__ | ||
|
||
/* An intrinsic id. The lower 23 bits are used to store a mono-specific ID. The | ||
* next 9 bits store overload tag bits. In the configuration of LLVM 9 we use, | ||
* there are 7017 total intrinsics defined in IntrinsicEnums.inc, so only 13 | ||
* bits are needed to label each intrinsic overload group. | ||
*/ | ||
typedef enum { | ||
#define INTRINS(id, llvm_id) INTRINS_ ## id, | ||
#define INTRINS_OVR(id, llvm_id, ty) INTRINS_ ## id, | ||
#define INTRINS_OVR_2_ARG(id, llvm_id, ty1, ty2) INTRINS_ ## id, | ||
#define INTRINS_OVR_3_ARG(id, llvm_id, ty1, ty2, ty3) INTRINS_ ## id, | ||
#define INTRINS_OVR_TAG(id, ...) INTRINS_ ## id, | ||
#define INTRINS_OVR_TAG_KIND(id, ...) INTRINS_ ## id, | ||
#include "llvm-intrinsics.h" | ||
INTRINS_NUM | ||
} IntrinsicId; | ||
|
||
enum { | ||
XBINOP_FORCEINT_and, | ||
XBINOP_FORCEINT_or, | ||
XBINOP_FORCEINT_ornot, | ||
XBINOP_FORCEINT_xor, | ||
}; | ||
|
||
#endif /* __MONO_MINI_LLVM_INTRINSICS_TYPES_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.