diff --git a/sources/LLVMSharp.Interop/Extensions/LLVMValueRef.cs b/sources/LLVMSharp.Interop/Extensions/LLVMValueRef.cs index 8c95c61..e41be9f 100644 --- a/sources/LLVMSharp.Interop/Extensions/LLVMValueRef.cs +++ b/sources/LLVMSharp.Interop/Extensions/LLVMValueRef.cs @@ -39,6 +39,10 @@ public readonly uint Alignment } } + public readonly LLVMTypeRef AllocatedType => (IsAAllocaInst != null) ? LLVM.GetAllocatedType(this) : default; + + public readonly uint ArgOperandsCount => ((IsACallInst != null) || (IsAInvokeInst != null) || (IsACallBrInst != null)) ? LLVM.GetNumArgOperands(this) : default; + public readonly LLVMAtomicRMWBinOp AtomicRMWBinOp { get @@ -58,6 +62,36 @@ public readonly LLVMAtomicRMWBinOp AtomicRMWBinOp public readonly LLVMValueRef BlockAddressFunction => (IsABlockAddress != null) ? LLVM.GetBlockAddressFunction(this) : default; + public readonly LLVMTypeRef CalledFunctionType => ((IsACallInst != null) || (IsAInvokeInst != null) || (IsACallBrInst != null)) ? LLVM.GetCalledFunctionType(this) : default; + + public readonly LLVMValueRef CalledValue => ((IsACallInst != null) || (IsAInvokeInst != null) || (IsACallBrInst != null)) ? LLVM.GetCalledValue(this) : default; + + public readonly LLVMAtomicOrdering CmpXchgFailureOrdering + { + get + { + return (IsAAtomicCmpXchgInst != null) ? LLVM.GetCmpXchgFailureOrdering(this) : default; + } + + set + { + LLVM.SetCmpXchgFailureOrdering(this, value); + } + } + + public readonly LLVMAtomicOrdering CmpXchgSuccessOrdering + { + get + { + return (IsAAtomicCmpXchgInst != null) ? LLVM.GetCmpXchgSuccessOrdering(this) : default; + } + + set + { + LLVM.SetCmpXchgSuccessOrdering(this, value); + } + } + public readonly LLVMValueRef Condition { get @@ -167,6 +201,8 @@ public readonly string GC } } + public readonly LLVMTypeRef GEPSourceElementType => (IsAGetElementPtrInst != null) ? LLVM.GetGEPSourceElementType(this) : default; + public readonly LLVMValueRef GlobalIFuncResolver { get @@ -570,10 +606,27 @@ public readonly string Name public readonly LLVMValueRef NextParam => (IsAArgument != null) ? LLVM.GetNextParam(this) : default; + public readonly LLVMBasicBlockRef NormalDest => (IsAInvokeInst != null) ? LLVM.GetNormalDest(this) : default; + + public readonly uint NumClauses => (IsALandingPadInst != null) ? LLVM.GetNumClauses(this) : default; + public readonly LLVMOpcode Opcode => Kind is LLVMValueKind.LLVMInstructionValueKind ? InstructionOpcode : ConstOpcode; public readonly int OperandCount => ((Kind == LLVMValueKind.LLVMMetadataAsValueValueKind) || (IsAUser != null)) ? LLVM.GetNumOperands(this) : default; + public readonly LLVMAtomicOrdering Ordering + { + get + { + return ((IsALoadInst != null) || (IsAStoreInst != null) || (IsAFenceInst != null) || (IsAAtomicRMWInst != null)) ? LLVM.GetOrdering(this) : default; + } + + set + { + LLVM.SetOrdering(this, value); + } + } + public readonly uint ParamsCount => (IsAFunction != null) ? LLVM.CountParams(this) : default; public readonly LLVMValueRef ParamParent => (IsAArgument != null) ? LLVM.GetParamParent(this) : default; @@ -679,6 +732,8 @@ public readonly LLVMUnnamedAddr UnnamedAddress } } + public readonly LLVMBasicBlockRef UnwindDest => ((IsAInvokeInst != null) || (IsACatchSwitchInst != null) || (IsACleanupReturnInst != null)) ? LLVM.GetUnwindDest(this) : default; + public readonly LLVMValueUsesEnumerable Uses => new LLVMValueUsesEnumerable(this); public readonly LLVMVisibility Visibility @@ -1235,6 +1290,10 @@ public readonly double GetConstRealDouble(out bool losesInfo) public readonly LLVMValueRef GetAggregateElement(uint idx) => LLVM.GetAggregateElement(this, idx); + public readonly LLVMValueRef GetArgOperand(uint index) => LLVM.GetArgOperand(this, index); + + public readonly LLVMValueRef GetClause(uint index) => LLVM.GetClause(this, index); + [Obsolete("Use GetAggregateElement instead")] public readonly LLVMValueRef GetElementAsConstant(uint idx) => LLVM.GetElementAsConstant(this, idx); diff --git a/sources/LLVMSharp/Values/Users/Instructions/AllocaInst.cs b/sources/LLVMSharp/Values/Users/Instructions/AllocaInst.cs index 028a923..5a1e17d 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/AllocaInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/AllocaInst.cs @@ -22,4 +22,6 @@ public uint Alignment Handle.SetAlignment(value); } } + + public Type AllocatedType => Context.GetOrCreate(Handle.AllocatedType); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/AtomicCmpXchgInst.cs b/sources/LLVMSharp/Values/Users/Instructions/AtomicCmpXchgInst.cs index 977eb3c..868770c 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/AtomicCmpXchgInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/AtomicCmpXchgInst.cs @@ -9,4 +9,60 @@ public sealed class AtomicCmpXchgInst : Instruction internal AtomicCmpXchgInst(LLVMValueRef handle) : base(handle.IsAAtomicCmpXchgInst) { } + + public AtomicOrdering FailureOrdering + { + get + { + return (AtomicOrdering)Handle.CmpXchgFailureOrdering; + } + + set + { + var handle = Handle; + handle.CmpXchgFailureOrdering = (LLVMAtomicOrdering)value; + } + } + + public AtomicOrdering SuccessOrdering + { + get + { + return (AtomicOrdering)Handle.CmpXchgSuccessOrdering; + } + + set + { + var handle = Handle; + handle.CmpXchgSuccessOrdering = (LLVMAtomicOrdering)value; + } + } + + public bool Volatile + { + get + { + return Handle.Volatile; + } + + set + { + var handle = Handle; + handle.Volatile = value; + } + } + + public bool Weak + { + get + { + return Handle.Weak; + } + + set + { + var handle = Handle; + handle.Weak = value; + } + } } diff --git a/sources/LLVMSharp/Values/Users/Instructions/AtomicRMWInst.cs b/sources/LLVMSharp/Values/Users/Instructions/AtomicRMWInst.cs index a8819f6..c0ae0a3 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/AtomicRMWInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/AtomicRMWInst.cs @@ -9,4 +9,46 @@ public sealed partial class AtomicRMWInst : Instruction internal AtomicRMWInst(LLVMValueRef handle) : base(handle.IsAAtomicRMWInst) { } + + public BinOp Operation + { + get + { + return (BinOp)Handle.AtomicRMWBinOp; + } + + set + { + var handle = Handle; + handle.AtomicRMWBinOp = (LLVMAtomicRMWBinOp)value; + } + } + + public AtomicOrdering Ordering + { + get + { + return (AtomicOrdering)Handle.Ordering; + } + + set + { + var handle = Handle; + handle.Ordering = (LLVMAtomicOrdering)value; + } + } + + public bool Volatile + { + get + { + return Handle.Volatile; + } + + set + { + var handle = Handle; + handle.Volatile = value; + } + } } diff --git a/sources/LLVMSharp/Values/Users/Instructions/BranchInst.cs b/sources/LLVMSharp/Values/Users/Instructions/BranchInst.cs index 7e03482..224f6b2 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/BranchInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/BranchInst.cs @@ -9,4 +9,8 @@ public sealed class BranchInst : Instruction internal BranchInst(LLVMValueRef handle) : base(handle.IsABranchInst) { } + + public Value Condition => Context.GetOrCreate(Handle.Condition); + + public bool IsConditional => Handle.IsConditional; } diff --git a/sources/LLVMSharp/Values/Users/Instructions/CallBase.cs b/sources/LLVMSharp/Values/Users/Instructions/CallBase.cs index 81af47e..6d412ca 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/CallBase.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/CallBase.cs @@ -11,6 +11,8 @@ private protected CallBase(LLVMValueRef handle) : base(handle) { } + public uint ArgOperandsCount => Handle.ArgOperandsCount; + public LLVMCallConv CallingConvention { get @@ -43,4 +45,10 @@ public Attribute[] GetAttributesAtIndex(LLVMAttributeIndex index) return attributes; } + + public FunctionType CalledFunctionType => Context.GetOrCreate(Handle.CalledFunctionType); + + public Value CalledOperand => Context.GetOrCreate(Handle.CalledValue); + + public Value GetArgOperand(uint index) => Context.GetOrCreate(Handle.GetArgOperand(index)); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/CallInst.cs b/sources/LLVMSharp/Values/Users/Instructions/CallInst.cs index 4d0c78b..2420965 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/CallInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/CallInst.cs @@ -10,6 +10,20 @@ private protected CallInst(LLVMValueRef handle) : base(handle.IsACallInst) { } + public bool IsTailCall + { + get + { + return Handle.IsTailCall; + } + + set + { + var handle = Handle; + handle.IsTailCall = value; + } + } + internal static new CallInst Create(LLVMValueRef handle) => handle switch { _ when handle.IsAIntrinsicInst != null => IntrinsicInst.Create(handle), diff --git a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs index ded110b..7eb40d5 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/CmpInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/CmpInst.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.Diagnostics.CodeAnalysis; using LLVMSharp.Interop; namespace LLVMSharp; @@ -10,6 +11,9 @@ 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; + internal static new CmpInst Create(LLVMValueRef handle) => handle switch { _ when handle.IsAFCmpInst != null => new FCmpInst(handle), diff --git a/sources/LLVMSharp/Values/Users/Instructions/FenceInst.cs b/sources/LLVMSharp/Values/Users/Instructions/FenceInst.cs index bf61fe6..3b42557 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/FenceInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/FenceInst.cs @@ -9,4 +9,18 @@ public sealed class FenceInst : Instruction internal FenceInst(LLVMValueRef handle) : base(handle.IsAFenceInst) { } + + public AtomicOrdering Ordering + { + get + { + return (AtomicOrdering)Handle.Ordering; + } + + set + { + var handle = Handle; + handle.Ordering = (LLVMAtomicOrdering)value; + } + } } diff --git a/sources/LLVMSharp/Values/Users/Instructions/GetElementPtrInst.cs b/sources/LLVMSharp/Values/Users/Instructions/GetElementPtrInst.cs index 16ddc51..5345a4a 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/GetElementPtrInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/GetElementPtrInst.cs @@ -9,4 +9,6 @@ public sealed class GetElementPtrInst : Instruction internal GetElementPtrInst(LLVMValueRef handle) : base(handle.IsAGetElementPtrInst) { } + + public Type SourceElementType => Context.GetOrCreate(Handle.GEPSourceElementType); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/Instruction.cs b/sources/LLVMSharp/Values/Users/Instructions/Instruction.cs index 695f007..4888444 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/Instruction.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/Instruction.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,10 +11,28 @@ private protected Instruction(LLVMValueRef handle) : base(handle.IsAInstruction, { } + public bool IsTerminator => Handle.IsATerminatorInst != null; + + public LLVMOpcode Opcode => Handle.InstructionOpcode; + + public BasicBlock Parent => Context.GetOrCreate(Handle.InstructionParent); + + public uint SuccessorsCount => Handle.SuccessorsCount; + + public Instruction Clone() => Context.GetOrCreate(Handle.InstructionClone); + public void EraseFromParent() => Handle.InstructionEraseFromParent(); + public BasicBlock GetSuccessor(uint index) => Context.GetOrCreate(Handle.GetSuccessor(index)); + public void RemoveFromParent() => Handle.InstructionRemoveFromParent(); + public void SetSuccessor(uint index, BasicBlock block) + { + ArgumentNullException.ThrowIfNull(block); + Handle.SetSuccessor(index, block.Handle); + } + internal static new Instruction Create(LLVMValueRef handle) => handle switch { _ when handle.IsAUnaryOperator != null => new UnaryOperator(handle), diff --git a/sources/LLVMSharp/Values/Users/Instructions/InvokeInst.cs b/sources/LLVMSharp/Values/Users/Instructions/InvokeInst.cs index d1255fa..00fda0a 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/InvokeInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/InvokeInst.cs @@ -9,4 +9,8 @@ public sealed class InvokeInst : CallBase internal InvokeInst(LLVMValueRef handle) : base(handle.IsAInvokeInst) { } + + public BasicBlock NormalDest => Context.GetOrCreate(Handle.NormalDest); + + public BasicBlock UnwindDest => Context.GetOrCreate(Handle.UnwindDest); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/LandingPadInst.cs b/sources/LLVMSharp/Values/Users/Instructions/LandingPadInst.cs index 90d6830..e2c5047 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/LandingPadInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/LandingPadInst.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; @@ -9,4 +10,28 @@ public sealed class LandingPadInst : Instruction internal LandingPadInst(LLVMValueRef handle) : base(handle.IsALandingPadInst) { } + + public bool IsCleanup + { + get + { + return Handle.IsCleanup; + } + + set + { + var handle = Handle; + handle.IsCleanup = value; + } + } + + public uint NumClauses => Handle.NumClauses; + + public void AddClause(Constant clauseVal) + { + ArgumentNullException.ThrowIfNull(clauseVal); + Handle.AddClause(clauseVal.Handle); + } + + public Constant GetClause(uint index) => Context.GetOrCreate(Handle.GetClause(index)); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/LoadInst.cs b/sources/LLVMSharp/Values/Users/Instructions/LoadInst.cs index 9be6a5d..7414760 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/LoadInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/LoadInst.cs @@ -22,4 +22,32 @@ public uint Alignment Handle.SetAlignment(value); } } + + public AtomicOrdering Ordering + { + get + { + return (AtomicOrdering)Handle.Ordering; + } + + set + { + var handle = Handle; + handle.Ordering = (LLVMAtomicOrdering)value; + } + } + + public bool Volatile + { + get + { + return Handle.Volatile; + } + + set + { + var handle = Handle; + handle.Volatile = value; + } + } } diff --git a/sources/LLVMSharp/Values/Users/Instructions/PHINode.cs b/sources/LLVMSharp/Values/Users/Instructions/PHINode.cs index 5fca336..bd5599e 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/PHINode.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/PHINode.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; @@ -9,4 +10,20 @@ public sealed class PHINode : Instruction internal PHINode(LLVMValueRef handle) : base(handle.IsAPHINode) { } + + public uint IncomingCount => Handle.IncomingCount; + + public void AddIncoming(Value incomingValue, BasicBlock incomingBlock) + { + ArgumentNullException.ThrowIfNull(incomingValue); + ArgumentNullException.ThrowIfNull(incomingBlock); + + Span values = [incomingValue.Handle]; + Span blocks = [incomingBlock.Handle]; + Handle.AddIncoming(values, blocks, 1); + } + + public BasicBlock GetIncomingBlock(uint index) => Context.GetOrCreate(Handle.GetIncomingBlock(index)); + + public Value GetIncomingValue(uint index) => Context.GetOrCreate(Handle.GetIncomingValue(index)); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/ReturnInst.cs b/sources/LLVMSharp/Values/Users/Instructions/ReturnInst.cs index a03e80e..fee4d60 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/ReturnInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/ReturnInst.cs @@ -9,4 +9,6 @@ public sealed class ReturnInst : Instruction internal ReturnInst(LLVMValueRef handle) : base(handle.IsAReturnInst) { } + + public Value? ReturnValue => (NumOperands == 0) ? null : GetOperand(0); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/SelectInst.cs b/sources/LLVMSharp/Values/Users/Instructions/SelectInst.cs index 820c4e0..c44a187 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/SelectInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/SelectInst.cs @@ -9,4 +9,10 @@ public sealed class SelectInst : Instruction internal SelectInst(LLVMValueRef handle) : base(handle.IsASelectInst) { } + + public Value Condition => GetOperand(0); + + public Value FalseValue => GetOperand(2); + + public Value TrueValue => GetOperand(1); } diff --git a/sources/LLVMSharp/Values/Users/Instructions/StoreInst.cs b/sources/LLVMSharp/Values/Users/Instructions/StoreInst.cs index f44ea7a..d4559da 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/StoreInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/StoreInst.cs @@ -22,4 +22,32 @@ public uint Alignment Handle.SetAlignment(value); } } + + public AtomicOrdering Ordering + { + get + { + return (AtomicOrdering)Handle.Ordering; + } + + set + { + var handle = Handle; + handle.Ordering = (LLVMAtomicOrdering)value; + } + } + + public bool Volatile + { + get + { + return Handle.Volatile; + } + + set + { + var handle = Handle; + handle.Volatile = value; + } + } } diff --git a/sources/LLVMSharp/Values/Users/Instructions/SwitchInst.cs b/sources/LLVMSharp/Values/Users/Instructions/SwitchInst.cs index c8d6d01..d48ffb9 100644 --- a/sources/LLVMSharp/Values/Users/Instructions/SwitchInst.cs +++ b/sources/LLVMSharp/Values/Users/Instructions/SwitchInst.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; @@ -9,4 +10,15 @@ public sealed class SwitchInst : Instruction internal SwitchInst(LLVMValueRef handle) : base(handle.IsASwitchInst) { } + + public Value Condition => GetOperand(0); + + public BasicBlock DefaultDest => Context.GetOrCreate(Handle.SwitchDefaultDest); + + public void AddCase(ConstantInt onVal, BasicBlock dest) + { + ArgumentNullException.ThrowIfNull(onVal); + ArgumentNullException.ThrowIfNull(dest); + Handle.AddCase(onVal.Handle, dest.Handle); + } } diff --git a/tests/LLVMSharp.UnitTests/ManagedApi.cs b/tests/LLVMSharp.UnitTests/ManagedApi.cs index 5d76090..c73cd9e 100644 --- a/tests/LLVMSharp.UnitTests/ManagedApi.cs +++ b/tests/LLVMSharp.UnitTests/ManagedApi.cs @@ -201,4 +201,206 @@ public void FunctionAccessors() Assert.That(function.IsDeclaration, Is.False); Assert.That(function.GetBasicBlocks().Length, Is.EqualTo(1)); } + + [Test] + public void InstructionCoreAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(int32.Handle, [int32.Handle, int32.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 addHandle = builder.BuildAdd(function.GetParam(0).Handle, function.GetParam(1).Handle, "sum"); + var retHandle = builder.BuildRet(addHandle); + + var add = (Instruction)context.GetOrCreate(addHandle); + Assert.That(add.Opcode, Is.EqualTo(LLVMOpcode.LLVMAdd)); + Assert.That(add.IsTerminator, Is.False); + Assert.That(add.Parent, Is.EqualTo(entry)); + + var ret = (ReturnInst)context.GetOrCreate(retHandle); + Assert.That(ret.IsTerminator, Is.True); + Assert.That(ret.Opcode, Is.EqualTo(LLVMOpcode.LLVMRet)); + Assert.That(ret.ReturnValue, Is.EqualTo(add)); + } + + [Test] + public void MemoryInstructionAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(Type.GetVoidTy(context).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 alloca = (AllocaInst)context.GetOrCreate(builder.BuildAlloca(int32.Handle, "slot")); + alloca.Alignment = 8; + Assert.That(alloca.AllocatedType, Is.EqualTo(int32)); + Assert.That(alloca.Alignment, Is.EqualTo(8u)); + + var store = (StoreInst)context.GetOrCreate(builder.BuildStore(LLVMValueRef.CreateConstInt(int32.Handle, 7), alloca.Handle)); + store.Alignment = 4; + store.Volatile = true; + store.Ordering = AtomicOrdering.Monotonic; + Assert.That(store.Alignment, Is.EqualTo(4u)); + Assert.That(store.Volatile, Is.True); + Assert.That(store.Ordering, Is.EqualTo(AtomicOrdering.Monotonic)); + + var load = (LoadInst)context.GetOrCreate(builder.BuildLoad2(int32.Handle, alloca.Handle, "v")); + load.Volatile = true; + load.Ordering = AtomicOrdering.Acquire; + Assert.That(load.Volatile, Is.True); + Assert.That(load.Ordering, Is.EqualTo(AtomicOrdering.Acquire)); + } + + [Test] + public void ComparisonInstructionAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + var flt = Type.GetFloatTy(context); + + var functionType = LLVMTypeRef.CreateFunction(Type.GetVoidTy(context).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.LLVMIntSLT, function.GetParam(0).Handle, function.GetParam(1).Handle, "c"); + var icmp = (ICmpInst)context.GetOrCreate(icmpHandle); + Assert.That(icmp.GetPredicate(), Is.EqualTo(CmpInst.Predicate.ICMP_SLT)); + + var fcmpHandle = builder.BuildFCmp(LLVMRealPredicate.LLVMRealOEQ, function.GetParam(2).Handle, function.GetParam(3).Handle, "f"); + var fcmp = (FCmpInst)context.GetOrCreate(fcmpHandle); + Assert.That(fcmp.GetPredicate(), Is.EqualTo(CmpInst.Predicate.FCMP_OEQ)); + } + + [Test] + public void BranchAndSwitchAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(Type.GetVoidTy(context).Handle, [], IsVarArg: false); + var function = (Function)context.GetOrCreate(module.AddFunction("f", functionType)); + var entry = function.AppendBasicBlock("entry"); + var ifTrue = function.AppendBasicBlock("true"); + var ifFalse = function.AppendBasicBlock("false"); + + using var builder = LLVMBuilderRef.Create(context.Handle); + builder.PositionAtEnd(entry.Handle); + + var cond = builder.BuildICmp(LLVMIntPredicate.LLVMIntSLT, LLVMValueRef.CreateConstInt(int32.Handle, 1), LLVMValueRef.CreateConstInt(int32.Handle, 2), "c"); + var branch = (BranchInst)context.GetOrCreate(builder.BuildCondBr(cond, ifTrue.Handle, ifFalse.Handle)); + Assert.That(branch.IsConditional, Is.True); + Assert.That(branch.Condition, Is.EqualTo(context.GetOrCreate(cond))); + Assert.That(branch.SuccessorsCount, Is.EqualTo(2u)); + Assert.That(branch.GetSuccessor(0), Is.EqualTo(ifTrue)); + + builder.PositionAtEnd(ifTrue.Handle); + var switchInst = (SwitchInst)context.GetOrCreate(builder.BuildSwitch(LLVMValueRef.CreateConstInt(int32.Handle, 0), ifFalse.Handle, 1)); + switchInst.AddCase((ConstantInt)context.GetOrCreate(LLVMValueRef.CreateConstInt(int32.Handle, 1)), entry); + Assert.That(switchInst.DefaultDest, Is.EqualTo(ifFalse)); + Assert.That(((ConstantInt)switchInst.Condition).ZExtValue, Is.EqualTo(0UL)); + } + + [Test] + public void PhiAndSelectAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + var int1 = Type.GetInt1Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(Type.GetVoidTy(context).Handle, [int1.Handle, int32.Handle, int32.Handle], IsVarArg: false); + var function = (Function)context.GetOrCreate(module.AddFunction("f", functionType)); + var entry = function.AppendBasicBlock("entry"); + var other = function.AppendBasicBlock("other"); + + using var builder = LLVMBuilderRef.Create(context.Handle); + builder.PositionAtEnd(entry.Handle); + + var phi = (PHINode)context.GetOrCreate(builder.BuildPhi(int32.Handle, "p")); + phi.AddIncoming((Value)context.GetOrCreate(LLVMValueRef.CreateConstInt(int32.Handle, 10)), entry); + phi.AddIncoming((Value)context.GetOrCreate(LLVMValueRef.CreateConstInt(int32.Handle, 20)), other); + Assert.That(phi.IncomingCount, Is.EqualTo(2u)); + Assert.That(phi.GetIncomingBlock(0), Is.EqualTo(entry)); + Assert.That(((ConstantInt)phi.GetIncomingValue(1)).ZExtValue, Is.EqualTo(20UL)); + + var condVal = function.GetParam(0); + var trueVal = function.GetParam(1); + var falseVal = function.GetParam(2); + var select = (SelectInst)context.GetOrCreate(builder.BuildSelect(condVal.Handle, trueVal.Handle, falseVal.Handle, "s")); + Assert.That(select.Condition, Is.EqualTo(condVal)); + Assert.That(select.TrueValue, Is.EqualTo(trueVal)); + Assert.That(select.FalseValue, Is.EqualTo(falseVal)); + } + + [Test] + public void CallInstructionAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(int32.Handle, [int32.Handle, int32.Handle], IsVarArg: false); + var callee = (Function)context.GetOrCreate(module.AddFunction("callee", functionType)); + var caller = (Function)context.GetOrCreate(module.AddFunction("caller", functionType)); + var entry = caller.AppendBasicBlock("entry"); + + using var builder = LLVMBuilderRef.Create(context.Handle); + builder.PositionAtEnd(entry.Handle); + + var callHandle = builder.BuildCall2(functionType, callee.Handle, new[] { caller.GetParam(0).Handle, caller.GetParam(1).Handle }, "r"); + var call = (CallInst)context.GetOrCreate(callHandle); + call.IsTailCall = true; + + Assert.That(call.ArgOperandsCount, Is.EqualTo(2u)); + Assert.That(call.CalledOperand, Is.EqualTo(callee)); + Assert.That(call.CalledFunctionType.NumParams, Is.EqualTo(2u)); + Assert.That(call.GetArgOperand(0), Is.EqualTo(caller.GetParam(0))); + Assert.That(call.IsTailCall, Is.True); + } + + [Test] + public void GepAndAtomicAccessors() + { + var context = new LLVMContext(); + var module = context.Handle.CreateModuleWithName("m"); + var int32 = Type.GetInt32Ty(context); + + var functionType = LLVMTypeRef.CreateFunction(Type.GetVoidTy(context).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 arrayType = LLVMTypeRef.CreateArray(int32.Handle, 4); + var storage = builder.BuildAlloca(arrayType, "arr"); + var gep = (GetElementPtrInst)context.GetOrCreate(builder.BuildGEP2(arrayType, storage, new[] { LLVMValueRef.CreateConstInt(int32.Handle, 0), LLVMValueRef.CreateConstInt(int32.Handle, 1) }, "elem")); + Assert.That(gep.SourceElementType, Is.EqualTo(context.GetOrCreate(arrayType))); + + var slot = builder.BuildAlloca(int32.Handle, "slot"); + var atomic = (AtomicRMWInst)context.GetOrCreate(builder.BuildAtomicRMW(LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpAdd, slot, LLVMValueRef.CreateConstInt(int32.Handle, 1), LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic, singleThread: false)); + Assert.That(atomic.Operation, Is.EqualTo(AtomicRMWInst.BinOp.Add)); + Assert.That(atomic.Ordering, Is.EqualTo(AtomicOrdering.Monotonic)); + + var fence = (FenceInst)context.GetOrCreate(builder.BuildFence(LLVMAtomicOrdering.LLVMAtomicOrderingAcquire, singleThread: false, "fence")); + Assert.That(fence.Ordering, Is.EqualTo(AtomicOrdering.Acquire)); + } }