diff --git a/sources/LLVMSharp/Types/ArrayType.cs b/sources/LLVMSharp/Types/ArrayType.cs index dbd1be0..20160a3 100644 --- a/sources/LLVMSharp/Types/ArrayType.cs +++ b/sources/LLVMSharp/Types/ArrayType.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. +using System; using LLVMSharp.Interop; namespace LLVMSharp; @@ -10,5 +11,13 @@ internal ArrayType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMArrayType { } + public static ArrayType Get(Type elementType, ulong numElements) + { + ArgumentNullException.ThrowIfNull(elementType); + var context = elementType.Context; + var handle = LLVMTypeRef.CreateArray2(elementType.Handle, numElements); + return context.GetOrCreate(handle); + } + public ulong NumElements => Handle.ArrayLength2; } diff --git a/sources/LLVMSharp/Types/FunctionType.cs b/sources/LLVMSharp/Types/FunctionType.cs index 65d521a..04878d7 100644 --- a/sources/LLVMSharp/Types/FunctionType.cs +++ b/sources/LLVMSharp/Types/FunctionType.cs @@ -11,6 +11,21 @@ internal FunctionType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMFuncti { } + public static FunctionType Get(Type returnType, Type[] parameterTypes, bool isVarArg = false) + { + ArgumentNullException.ThrowIfNull(parameterTypes); + return Get(returnType, parameterTypes.AsSpan(), isVarArg); + } + + public static FunctionType Get(Type returnType, ReadOnlySpan parameterTypes, bool isVarArg) + { + ArgumentNullException.ThrowIfNull(returnType); + var context = returnType.Context; + var handles = Type.GetHandles(parameterTypes, context, nameof(parameterTypes)); + var handle = LLVMTypeRef.CreateFunction(returnType.Handle, handles, isVarArg); + return context.GetOrCreate(handle); + } + public bool IsVarArg => Handle.IsFunctionVarArg; public uint NumParams => Handle.ParamTypesCount; diff --git a/sources/LLVMSharp/Types/PointerType.cs b/sources/LLVMSharp/Types/PointerType.cs index 4ef2ec6..6f072fa 100644 --- a/sources/LLVMSharp/Types/PointerType.cs +++ b/sources/LLVMSharp/Types/PointerType.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. +using System; using LLVMSharp.Interop; namespace LLVMSharp; @@ -11,4 +12,11 @@ internal PointerType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMPointer } public uint AddressSpace => Handle.PointerAddressSpace; + + public static PointerType Get(LLVMContext context, uint addressSpace = 0) + { + ArgumentNullException.ThrowIfNull(context); + var handle = context.Handle.CreatePointerType(addressSpace); + return context.GetOrCreate(handle); + } } diff --git a/sources/LLVMSharp/Types/StructType.cs b/sources/LLVMSharp/Types/StructType.cs index 06a1862..365ae7f 100644 --- a/sources/LLVMSharp/Types/StructType.cs +++ b/sources/LLVMSharp/Types/StructType.cs @@ -20,6 +20,20 @@ public static StructType Create(LLVMContext context, ReadOnlySpan name) return context.GetOrCreate(handle); } + public static StructType Get(LLVMContext context, Type[] elementTypes, bool packed = false) + { + ArgumentNullException.ThrowIfNull(elementTypes); + return Get(context, elementTypes.AsSpan(), packed); + } + + public static StructType Get(LLVMContext context, ReadOnlySpan elementTypes, bool packed) + { + ArgumentNullException.ThrowIfNull(context); + var handles = Type.GetHandles(elementTypes, context, nameof(elementTypes)); + var handle = context.Handle.GetStructType(handles, packed); + return context.GetOrCreate(handle); + } + public bool IsOpaque => Handle.IsOpaqueStruct; public bool IsPacked => Handle.IsPackedStruct; @@ -58,15 +72,7 @@ public void SetBody(Type[] elementTypes, bool packed) public void SetBody(ReadOnlySpan elementTypes, bool packed) { - var handles = new LLVMTypeRef[elementTypes.Length]; - - for (var i = 0; i < handles.Length; i++) - { - var elementType = elementTypes[i]; - ArgumentNullException.ThrowIfNull(elementType); - handles[i] = elementType.Handle; - } - + var handles = Type.GetHandles(elementTypes, Context, nameof(elementTypes)); Handle.StructSetBody(handles, packed); } } diff --git a/sources/LLVMSharp/Types/TargetExtType.cs b/sources/LLVMSharp/Types/TargetExtType.cs new file mode 100644 index 0000000..355324f --- /dev/null +++ b/sources/LLVMSharp/Types/TargetExtType.cs @@ -0,0 +1,75 @@ +// Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. + +using System; +using LLVMSharp.Interop; + +namespace LLVMSharp; + +public sealed class TargetExtType : Type +{ + internal TargetExtType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMTargetExtTypeKind) + { + } + + public string Name => Handle.TargetExtTypeName; + + public uint NumIntParameters => Handle.TargetExtTypeNumIntParams; + + public uint NumTypeParameters => Handle.TargetExtTypeNumTypeParams; + + public static TargetExtType Get(LLVMContext context, string name) + { + ArgumentNullException.ThrowIfNull(name); + return Get(context, name.AsSpan(), [], []); + } + + public static TargetExtType Get(LLVMContext context, string name, Type[] typeParameters, uint[] intParameters) + { + ArgumentNullException.ThrowIfNull(name); + ArgumentNullException.ThrowIfNull(typeParameters); + ArgumentNullException.ThrowIfNull(intParameters); + return Get(context, name.AsSpan(), typeParameters.AsSpan(), intParameters.AsSpan()); + } + + public static TargetExtType Get(LLVMContext context, string name, ReadOnlySpan typeParameters, ReadOnlySpan intParameters) + { + ArgumentNullException.ThrowIfNull(name); + return Get(context, name.AsSpan(), typeParameters, intParameters); + } + + public static TargetExtType Get(LLVMContext context, ReadOnlySpan name, ReadOnlySpan typeParameters, ReadOnlySpan intParameters) + { + ArgumentNullException.ThrowIfNull(context); + var handles = Type.GetHandles(typeParameters, context, nameof(typeParameters)); + var handle = context.Handle.CreateTargetExtType(name, handles, intParameters); + return context.GetOrCreate(handle); + } + + public uint GetIntParameter(uint index) => Handle.GetTargetExtTypeIntParam(index); + + public uint[] GetIntParameters() + { + var parameters = new uint[NumIntParameters]; + + for (var i = 0; i < parameters.Length; i++) + { + parameters[i] = GetIntParameter((uint)i); + } + + return parameters; + } + + public Type GetTypeParameter(uint index) => Context.GetOrCreate(Handle.GetTargetExtTypeTypeParam(index)); + + public Type[] GetTypeParameters() + { + var parameters = new Type[NumTypeParameters]; + + for (var i = 0; i < parameters.Length; i++) + { + parameters[i] = GetTypeParameter((uint)i); + } + + return parameters; + } +} diff --git a/sources/LLVMSharp/Types/Type.cs b/sources/LLVMSharp/Types/Type.cs index 759f2d0..17edf35 100644 --- a/sources/LLVMSharp/Types/Type.cs +++ b/sources/LLVMSharp/Types/Type.cs @@ -61,6 +61,8 @@ private protected Type(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind1, LLVMT public bool IsStructTy => Handle.Kind == LLVMTypeKind.LLVMStructTypeKind; + public bool IsTargetExtTy => Handle.Kind == LLVMTypeKind.LLVMTargetExtTypeKind; + public bool IsTokenTy => Handle.Kind == LLVMTypeKind.LLVMTokenTypeKind; public bool IsVectorTy => Handle.Kind is LLVMTypeKind.LLVMVectorTypeKind or LLVMTypeKind.LLVMScalableVectorTypeKind; @@ -107,6 +109,28 @@ public static Type GetHalfTy(LLVMContext c) return c.GetOrCreate(handle); } + public static Type? GetPrimitiveType(LLVMContext c, LLVMTypeKind kind) + { + ArgumentNullException.ThrowIfNull(c); + + return kind switch + { + LLVMTypeKind.LLVMVoidTypeKind => GetVoidTy(c), + LLVMTypeKind.LLVMHalfTypeKind => GetHalfTy(c), + LLVMTypeKind.LLVMBFloatTypeKind => GetBFloatTy(c), + LLVMTypeKind.LLVMFloatTypeKind => GetFloatTy(c), + LLVMTypeKind.LLVMDoubleTypeKind => GetDoubleTy(c), + LLVMTypeKind.LLVMX86_FP80TypeKind => GetX86_FP80Ty(c), + LLVMTypeKind.LLVMFP128TypeKind => GetFP128Ty(c), + LLVMTypeKind.LLVMPPC_FP128TypeKind => GetPPC_FP128Ty(c), + LLVMTypeKind.LLVMLabelTypeKind => GetLabelTy(c), + LLVMTypeKind.LLVMMetadataTypeKind => GetMetadataTy(c), + LLVMTypeKind.LLVMX86_AMXTypeKind => GetX86_AMXTy(c), + LLVMTypeKind.LLVMTokenTypeKind => GetTokenTy(c), + _ => null, + }; + } + public static IntegerType GetInt1Ty(LLVMContext c) { ArgumentNullException.ThrowIfNull(c); @@ -142,6 +166,20 @@ public static IntegerType GetInt64Ty(LLVMContext c) return c.GetOrCreate(handle); } + public static IntegerType GetInt128Ty(LLVMContext c) + { + ArgumentNullException.ThrowIfNull(c); + var handle = c.Handle.Int128Type; + return c.GetOrCreate(handle); + } + + public static IntegerType GetIntNTy(LLVMContext c, uint n) + { + ArgumentNullException.ThrowIfNull(c); + var handle = c.Handle.GetIntType(n); + return c.GetOrCreate(handle); + } + public static Type GetFP128Ty(LLVMContext c) { ArgumentNullException.ThrowIfNull(c); @@ -156,6 +194,13 @@ public static Type GetLabelTy(LLVMContext c) return c.GetOrCreate(handle); } + public static Type GetMetadataTy(LLVMContext c) + { + ArgumentNullException.ThrowIfNull(c); + var handle = c.Handle.MetadataType; + return c.GetOrCreate(handle); + } + public static Type GetPPC_FP128Ty(LLVMContext c) { ArgumentNullException.ThrowIfNull(c); @@ -163,6 +208,13 @@ public static Type GetPPC_FP128Ty(LLVMContext c) return c.GetOrCreate(handle); } + public static Type GetTokenTy(LLVMContext c) + { + ArgumentNullException.ThrowIfNull(c); + var handle = c.Handle.TokenType; + return c.GetOrCreate(handle); + } + public static Type GetVoidTy(LLVMContext c) { ArgumentNullException.ThrowIfNull(c); @@ -170,6 +222,17 @@ public static Type GetVoidTy(LLVMContext c) return c.GetOrCreate(handle); } + public static PointerType GetWasm_ExternrefTy(LLVMContext c) => PointerType.Get(c, 10); + + public static PointerType GetWasm_FuncrefTy(LLVMContext c) => PointerType.Get(c, 20); + + public static Type GetX86_AMXTy(LLVMContext c) + { + ArgumentNullException.ThrowIfNull(c); + var handle = c.Handle.X86AMXType; + return c.GetOrCreate(handle); + } + public static Type GetX86_FP80Ty(LLVMContext c) { ArgumentNullException.ThrowIfNull(c); @@ -210,7 +273,27 @@ public static Type GetX86_FP80Ty(LLVMContext c) LLVMTypeKind.LLVMScalableVectorTypeKind => new VectorType(handle), LLVMTypeKind.LLVMBFloatTypeKind => new Type(handle, LLVMTypeKind.LLVMBFloatTypeKind), LLVMTypeKind.LLVMX86_AMXTypeKind => new Type(handle, LLVMTypeKind.LLVMX86_AMXTypeKind), - LLVMTypeKind.LLVMTargetExtTypeKind => new Type(handle, LLVMTypeKind.LLVMTargetExtTypeKind), + LLVMTypeKind.LLVMTargetExtTypeKind => new TargetExtType(handle), _ => new Type(handle, handle.Kind), }; + + internal static LLVMTypeRef[] GetHandles(ReadOnlySpan types, LLVMContext context, string paramName) + { + var handles = new LLVMTypeRef[types.Length]; + + for (var i = 0; i < handles.Length; i++) + { + var type = types[i]; + ArgumentNullException.ThrowIfNull(type, paramName); + + if (type.Context != context) + { + throw new ArgumentException("All types must belong to the same context.", paramName); + } + + handles[i] = type.Handle; + } + + return handles; + } } diff --git a/sources/LLVMSharp/Types/VectorType.cs b/sources/LLVMSharp/Types/VectorType.cs index ac20f74..2205fc0 100644 --- a/sources/LLVMSharp/Types/VectorType.cs +++ b/sources/LLVMSharp/Types/VectorType.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. +using System; using LLVMSharp.Interop; namespace LLVMSharp; @@ -10,6 +11,16 @@ internal VectorType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMVectorTy { } + public static VectorType Get(Type elementType, uint elementCount, bool scalable = false) + { + ArgumentNullException.ThrowIfNull(elementType); + var context = elementType.Context; + var handle = scalable + ? LLVMTypeRef.CreateScalableVector(elementType.Handle, elementCount) + : LLVMTypeRef.CreateVector(elementType.Handle, elementCount); + return context.GetOrCreate(handle); + } + public bool IsScalable => Handle.Kind == LLVMTypeKind.LLVMScalableVectorTypeKind; public uint NumElements => Handle.VectorSize; diff --git a/tests/LLVMSharp.UnitTests/ManagedApi.cs b/tests/LLVMSharp.UnitTests/ManagedApi.cs index 8fbc7e4..8fa5efa 100644 --- a/tests/LLVMSharp.UnitTests/ManagedApi.cs +++ b/tests/LLVMSharp.UnitTests/ManagedApi.cs @@ -34,10 +34,34 @@ public void TypePredicates() Assert.That(int32.Context, Is.EqualTo(context)); Assert.That(((IntegerType)int32).BitWidth, Is.EqualTo(32u)); + var int128 = Type.GetInt128Ty(context); + Assert.That(int128.BitWidth, Is.EqualTo(128u)); + Assert.That(Type.GetIntNTy(context, 128), Is.SameAs(int128)); + Assert.That(Type.GetIntNTy(context, 256).BitWidth, Is.EqualTo(256u)); + var flt = Type.GetFloatTy(context); Assert.That(flt.IsFloatingPointTy, Is.True); Assert.That(flt.IsFloatTy, Is.True); Assert.That(flt.IsIntegerTy, Is.False); + + var metadata = Type.GetMetadataTy(context); + Assert.That(metadata.IsMetadataTy, Is.True); + Assert.That(metadata.Context, Is.SameAs(context)); + Assert.That(Type.GetPrimitiveType(context, LLVMTypeKind.LLVMMetadataTypeKind), Is.SameAs(metadata)); + + var token = Type.GetTokenTy(context); + Assert.That(token.IsTokenTy, Is.True); + Assert.That(token.Context, Is.SameAs(context)); + Assert.That(Type.GetPrimitiveType(context, LLVMTypeKind.LLVMTokenTypeKind), Is.SameAs(token)); + + var x86AMX = Type.GetX86_AMXTy(context); + Assert.That(x86AMX.IsX86AMXTy, Is.True); + Assert.That(x86AMX.Context, Is.SameAs(context)); + Assert.That(Type.GetPrimitiveType(context, LLVMTypeKind.LLVMX86_AMXTypeKind), Is.SameAs(x86AMX)); + Assert.That(Type.GetPrimitiveType(context, LLVMTypeKind.LLVMIntegerTypeKind), Is.Null); + + Assert.That(Type.GetWasm_ExternrefTy(context).AddressSpace, Is.EqualTo(10u)); + Assert.That(Type.GetWasm_FuncrefTy(context).AddressSpace, Is.EqualTo(20u)); } [Test] @@ -46,18 +70,24 @@ public void SequentialAndPointerTypes() var context = new LLVMContext(); var int32 = Type.GetInt32Ty(context); - var vector = (VectorType)context.GetOrCreate(LLVMTypeRef.CreateVector(int32.Handle, 4)); + var vector = VectorType.Get(int32, 4); Assert.That(vector.IsVectorTy, Is.True); + Assert.That(vector.IsScalable, Is.False); Assert.That(vector.NumElements, Is.EqualTo(4u)); Assert.That(vector.ElementType, Is.EqualTo(int32)); Assert.That(vector.ScalarType, Is.EqualTo(int32)); - var array = (ArrayType)context.GetOrCreate(LLVMTypeRef.CreateArray(int32.Handle, 8)); + var scalableVector = VectorType.Get(int32, 4, scalable: true); + Assert.That(scalableVector.IsVectorTy, Is.True); + Assert.That(scalableVector.IsScalable, Is.True); + Assert.That(scalableVector.NumElements, Is.EqualTo(4u)); + + var array = ArrayType.Get(int32, 8); Assert.That(array.IsArrayTy, Is.True); Assert.That(array.NumElements, Is.EqualTo(8ul)); Assert.That(array.ElementType, Is.EqualTo(int32)); - var pointer = (PointerType)context.GetOrCreate(LLVMTypeRef.CreatePointer(int32.Handle, 1)); + var pointer = PointerType.Get(context, 1); Assert.That(pointer.IsPointerTy, Is.True); Assert.That(pointer.AddressSpace, Is.EqualTo(1u)); } @@ -69,8 +99,7 @@ public void FunctionTypeAccessors() var int32 = Type.GetInt32Ty(context); var flt = Type.GetFloatTy(context); - var handle = LLVMTypeRef.CreateFunction(int32.Handle, [int32.Handle, flt.Handle], IsVarArg: false); - var functionType = (FunctionType)context.GetOrCreate(handle); + var functionType = FunctionType.Get(int32, [int32, flt]); Assert.That(functionType.IsFunctionTy, Is.True); Assert.That(functionType.ReturnType, Is.EqualTo(int32)); @@ -83,6 +112,26 @@ public void FunctionTypeAccessors() Assert.That(parameters[1], Is.EqualTo(flt)); } + [Test] + public void TargetExtensionTypeAccessors() + { + var context = new LLVMContext(); + var int32 = Type.GetInt32Ty(context); + + var targetExtType = TargetExtType.Get(context, "llvmsharp.test", [int32], [42]); + + Assert.That(targetExtType.IsTargetExtTy, Is.True); + Assert.That(targetExtType.Name, Is.EqualTo("llvmsharp.test")); + Assert.That(targetExtType.NumTypeParameters, Is.EqualTo(1u)); + Assert.That(targetExtType.NumIntParameters, Is.EqualTo(1u)); + Assert.That(targetExtType.GetTypeParameter(0), Is.SameAs(int32)); + Assert.That(targetExtType.GetTypeParameters(), Is.EqualTo(new Type[] { int32 })); + Assert.That(targetExtType.GetIntParameter(0), Is.EqualTo(42u)); + Assert.That(targetExtType.GetIntParameters(), Is.EqualTo(new uint[] { 42 })); + Assert.That(targetExtType.Context, Is.SameAs(context)); + Assert.That(TargetExtType.Get(context, "llvmsharp.test", [int32], [42]), Is.SameAs(targetExtType)); + } + [Test] public void StructTypeAccessors() { @@ -104,6 +153,11 @@ public void StructTypeAccessors() var elementTypes = structType.GetElementTypes(); Assert.That(elementTypes.Length, Is.EqualTo(2)); Assert.That(elementTypes[0], Is.EqualTo(int32)); + + var literalStructType = StructType.Get(context, [int32, flt], packed: true); + Assert.That(literalStructType.IsPacked, Is.True); + Assert.That(literalStructType.GetElementTypes(), Is.EqualTo(new Type[] { int32, flt })); + Assert.That(StructType.Get(context, [int32, flt], packed: true), Is.SameAs(literalStructType)); } [Test]