From 2552575e93186790be984dd36f869998228fa768 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jul 2026 21:21:35 -0700 Subject: [PATCH 1/5] Add managed CmpInst static predicate helpers Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Users/Instructions/CmpInst.Predicate.cs | 151 ++++++++++++++++++ .../Values/Users/Instructions/FCmpInst.cs | 2 + .../Values/Users/Instructions/ICmpInst.cs | 25 +++ 3 files changed, 178 insertions(+) diff --git a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.Predicate.cs b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.Predicate.cs index fd1a65c7..559111a4 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.Predicate.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.Predicate.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; @@ -36,4 +37,154 @@ public enum Predicate ICMP_SLT = LLVMIntPredicate.LLVMIntSLT, ICMP_SLE = LLVMIntPredicate.LLVMIntSLE, } + + public static bool IsFPPredicate(Predicate predicate) => predicate <= Predicate.FCMP_TRUE; + + public static bool IsIntPredicate(Predicate predicate) => predicate is >= Predicate.ICMP_EQ and <= Predicate.ICMP_SLE; + + public static Predicate GetInversePredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_EQ => Predicate.ICMP_NE, + Predicate.ICMP_NE => Predicate.ICMP_EQ, + Predicate.ICMP_UGT => Predicate.ICMP_ULE, + Predicate.ICMP_ULT => Predicate.ICMP_UGE, + Predicate.ICMP_UGE => Predicate.ICMP_ULT, + Predicate.ICMP_ULE => Predicate.ICMP_UGT, + Predicate.ICMP_SGT => Predicate.ICMP_SLE, + Predicate.ICMP_SLT => Predicate.ICMP_SGE, + Predicate.ICMP_SGE => Predicate.ICMP_SLT, + Predicate.ICMP_SLE => Predicate.ICMP_SGT, + Predicate.FCMP_OEQ => Predicate.FCMP_UNE, + Predicate.FCMP_ONE => Predicate.FCMP_UEQ, + Predicate.FCMP_OGT => Predicate.FCMP_ULE, + Predicate.FCMP_OLT => Predicate.FCMP_UGE, + Predicate.FCMP_OGE => Predicate.FCMP_ULT, + Predicate.FCMP_OLE => Predicate.FCMP_UGT, + Predicate.FCMP_UEQ => Predicate.FCMP_ONE, + Predicate.FCMP_UNE => Predicate.FCMP_OEQ, + Predicate.FCMP_UGT => Predicate.FCMP_OLE, + Predicate.FCMP_ULT => Predicate.FCMP_OGE, + Predicate.FCMP_UGE => Predicate.FCMP_OLT, + Predicate.FCMP_ULE => Predicate.FCMP_OGT, + Predicate.FCMP_ORD => Predicate.FCMP_UNO, + Predicate.FCMP_UNO => Predicate.FCMP_ORD, + Predicate.FCMP_TRUE => Predicate.FCMP_FALSE, + Predicate.FCMP_FALSE => Predicate.FCMP_TRUE, + _ => throw new ArgumentOutOfRangeException(nameof(predicate)), + }; + + public static Predicate GetOrderedPredicate(Predicate predicate) => (Predicate)((int)predicate & (int)Predicate.FCMP_ORD); + + public static Predicate GetUnorderedPredicate(Predicate predicate) => (Predicate)((int)predicate | (int)Predicate.FCMP_UNO); + + public static Predicate GetSwappedPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_SGT => Predicate.ICMP_SLT, + Predicate.ICMP_SLT => Predicate.ICMP_SGT, + Predicate.ICMP_SGE => Predicate.ICMP_SLE, + Predicate.ICMP_SLE => Predicate.ICMP_SGE, + Predicate.ICMP_UGT => Predicate.ICMP_ULT, + Predicate.ICMP_ULT => Predicate.ICMP_UGT, + Predicate.ICMP_UGE => Predicate.ICMP_ULE, + Predicate.ICMP_ULE => Predicate.ICMP_UGE, + Predicate.FCMP_OGT => Predicate.FCMP_OLT, + Predicate.FCMP_OLT => Predicate.FCMP_OGT, + Predicate.FCMP_OGE => Predicate.FCMP_OLE, + Predicate.FCMP_OLE => Predicate.FCMP_OGE, + Predicate.FCMP_UGT => Predicate.FCMP_ULT, + Predicate.FCMP_ULT => Predicate.FCMP_UGT, + Predicate.FCMP_UGE => Predicate.FCMP_ULE, + Predicate.FCMP_ULE => Predicate.FCMP_UGE, + _ => predicate, + }; + + public static bool IsStrictPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_SGT or Predicate.ICMP_SLT or Predicate.ICMP_UGT or Predicate.ICMP_ULT or + Predicate.FCMP_OGT or Predicate.FCMP_OLT or Predicate.FCMP_UGT or Predicate.FCMP_ULT => true, + _ => false, + }; + + public static Predicate GetStrictPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_SGE => Predicate.ICMP_SGT, + Predicate.ICMP_SLE => Predicate.ICMP_SLT, + Predicate.ICMP_UGE => Predicate.ICMP_UGT, + Predicate.ICMP_ULE => Predicate.ICMP_ULT, + Predicate.FCMP_OGE => Predicate.FCMP_OGT, + Predicate.FCMP_OLE => Predicate.FCMP_OLT, + Predicate.FCMP_UGE => Predicate.FCMP_UGT, + Predicate.FCMP_ULE => Predicate.FCMP_ULT, + _ => predicate, + }; + + public static Predicate GetNonStrictPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_SGT => Predicate.ICMP_SGE, + Predicate.ICMP_SLT => Predicate.ICMP_SLE, + Predicate.ICMP_UGT => Predicate.ICMP_UGE, + Predicate.ICMP_ULT => Predicate.ICMP_ULE, + Predicate.FCMP_OGT => Predicate.FCMP_OGE, + Predicate.FCMP_OLT => Predicate.FCMP_OLE, + Predicate.FCMP_UGT => Predicate.FCMP_UGE, + Predicate.FCMP_ULT => Predicate.FCMP_ULE, + _ => predicate, + }; + + public static bool IsEquality(Predicate predicate) + { + if (IsIntPredicate(predicate)) + { + return ICmpInst.IsEquality(predicate); + } + + if (IsFPPredicate(predicate)) + { + return FCmpInst.IsEquality(predicate); + } + + throw new ArgumentOutOfRangeException(nameof(predicate)); + } + + public static bool IsRelational(Predicate predicate) => !IsEquality(predicate); + + public static bool IsSigned(Predicate predicate) => predicate switch + { + Predicate.ICMP_SLT or Predicate.ICMP_SLE or Predicate.ICMP_SGT or Predicate.ICMP_SGE => true, + _ => false, + }; + + public static bool IsUnsigned(Predicate predicate) => predicate switch + { + Predicate.ICMP_ULT or Predicate.ICMP_ULE or Predicate.ICMP_UGT or Predicate.ICMP_UGE => true, + _ => false, + }; + + public static bool IsOrdered(Predicate predicate) => predicate switch + { + Predicate.FCMP_OEQ or Predicate.FCMP_ONE or Predicate.FCMP_OGT or + Predicate.FCMP_OLT or Predicate.FCMP_OGE or Predicate.FCMP_OLE or Predicate.FCMP_ORD => true, + _ => false, + }; + + public static bool IsUnordered(Predicate predicate) => predicate switch + { + Predicate.FCMP_UEQ or Predicate.FCMP_UNE or Predicate.FCMP_UGT or + Predicate.FCMP_ULT or Predicate.FCMP_UGE or Predicate.FCMP_ULE or Predicate.FCMP_UNO => true, + _ => false, + }; + + public static bool IsTrueWhenEqual(Predicate predicate) => predicate switch + { + Predicate.ICMP_EQ or Predicate.ICMP_UGE or Predicate.ICMP_ULE or Predicate.ICMP_SGE or Predicate.ICMP_SLE or + Predicate.FCMP_TRUE or Predicate.FCMP_UEQ or Predicate.FCMP_UGE or Predicate.FCMP_ULE => true, + _ => false, + }; + + public static bool IsFalseWhenEqual(Predicate predicate) => predicate switch + { + Predicate.ICMP_NE or Predicate.ICMP_UGT or Predicate.ICMP_ULT or Predicate.ICMP_SGT or Predicate.ICMP_SLT or + Predicate.FCMP_FALSE or Predicate.FCMP_ONE or Predicate.FCMP_OGT or Predicate.FCMP_OLT => true, + _ => false, + }; } diff --git a/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs index 86980f82..4d706737 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs @@ -9,4 +9,6 @@ public sealed class FCmpInst : CmpInst internal FCmpInst(LLVMValueRef handle) : base(handle.IsAFCmpInst) { } + + public static new bool IsEquality(Predicate predicate) => predicate is Predicate.FCMP_OEQ or Predicate.FCMP_ONE or Predicate.FCMP_UEQ or Predicate.FCMP_UNE; } diff --git a/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs index beb1ad86..4a015e95 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.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; @@ -23,4 +24,28 @@ public bool HasSameSign handle.ICmpSameSign = value; } } + + public static new bool IsEquality(Predicate predicate) => predicate is Predicate.ICMP_EQ or Predicate.ICMP_NE; + + public static Predicate GetSignedPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_EQ or Predicate.ICMP_NE or + Predicate.ICMP_SGT or Predicate.ICMP_SLT or Predicate.ICMP_SGE or Predicate.ICMP_SLE => predicate, + Predicate.ICMP_UGT => Predicate.ICMP_SGT, + Predicate.ICMP_ULT => Predicate.ICMP_SLT, + Predicate.ICMP_UGE => Predicate.ICMP_SGE, + Predicate.ICMP_ULE => Predicate.ICMP_SLE, + _ => throw new ArgumentOutOfRangeException(nameof(predicate)), + }; + + public static Predicate GetUnsignedPredicate(Predicate predicate) => predicate switch + { + Predicate.ICMP_EQ or Predicate.ICMP_NE or + Predicate.ICMP_UGT or Predicate.ICMP_ULT or Predicate.ICMP_UGE or Predicate.ICMP_ULE => predicate, + Predicate.ICMP_SGT => Predicate.ICMP_UGT, + Predicate.ICMP_SLT => Predicate.ICMP_ULT, + Predicate.ICMP_SGE => Predicate.ICMP_UGE, + Predicate.ICMP_SLE => Predicate.ICMP_ULE, + _ => throw new ArgumentOutOfRangeException(nameof(predicate)), + }; } From ee066548bfda3b3718f57da9b7fb1c590ba54aca Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jul 2026 21:21:35 -0700 Subject: [PATCH 2/5] Add managed VectorType support for scalable vectors Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- sources/LLVMSharp/Types/CompositeType.cs | 4 ++++ sources/LLVMSharp/Types/SequentialType.cs | 4 ++++ sources/LLVMSharp/Types/Type.cs | 11 ++++++++++- sources/LLVMSharp/Types/VectorType.cs | 4 +++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/sources/LLVMSharp/Types/CompositeType.cs b/sources/LLVMSharp/Types/CompositeType.cs index d560b9a9..7d25a9b7 100644 --- a/sources/LLVMSharp/Types/CompositeType.cs +++ b/sources/LLVMSharp/Types/CompositeType.cs @@ -9,4 +9,8 @@ public class CompositeType : Type private protected CompositeType(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind) : base(handle, expectedTypeKind) { } + + private protected CompositeType(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind1, LLVMTypeKind expectedTypeKind2) : base(handle, expectedTypeKind1, expectedTypeKind2) + { + } } diff --git a/sources/LLVMSharp/Types/SequentialType.cs b/sources/LLVMSharp/Types/SequentialType.cs index 4e2207f6..d76cfcd6 100644 --- a/sources/LLVMSharp/Types/SequentialType.cs +++ b/sources/LLVMSharp/Types/SequentialType.cs @@ -10,5 +10,9 @@ private protected SequentialType(LLVMTypeRef handle, LLVMTypeKind expectedTypeKi { } + private protected SequentialType(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind1, LLVMTypeKind expectedTypeKind2) : base(handle, expectedTypeKind1, expectedTypeKind2) + { + } + public Type ElementType => Context.GetOrCreate(Handle.ElementType); } diff --git a/sources/LLVMSharp/Types/Type.cs b/sources/LLVMSharp/Types/Type.cs index bbcd4f4c..759f2d04 100644 --- a/sources/LLVMSharp/Types/Type.cs +++ b/sources/LLVMSharp/Types/Type.cs @@ -16,6 +16,15 @@ private protected Type(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind) Handle = handle; } + private protected Type(LLVMTypeRef handle, LLVMTypeKind expectedTypeKind1, LLVMTypeKind expectedTypeKind2) + { + if ((handle.Kind != expectedTypeKind1) && (handle.Kind != expectedTypeKind2)) + { + throw new ArgumentOutOfRangeException(nameof(handle)); + } + Handle = handle; + } + public LLVMTypeRef Handle { get; } public LLVMContext Context => LLVMContext.GetOrCreate(Handle.Context); @@ -198,7 +207,7 @@ public static Type GetX86_FP80Ty(LLVMContext c) LLVMTypeKind.LLVMVectorTypeKind => new VectorType(handle), LLVMTypeKind.LLVMMetadataTypeKind => new Type(handle, LLVMTypeKind.LLVMMetadataTypeKind), LLVMTypeKind.LLVMTokenTypeKind => new Type(handle, LLVMTypeKind.LLVMTokenTypeKind), - LLVMTypeKind.LLVMScalableVectorTypeKind => new Type(handle, LLVMTypeKind.LLVMScalableVectorTypeKind), + 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), diff --git a/sources/LLVMSharp/Types/VectorType.cs b/sources/LLVMSharp/Types/VectorType.cs index 3aa4a6f8..ac20f745 100644 --- a/sources/LLVMSharp/Types/VectorType.cs +++ b/sources/LLVMSharp/Types/VectorType.cs @@ -6,9 +6,11 @@ namespace LLVMSharp; public sealed class VectorType : SequentialType { - internal VectorType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMVectorTypeKind) + internal VectorType(LLVMTypeRef handle) : base(handle, LLVMTypeKind.LLVMVectorTypeKind, LLVMTypeKind.LLVMScalableVectorTypeKind) { } + public bool IsScalable => Handle.Kind == LLVMTypeKind.LLVMScalableVectorTypeKind; + public uint NumElements => Handle.VectorSize; } From 0d8e51b635d1a8b9de477fcb96fe0293046294d8 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jul 2026 21:21:35 -0700 Subject: [PATCH 3/5] Add managed Function.IsIntrinsic accessor Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../LLVMSharp/Values/Users/Constants/GlobalValues/Function.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sources/LLVMSharp/Values/Users/Constants/GlobalValues/Function.cs b/sources/LLVMSharp/Values/Users/Constants/GlobalValues/Function.cs index dcd3d999..2e1ac124 100644 --- a/sources/LLVMSharp/Values/Users/Constants/GlobalValues/Function.cs +++ b/sources/LLVMSharp/Values/Users/Constants/GlobalValues/Function.cs @@ -53,6 +53,8 @@ public string GC public uint IntrinsicID => Handle.IntrinsicID; + public bool IsIntrinsic => Handle.IntrinsicID != 0; + public uint NumParams => Handle.ParamsCount; public Constant? PersonalityFn From 1ddfc4dc157da2eaa666a4b6620c4674f74d905e Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jul 2026 21:30:39 -0700 Subject: [PATCH 4/5] Add managed Comdat type Wrap LLVMComdatRef in a managed Comdat exposing SelectionKind, add the LLVMValueRef.Comdat / LLVMComdatRef.SelectionKind / LLVMModuleRef.GetOrInsertComdat interop accessors it builds on, and surface GlobalObject.Comdat/HasComdat and Module.GetOrInsertComdat over the existing LLVM-C comdat API. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- sources/LLVMSharp/Comdat.cs | 37 +++++++++++++++++++ sources/LLVMSharp/Module.cs | 2 + .../Constants/GlobalValues/GlobalObject.cs | 18 +++++++++ tests/LLVMSharp.UnitTests/ManagedApi.cs | 27 ++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 sources/LLVMSharp/Comdat.cs diff --git a/sources/LLVMSharp/Comdat.cs b/sources/LLVMSharp/Comdat.cs new file mode 100644 index 00000000..85fa337d --- /dev/null +++ b/sources/LLVMSharp/Comdat.cs @@ -0,0 +1,37 @@ +// 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 Comdat(LLVMComdatRef handle) : IEquatable +{ + public LLVMComdatRef Handle { get; } = handle; + + public LLVMComdatSelectionKind SelectionKind + { + get + { + return Handle.SelectionKind; + } + + set + { + var handle = Handle; + handle.SelectionKind = value; + } + } + + public static bool operator ==(Comdat? left, Comdat? right) => ReferenceEquals(left, right) || (left?.Handle == right?.Handle); + + public static bool operator !=(Comdat? left, Comdat? right) => !(left == right); + + public override bool Equals(object? obj) => (obj is Comdat other) && Equals(other); + + public bool Equals(Comdat? other) => this == other; + + public override int GetHashCode() => Handle.GetHashCode(); + + public override string ToString() => Handle.ToString(); +} diff --git a/sources/LLVMSharp/Module.cs b/sources/LLVMSharp/Module.cs index 20b8377a..95b8e6da 100644 --- a/sources/LLVMSharp/Module.cs +++ b/sources/LLVMSharp/Module.cs @@ -212,6 +212,8 @@ public Function GetOrInsertFunction(string name, FunctionType functionType) return GetFunction(name) ?? AddFunction(name, functionType); } + public Comdat GetOrInsertComdat(string name) => new Comdat(Handle.GetOrInsertComdat(name)); + public StructType? GetTypeByName(string name) { var handle = Handle.GetTypeByName(name); diff --git a/sources/LLVMSharp/Values/Users/Constants/GlobalValues/GlobalObject.cs b/sources/LLVMSharp/Values/Users/Constants/GlobalValues/GlobalObject.cs index 1a722a4a..d4139bfa 100644 --- a/sources/LLVMSharp/Values/Users/Constants/GlobalValues/GlobalObject.cs +++ b/sources/LLVMSharp/Values/Users/Constants/GlobalValues/GlobalObject.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,23 @@ private protected GlobalObject(LLVMValueRef handle, LLVMValueKind expectedValueK { } + public Comdat? Comdat + { + get + { + var comdat = Handle.Comdat; + return (comdat.Handle != IntPtr.Zero) ? new Comdat(comdat) : null; + } + + set + { + var handle = Handle; + handle.Comdat = (value is not null) ? value.Handle : default; + } + } + + public bool HasComdat => Handle.Comdat.Handle != IntPtr.Zero; + public string Section { get diff --git a/tests/LLVMSharp.UnitTests/ManagedApi.cs b/tests/LLVMSharp.UnitTests/ManagedApi.cs index 0b3df1dc..2ae9d554 100644 --- a/tests/LLVMSharp.UnitTests/ManagedApi.cs +++ b/tests/LLVMSharp.UnitTests/ManagedApi.cs @@ -171,6 +171,33 @@ public void GlobalVariableAndUserOperands() Assert.That(((ConstantInt)global.Initializer!).ZExtValue, Is.EqualTo(42UL)); } + [Test] + public void GlobalObjectComdat() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var global = (GlobalVariable)context.GetOrCreate(module.AddGlobal(int32.Handle, "g")); + Assert.That(global.HasComdat, Is.False); + Assert.That(global.Comdat, Is.Null); + + var comdat = new Comdat(module.GetOrInsertComdat("g")) + { + SelectionKind = LLVMComdatSelectionKind.LLVMLargestComdatSelectionKind, + }; + + global.Comdat = comdat; + Assert.That(global.HasComdat, Is.True); + Assert.That(global.Comdat, Is.Not.Null); + Assert.That(global.Comdat, Is.EqualTo(comdat)); + Assert.That(global.Comdat!.SelectionKind, Is.EqualTo(LLVMComdatSelectionKind.LLVMLargestComdatSelectionKind)); + + global.Comdat = null; + Assert.That(global.HasComdat, Is.False); + Assert.That(global.Comdat, Is.Null); + } + [Test] public void FunctionAccessors() { From 2202b8b9e955370780cf09ec47a85bf138358450 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jul 2026 21:52:01 -0700 Subject: [PATCH 5/5] Add managed CmpInst instance predicate accessors Mirror the C++ CmpInst/ICmpInst/FCmpInst instance predicate overloads (getInverse/swapped/ordered/unordered/strict/non-strict predicate, isFP/isInt/isStrict/isEquality/isRelational/isSigned/isUnsigned/isTrueWhenEqual/isFalseWhenEqual, ICmpInst getSigned/getUnsignedPredicate, FCmpInst isOrdered/isUnordered) by delegating to the existing static predicate helpers off GetPredicate(). Pure managed, so the isEquality/isRelational follow-up needs no native round-trip. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Values/Users/Instructions/CmpInst.cs | 36 +++++++++++++++ .../Values/Users/Instructions/FCmpInst.cs | 4 ++ .../Values/Users/Instructions/ICmpInst.cs | 7 +++ tests/LLVMSharp.UnitTests/ManagedApi.cs | 44 +++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs index 7eb40d5b..b1adacce 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs @@ -14,6 +14,42 @@ private protected CmpInst(LLVMValueRef handle) : base(handle.IsACmpInst) [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getPredicate(); the 'Predicate' name is the nested predicate enum type.")] public Predicate GetPredicate() => (Handle.IsAICmpInst != null) ? (Predicate)Handle.ICmpPredicate : (Predicate)Handle.FCmpPredicate; + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getInversePredicate(); overloads the static predicate transform.")] + public Predicate GetInversePredicate() => GetInversePredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getSwappedPredicate(); overloads the static predicate transform.")] + public Predicate GetSwappedPredicate() => GetSwappedPredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getOrderedPredicate(); overloads the static predicate transform.")] + public Predicate GetOrderedPredicate() => GetOrderedPredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getUnorderedPredicate(); overloads the static predicate transform.")] + public Predicate GetUnorderedPredicate() => GetUnorderedPredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getStrictPredicate(); overloads the static predicate transform.")] + public Predicate GetStrictPredicate() => GetStrictPredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ CmpInst::getNonStrictPredicate(); overloads the static predicate transform.")] + public Predicate GetNonStrictPredicate() => GetNonStrictPredicate(GetPredicate()); + + public bool IsFPPredicate() => IsFPPredicate(GetPredicate()); + + public bool IsIntPredicate() => IsIntPredicate(GetPredicate()); + + public bool IsStrictPredicate() => IsStrictPredicate(GetPredicate()); + + public bool IsEquality() => IsEquality(GetPredicate()); + + public bool IsRelational() => IsRelational(GetPredicate()); + + public bool IsSigned() => IsSigned(GetPredicate()); + + public bool IsUnsigned() => IsUnsigned(GetPredicate()); + + public bool IsTrueWhenEqual() => IsTrueWhenEqual(GetPredicate()); + + public bool IsFalseWhenEqual() => IsFalseWhenEqual(GetPredicate()); + internal static new CmpInst Create(LLVMValueRef handle) => handle switch { _ when handle.IsAFCmpInst != null => new FCmpInst(handle), diff --git a/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs index 4d706737..20f13b79 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/FCmpInst.cs @@ -11,4 +11,8 @@ internal FCmpInst(LLVMValueRef handle) : base(handle.IsAFCmpInst) } public static new bool IsEquality(Predicate predicate) => predicate is Predicate.FCMP_OEQ or Predicate.FCMP_ONE or Predicate.FCMP_UEQ or Predicate.FCMP_UNE; + + public bool IsOrdered() => IsOrdered(GetPredicate()); + + public bool IsUnordered() => IsUnordered(GetPredicate()); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs index 4a015e95..8654b4bc 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/ICmpInst.cs @@ -1,6 +1,7 @@ // 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 System.Diagnostics.CodeAnalysis; using LLVMSharp.Interop; namespace LLVMSharp; @@ -48,4 +49,10 @@ Predicate.ICMP_EQ or Predicate.ICMP_NE or Predicate.ICMP_SLE => Predicate.ICMP_ULE, _ => throw new ArgumentOutOfRangeException(nameof(predicate)), }; + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ ICmpInst::getSignedPredicate(); overloads the static predicate transform.")] + public Predicate GetSignedPredicate() => GetSignedPredicate(GetPredicate()); + + [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Mirrors C++ ICmpInst::getUnsignedPredicate(); overloads the static predicate transform.")] + public Predicate GetUnsignedPredicate() => GetUnsignedPredicate(GetPredicate()); } diff --git a/tests/LLVMSharp.UnitTests/ManagedApi.cs b/tests/LLVMSharp.UnitTests/ManagedApi.cs index 2ae9d554..22299c09 100644 --- a/tests/LLVMSharp.UnitTests/ManagedApi.cs +++ b/tests/LLVMSharp.UnitTests/ManagedApi.cs @@ -257,6 +257,50 @@ public void InstructionCoreAccessors() Assert.That(ret.ReturnValue, Is.EqualTo(add)); } + [Test] + public void ComparePredicateAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + var flt = Type.GetFloatTy(context); + + var functionType = LLVMTypeRef.CreateFunction(int32.Handle, [int32.Handle, int32.Handle, flt.Handle, flt.Handle], IsVarArg: false); + var function = (Function)context.GetOrCreate(module.AddFunction("f", functionType)); + var entry = function.AppendBasicBlock("entry"); + + using var builder = LLVMBuilderRef.Create(context.Handle); + builder.PositionAtEnd(entry.Handle); + + var icmpHandle = builder.BuildICmp(LLVMIntPredicate.LLVMIntSGT, function.GetParam(0).Handle, function.GetParam(1).Handle, "icmp"); + var fcmpHandle = builder.BuildFCmp(LLVMRealPredicate.LLVMRealUEQ, function.GetParam(2).Handle, function.GetParam(3).Handle, "fcmp"); + + var icmp = (ICmpInst)context.GetOrCreate(icmpHandle); + Assert.That(icmp.GetPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SGT)); + Assert.That(icmp.IsIntPredicate(), Is.True); + Assert.That(icmp.IsFPPredicate(), Is.False); + Assert.That(icmp.IsSigned(), Is.True); + Assert.That(icmp.IsUnsigned(), Is.False); + Assert.That(icmp.IsEquality(), Is.False); + Assert.That(icmp.IsRelational(), Is.True); + Assert.That(icmp.IsStrictPredicate(), Is.True); + Assert.That(icmp.GetInversePredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SLE)); + Assert.That(icmp.GetSwappedPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SLT)); + Assert.That(icmp.GetNonStrictPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SGE)); + Assert.That(icmp.GetUnsignedPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_UGT)); + Assert.That(icmp.GetSignedPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SGT)); + + var fcmp = (FCmpInst)context.GetOrCreate(fcmpHandle); + Assert.That(fcmp.GetPredicate(), Is.EqualTo(CmpInst.Predicate.FCMP_UEQ)); + Assert.That(fcmp.IsFPPredicate(), Is.True); + Assert.That(fcmp.IsEquality(), Is.True); + Assert.That(fcmp.IsRelational(), Is.False); + Assert.That(fcmp.IsOrdered(), Is.False); + Assert.That(fcmp.IsUnordered(), Is.True); + Assert.That(fcmp.GetInversePredicate(), Is.EqualTo(CmpInst.Predicate.FCMP_ONE)); + Assert.That(fcmp.GetOrderedPredicate(), Is.EqualTo(CmpInst.Predicate.FCMP_OEQ)); + } + [Test] public void MemoryInstructionAccessors() {