diff --git a/IgnoredWords.dic b/IgnoredWords.dic index 8bd5529ba..bcb678b86 100644 --- a/IgnoredWords.dic +++ b/IgnoredWords.dic @@ -75,6 +75,7 @@ Llilum llvm llvmversion LValue +malloc marshallers marshalling memcopy diff --git a/src/Interop/InteropTests/ABI/libllvm-c/AnalysisBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/AnalysisBindingsTests.cs new file mode 100644 index 000000000..f600c6d57 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/AnalysisBindingsTests.cs @@ -0,0 +1,62 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.AnalysisBindings; +using static Ubiquity.NET.Llvm.Interop.ABI.llvm_c.Core; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class AnalysisBindingsTests + { + [TestMethod] + public void LibLLVMVerifyFunctionExTest( ) + { + using LLVMContextRef ctx = LLVMContextCreate(); + using LLVMModuleRef module = LLVMModuleCreateWithNameInContext("testModule"u8, ctx); + LLVMTypeRef intType = LLVMInt32TypeInContext(ctx); + LLVMTypeRef funcType = LLVMFunctionType(intType, [], 0, false); + + // declare a test func to work with and create an entry block for it... + LLVMValueRef goodFunc = LLVMAddFunction(module, "goodfunc"u8, funcType); + ImplementFunction(goodFunc, intType, createBroken: false); + LLVMStatus goodStatus = LibLLVMVerifyFunctionEx(goodFunc, llvm_c.LLVMVerifierFailureAction.LLVMPrintMessageAction, out string goodmsg); + Assert.AreEqual(0, goodStatus.ErrorCode); + Assert.IsFalse(goodStatus.Failed); + Assert.IsTrue(goodStatus.Succeeded); + // test for each state of a string in order to produce a distinct failure point for each condition + Assert.IsNotNull(goodmsg, "Error message should not be null"); + Assert.IsTrue(string.IsNullOrEmpty(goodmsg), "Error message should be empty, for successful validation"); + + LLVMValueRef badFunc = LLVMAddFunction(module, "badfunc"u8, funcType); + ImplementFunction(badFunc, intType, createBroken: true); + LLVMStatus badStatus = LibLLVMVerifyFunctionEx(badFunc, llvm_c.LLVMVerifierFailureAction.LLVMPrintMessageAction, out string badmsg); + Assert.AreNotEqual(0, badStatus.ErrorCode); + Assert.IsTrue(badStatus.Failed); + Assert.IsFalse(badStatus.Succeeded); + // test for each state of a string in order to produce a distinct failure point for each condition + Assert.IsNotNull(badmsg, "Error message should not be null"); + Assert.IsFalse(string.IsNullOrEmpty(badmsg), "Error message should not be empty"); + Assert.IsFalse(string.IsNullOrWhiteSpace(badmsg), "Error message should not be all whitespace"); + } + + private static void ImplementFunction(LLVMValueRef func, LLVMTypeRef intType, bool createBroken = false) + { + LLVMContextRefAlias ctx = LLVMGetValueContext(func); + + // Create an instruction builder to work with and connect it to + // a new entry block for the test function + using LLVMBuilderRef testBuilder = LLVMCreateBuilderInContext(ctx); + LLVMPositionBuilderAtEnd(testBuilder, LLVMAppendBasicBlockInContext(ctx, func, "entry"u8)); + + // Now build out some code... + LLVMValueRef constOne = LLVMConstInt(intType, 1, false); + LLVMValueRef r0 = LLVMBuildAdd(testBuilder, constOne, constOne, string.Empty); + + // BB without terminator is a good example of a bad function + if (!createBroken) + { + LLVMBuildRet(testBuilder, r0); + } + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/AttributeBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/AttributeBindingsTests.cs new file mode 100644 index 000000000..41c52318f --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/AttributeBindingsTests.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Extensions; +using Ubiquity.NET.InteropHelpers; +using Ubiquity.NET.Llvm.Interop.ABI.StringMarshaling; +using Ubiquity.NET.Llvm.Interop.UT; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.AttributeBindings; +using static Ubiquity.NET.Llvm.Interop.ABI.llvm_c.Core; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class AttributeBindingsTests + { + [TestMethod] + public void LibLLVMGetNumKnownAttribsTest( ) + { + int len = checked((int)LibLLVMGetNumKnownAttribs()); + // Known count of attributes at time of this test + // Changes are flagged by this test so that updates to consumers or release notes + // can be made if applicable. + Assert.AreEqual(KnownAttributes.Count, len); + } + + [TestMethod] + public void LibLLVMGetKnownAttributeNamesTest( ) + { + int len = checked((int)LibLLVMGetNumKnownAttribs()); + unsafe + { + byte** ppData = stackalloc byte*[len]; + using LLVMErrorRef errorRef = LibLLVMGetKnownAttributeNames(ppData, (nuint)len); + errorRef.ThrowIfFailed(); + + // make sure conversion is plausible. + var actualNames = new LazyEncodedString[len]; + for(int i = 0; i < len; ++i) + { + // https://github.com/microsoft/testfx/issues/5543 +#pragma warning disable MSTEST0037 // Use proper 'Assert' methods + Assert.IsTrue(ppData[i] is not null); +#pragma warning restore MSTEST0037 // Use proper 'Assert' methods + + var les = LazyEncodedString.FromUnmanaged(ppData[i]); + + actualNames[i] = LazyEncodedString.FromUnmanaged(ppData[i])!; + } + + foreach(var name in actualNames) + { + Assert.IsTrue(KnownAttributes.ContainsKey(name), $"Attribute name not known: '{name}'"); + } + } + } + + [TestMethod] + public void LibLLVMAttributeToStringTest( ) + { + using LLVMContextRef ctx = LLVMContextCreate(); + LazyEncodedString name = new("custom"u8); + LazyEncodedString value = "custom value"u8; + + LLVMAttributeRef attribValue = LLVMCreateStringAttribute(ctx, name, value); + Assert.IsFalse(attribValue.IsNull); + + string result = LibLLVMAttributeToString(attribValue); + Assert.AreEqual("\"custom\"=\"custom value\"", result); + } + + [TestMethod] + public void LibLLVMIsConstantRangeAttributeTest( ) + { + using LLVMContextRef ctx = LLVMContextCreate(); + + // create and validate a known constant range attribute + LLVMAttributeRef knownConstRangeAttrib = LLVMCreateConstantRangeAttribute(ctx, LLVMGetEnumAttributeKindForName("range"u8), 32, [0], [0x12345678]); + Assert.IsFalse(knownConstRangeAttrib.IsNull); + string knownConstRangeAttribAsString = LibLLVMAttributeToString(knownConstRangeAttrib); + // 0x12345678 = 305419896 + Assert.AreEqual("range(i32 0, 305419896)", knownConstRangeAttribAsString); + + // Create and validate an attribute that is known NOT to be a constant range + LLVMAttributeRef enumAttrib = LLVMCreateEnumAttribute(ctx, LLVMGetEnumAttributeKindForName("builtin"u8), 0); + Assert.IsFalse(enumAttrib.IsNull); + string enumAttribAsString = LibLLVMAttributeToString(enumAttrib); + Assert.AreEqual("builtin", enumAttribAsString); + + // Now actually test the API in question. + Assert.IsTrue(LibLLVMIsConstantRangeAttribute(knownConstRangeAttrib)); + Assert.IsFalse(LibLLVMIsConstantRangeAttribute(enumAttrib)); + } + + [SkipTestMethod] + public void LibLLVMIsConstantRangeListAttributeTest( ) + { + // At present the creation of a constant range list attribute instance is + // not possible with the LLVM-C API nor the extended API. It's not entirely + // clear on what such a thing really is... + // The only known attribute supporting this type of arg is the "initializes" attribute. + + // TEMP: find a known attribute requiring a constant range list... + var attrib = ( from kvp in KnownAttributes + where kvp.Value.ArgKind == LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_ConstantRangeList + select kvp + ).FirstOrDefault(); + + throw new NotImplementedException(); + } + + [TestMethod] + public void LibLLVMGetAttributeInfoTest( ) + { + foreach(var kvp in KnownAttributes.OrderBy(kvp=>kvp.Value.ID)) + { + LibLLVMGetAttributeInfo( kvp.Key, out LibLLVMAttributeInfo info ).ThrowIfFailed(); + Assert.AreEqual( kvp.Value, info ); + if(info.ID == 0) + { + // ALL attributes with enum ID == 0 should be "string" + // [Double checks any potential conflicts with KnownAttributes map] + Assert.AreEqual( LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, info.ArgKind ); + } + + ShowKnownAttributesEntry( kvp.Key, info ); + } + + // LibLLVM should support Custom attributes as well. + using LLVMErrorRef errorRef = LibLLVMGetAttributeInfo("custom"u8, out LibLLVMAttributeInfo customAttribinfo); + errorRef.ThrowIfFailed(); + + Assert.AreEqual(0u, customAttribinfo.ID); + Assert.AreEqual(LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, customAttribinfo.ArgKind); + Assert.AreEqual(LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All, customAttribinfo.AllowedOn); + } + + [TestMethod] + public void LibLLVMGetAttributeNameFromIDTest( ) + { + var knownEnumAttribs = from kvp in KnownAttributes + where kvp.Value.ID > 0 + select kvp; + + foreach(var kvp in knownEnumAttribs) + { + var actualName = LibLLVMGetAttributeNameFromID(kvp.Value.ID); + Assert.IsNotNull(actualName, $"Name should not be null for ID: {kvp.Value.ID})"); + Assert.AreEqual(kvp.Key, actualName, $"Name for ID: {kvp.Value.ID} should be '{kvp.Key})'"); + } + } + + private readonly static ImmutableDictionary KnownAttributes + = new DictionaryBuilder { + ["no-infs-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["approx-func-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["no-jump-tables"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["denormal-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["less-precise-fpmad"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["no-signed-zeros-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["profile-sample-accurate"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["no-nans-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["unsafe-fp-math"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["use-sample-profile"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + ["no-inline-line-tables"u8] = new(0, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_All), + // First Enum attribute... + ["allocalign"u8] = new(1, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["allocptr"u8] = new(2, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["alwaysinline"u8] = new(3, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["builtin"u8] = new(4, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["cold"u8] = new(5, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["convergent"u8] = new(6, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["coro_only_destroy_when_complete"u8] = new(7, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["coro_elide_safe"u8] = new(8, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["dead_on_unwind"u8] = new(9, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["disable_sanitizer_instrumentation"u8] = new(10, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["fn_ret_thunk_extern"u8] = new(11, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["hot"u8] = new(12, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["hybrid_patchable"u8] = new(13, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["immarg"u8] = new(14, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["inreg"u8] = new(15, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["inlinehint"u8] = new(16, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["jumptable"u8] = new(17, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["minsize"u8] = new(18, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["mustprogress"u8] = new(19, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["naked"u8] = new(20, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nest"u8] = new(21, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["noalias"u8] = new(22, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["nobuiltin"u8] = new(23, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nocallback"u8] = new(24, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nocapture"u8] = new(25, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["nocf_check"u8] = new(26, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nodivergencesource"u8] = new(27, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noduplicate"u8] = new(28, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noext"u8] = new(29, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["nofree"u8] = new(30, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noimplicitfloat"u8] = new(31, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noinline"u8] = new(32, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nomerge"u8] = new(33, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noprofile"u8] = new(34, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["norecurse"u8] = new(35, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noredzone"u8] = new(36, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noreturn"u8] = new(37, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nosanitize_bounds"u8] = new(38, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nosanitize_coverage"u8] = new(39, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nosync"u8] = new(40, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["noundef"u8] = new(41, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["nounwind"u8] = new(42, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nonlazybind"u8] = new(43, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nonnull"u8] = new(44, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["null_pointer_is_valid"u8] = new(45, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["optforfuzzing"u8] = new(46, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["optdebug"u8] = new(47, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["optsize"u8] = new(48, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["optnone"u8] = new(49, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["presplitcoroutine"u8] = new(50, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["readnone"u8] = new(51, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["readonly"u8] = new(52, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["returned"u8] = new(53, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["returns_twice"u8] = new(54, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["signext"u8] = new(55, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["safestack"u8] = new(56, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_address"u8] = new(57, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_hwaddress"u8] = new(58, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_memtag"u8] = new(59, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_memory"u8] = new(60, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_numerical_stability"u8] = new(61, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_realtime"u8] = new(62, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_realtime_blocking"u8] = new(63, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_thread"u8] = new(64, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sanitize_type"u8] = new(65, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["shadowcallstack"u8] = new(66, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["skipprofile"u8] = new(67, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["speculatable"u8] = new(68, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["speculative_load_hardening"u8] = new(69, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["ssp"u8] = new(70, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sspreq"u8] = new(71, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sspstrong"u8] = new(72, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["strictfp"u8] = new(73, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["swiftasync"u8] = new(74, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["swifterror"u8] = new(75, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["swiftself"u8] = new(76, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["willreturn"u8] = new(77, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["writable"u8] = new(78, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["writeonly"u8] = new(79, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["zeroext"u8] = new(80, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_None, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["byref"u8] = new(81, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["byval"u8] = new(82, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["elementtype"u8] = new(83, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["inalloca"u8] = new(84, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["preallocated"u8] = new(85, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["sret"u8] = new(86, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Type, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["align"u8] = new(87, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["allockind"u8] = new(88, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["allocsize"u8] = new(89, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["captures"u8] = new(90, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["dereferenceable"u8] = new(91, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["dereferenceable_or_null"u8] = new(92, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["memory"u8] = new(93, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["nofpclass"u8] = new(94, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["alignstack"u8] = new(95, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["uwtable"u8] = new(96, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["vscale_range"u8] = new(97, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_Int, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Function), + ["range"u8] = new(98, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_ConstantRange, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Return | LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + ["initializes"u8] = new(99, LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_ConstantRangeList, LibLLVMAttributeAllowedOn.LibLLVMAttributeAllowedOn_Parameter), + }.ToImmutable(); + + // for a debug build, write the element entries for the "KnownAttributes" + // This makes it easier to update that map AFTER validation of any changed values. + [Conditional("DEBUG")] + private static void ShowKnownAttributesEntry( LazyEncodedString name, LibLLVMAttributeInfo info ) + { + var flagValues = from val in info.AllowedOn.ToString().Split(',') + select $"{nameof(LibLLVMAttributeAllowedOn)}.{val.Trim()}"; + + if(info.ID == 1) + { + Debug.WriteLine( "// First Enum attribute..." ); + } + + Debug.WriteLine( $"[\"{name}\"u8] = new({info.ID}, LibLLVMAttributeArgKind.{info.ArgKind}, {string.Join( " | ", flagValues )})," ); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/ContextBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/ContextBindingsTests.cs new file mode 100644 index 000000000..181ef6f21 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/ContextBindingsTests.cs @@ -0,0 +1,30 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.ContextBindings; +using static Ubiquity.NET.Llvm.Interop.ABI.llvm_c.Core; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class ContextBindingsTests + { + [TestMethod] + public void LibLLVMContextGetIsODRUniquingDebugTypesTest( ) + { + using LLVMContextRef ctx = LLVMContextCreate(); + Assert.IsFalse(LibLLVMContextGetIsODRUniquingDebugTypes(ctx)); + } + + [TestMethod] + public void LibLLVMContextSetIsODRUniquingDebugTypesTest( ) + { + using LLVMContextRef ctx = LLVMContextCreate(); + LibLLVMContextSetIsODRUniquingDebugTypes(ctx, true); + Assert.IsTrue(LibLLVMContextGetIsODRUniquingDebugTypes(ctx)); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/DataLayoutBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/DataLayoutBindingsTests.cs new file mode 100644 index 000000000..96fc06f02 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/DataLayoutBindingsTests.cs @@ -0,0 +1,62 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.InteropHelpers; +using Ubiquity.NET.Llvm.Interop.UT; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.DataLayoutBindings; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class DataLayoutBindingsTests + { + [TestMethod] + public void LibLLVMParseDataLayoutTest( ) + { + using(var errorRef = LibLLVMParseDataLayout("badlayout"u8, out LLVMTargetDataRef retVal)) + using(retVal) + { + Assert.IsTrue(retVal.IsInvalid); + Assert.IsTrue(errorRef.Failed); + string errMsg = errorRef.ToString(); + Assert.IsFalse(string.IsNullOrWhiteSpace(errMsg), "Failure should have an error message"); + } + + // should match SPARC but as long as it is valid syntax the semantics don't matter. + LazyEncodedString goodLayout = "E-p:32:32-f128:128:128"u8; + using(var errorRef = LibLLVMParseDataLayout(goodLayout, out LLVMTargetDataRef retVal)) + using(retVal) + { + Assert.IsFalse(errorRef.Failed); + Assert.IsTrue(errorRef.Success); + Assert.IsFalse(retVal.IsInvalid); + string errMsg = errorRef.ToString(); + Assert.IsTrue(string.IsNullOrWhiteSpace(errMsg), "Valid layout should NOT have an error message"); + } + } + + [TestMethod] + public void LibLLVMGetDataLayoutStringTest( ) + { + // should match SPARC but as long as it is valid syntax the semantics don't matter. + LazyEncodedString goodLayout = "E-p:32:32-f128:128:128"u8; + using(var errorRef = LibLLVMParseDataLayout(goodLayout, out LLVMTargetDataRef retVal)) + using(retVal) + { + // status of parse assumed correct, behavior is validated in LibLLVMParseDataLayoutTest() + + LazyEncodedString? retrievedLayout = LibLLVMGetDataLayoutString(retVal); + Assert.IsNotNull(retrievedLayout); + Assert.IsFalse(LazyEncodedString.IsNullOrEmpty(retrievedLayout)); + Assert.IsFalse(LazyEncodedString.IsNullOrWhiteSpace(retrievedLayout)); + + // This assert is a bit dodgy, as there's no formal canonicalization of the layout strings + // and multiple strings can describe the same layout... BUT, the retrieval returns the + // EXACT string used to create the layout, thus, for this test it is a legit thing to do. + Assert.AreEqual(goodLayout, retrievedLayout); + } + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/IRBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/IRBindingsTests.cs new file mode 100644 index 000000000..5453838b7 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/IRBindingsTests.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.IRBindings; +using static Ubiquity.NET.Llvm.Interop.ABI.llvm_c.Core; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class IRBindingsTests + { + [SkipTestMethod] + public void LibLLVMHasUnwindDestTest( ) + { + // As of this writing, the only implemented instructions that might contain an unwind dest are a CleanupReturn and + // CatchSwitchInst, all other instructions result in a 0; + // TODO: Figure out minimum API calls needed to build a valid case for each type and at least one for the "negative" + // then validate the API returns the correct value. + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/MetadataBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/MetadataBindingsTests.cs new file mode 100644 index 000000000..f7acef8f2 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/MetadataBindingsTests.cs @@ -0,0 +1,186 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class MetadataBindingsTests + { + [SkipTestMethod] + public void LibLLVMDIBasicTypeGetEncodingTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetNodeContextTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDiCompileUnitGetEmissionKindTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDIBuilderCreateTempFunctionFwdDeclTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDIBuilderFinalizeSubProgramTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDIDescriptorGetTagTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDILocationGetInlinedAtScopeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMMetadataAsStringTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMMDNodeGetNumOperandsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMMDNodeGetOperandTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMMDNodeReplaceOperandTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetOperandNodeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMetadataGetParentModuleTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMetadataEraseFromParentTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetMetadataIDTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMDNodeGetNumOperandsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMDNodeGetOperandTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMDNodeSetOperandTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMDNodeAddOperandTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNamedMDNodeClearOperandsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMConstantAsMetadataTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetMDStringTextTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMAddNamedMetadataOperand2Test( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMSetMetadata2Test( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMIsTemporaryTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMIsResolvedTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMIsUniquedTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMIsDistinctTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDISubRangeGetLowerBoundsTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/ModuleBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/ModuleBindingsTests.cs new file mode 100644 index 000000000..df495c6c4 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/ModuleBindingsTests.cs @@ -0,0 +1,120 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class ModuleBindingsTests + { + [SkipTestMethod] + public void LibLLVMModuleGetComdatTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleGetNumComdatsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleBeginComdatsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMNextComdatTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMCurrentComdatTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleComdatIteratorResetTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMDisposeComdatIteratorTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetOrInsertFunctionTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetModuleSourceFileNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMSetModuleSourceFileNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetModuleNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetGlobalAliasTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleInsertOrUpdateComdatTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleComdatRemoveTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleComdatClearTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMComdatGetNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleGetFirstGlobalAliasTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMModuleGetNextGlobalAliasTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/ObjectFileBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/ObjectFileBindingsTests.cs new file mode 100644 index 000000000..2fd7e79f6 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/ObjectFileBindingsTests.cs @@ -0,0 +1,30 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class ObjectFileBindingsTests + { + [SkipTestMethod] + public void LibLLVMSymbolIteratorCloneTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMSectionIteratorCloneTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMRelocationIteratorCloneTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/OrcJITv2BindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/OrcJITv2BindingsTests.cs new file mode 100644 index 000000000..e0426db16 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/OrcJITv2BindingsTests.cs @@ -0,0 +1,18 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class OrcJITv2BindingsTests + { + [SkipTestMethod] + public void LibLLVMExecutionSessionRemoveDyLibTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/PassBuilderOptionsBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/PassBuilderOptionsBindingsTests.cs new file mode 100644 index 000000000..eeb3bbf78 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/PassBuilderOptionsBindingsTests.cs @@ -0,0 +1,90 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class PassBuilderOptionsBindingsTests + { + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetVerifyEachTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetDebugLoggingTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetAAPipelineTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetLoopInterleavingTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetLoopVectorizationTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetSLPVectorizationTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetLoopUnrollingTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetForgetAllSCEVInLoopUnrollTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetLicmMssaOptCapTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetLicmMssaNoAccForPromotionCapTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetCallGraphProfileTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetMergeFunctionsTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMPassBuilderOptionsGetInlinerThresholdTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/ReadMe.md b/src/Interop/InteropTests/ABI/libllvm-c/ReadMe.md new file mode 100644 index 000000000..2d2f3d2e0 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/ReadMe.md @@ -0,0 +1,14 @@ +# LibLLVM Interop Tests +These tests focus on validating the extended C API unique to LibLLVM. They do NOT +test the official LLVM-C API nor it's interop bindings. (That would be excessive and +likely redundant as LLVM itself tests the APIs better, and the callers are tested in +the wrapper libraries in this repo.) The LibLLVM methods are unique to this library +and need testing at this low level to ensure that the upper layers can rely on them +to behave as expected. There is no native code testing of these APIs (at least not at +this point) so this is the only "line of defense" for them. + +>[!IMPORTANT] +> As of this writing most are completely empty tests that don't do anything. These +> will come online in subsequent builds. In many cases the value of tests at this +> low level is debatable. Is it worth 300 lines of complex setup to test one function +> call? Especially when the upper layers do exercise the functionality? diff --git a/src/Interop/InteropTests/ABI/libllvm-c/TargetMachineBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/TargetMachineBindingsTests.cs new file mode 100644 index 000000000..8648aa8e3 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/TargetMachineBindingsTests.cs @@ -0,0 +1,78 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class TargetMachineBindingsTests + { + [SkipTestMethod] + public void LibLLVMGetTargetMachineAsmVerbosityTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetTargetMachineFastISelTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetTargetMachineGlobalISelTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetTargetMachineGlobalISelAbortTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetTargetMachineMachineOutlinerTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetCPUTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetFeaturesTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetABITest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetCodeGenOptLevelTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetRelocModeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTargetMachineOptionsGetCodeModelTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/TargetRegistrationBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/TargetRegistrationBindingsTests.cs new file mode 100644 index 000000000..c55b65b79 --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/TargetRegistrationBindingsTests.cs @@ -0,0 +1,72 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.InteropHelpers; +using Ubiquity.NET.Llvm.Interop.UT; + +using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.TargetRegistrationBindings; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class TargetRegistrationBindingsTests + { + [SkipTestMethod] + public void LibLLVMRegisterTargetTest( ) + { + throw new NotImplementedException(); + } + + [TestMethod] + public void LibLLVMGetNumTargetsTest( ) + { + Int32 numTargets = LibLLVMGetNumTargets(); + // -3 to account for declared "None, Native, and ALL" values + // not included in native methods. + int expectedTargets = Enum.GetValues().Length - 3; + Assert.AreEqual(expectedTargets, numTargets); + } + + [TestMethod] + public void LibLLVMGetRuntimeTargetsTest( ) + { + var targets = new LibLLVMCodeGenTarget[LibLLVMGetNumTargets()]; + LibLLVMGetRuntimeTargets( targets ).ThrowIfFailed(); + + // Test supported targets; This is an extension as at one point the + // set of supported targets was ONLY the native target and that of one + // additional target. That's not true anymore, so this should verify + // that ALL (non-experimental) targets are an option. + var nativeTargets = from id in Enum.GetValues() + where id != LibLLVMCodeGenTarget.CodeGenTarget_None + && id != LibLLVMCodeGenTarget.CodeGenTarget_Native + && id != LibLLVMCodeGenTarget.CodeGenTarget_All + select id; + + foreach(var v in nativeTargets) + { + Assert.IsTrue(targets.Contains(v), $"Target: {v} should be supported"); + } + } + + [TestMethod] + public void LibLLVMGetVersionTest( ) + { + UInt64 ver = LibLLVMGetVersion(); + Assert.IsTrue( ver > 0); + var csemVer = CSemVer.FromUInt64(ver); + Assert.AreEqual(20u, csemVer.Major); + Assert.AreEqual(1u, csemVer.Minor); + + // Testing for an exact match of the patch level (or anything finer grained than that) + // in an automated test is dubious as it would require updating the tests on effectively + // EVERY build of the native library... So, this tests for a minimum value that was valid + // at the time of creation. The above major/minor values should be updated on changes to + // those assumptions as any number of things may have changed. + Assert.IsTrue(4u <= csemVer.Patch); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/TripleBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/TripleBindingsTests.cs new file mode 100644 index 000000000..695f7ea9f --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/TripleBindingsTests.cs @@ -0,0 +1,120 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class TripleBindingsTests + { + [SkipTestMethod] + public void LibLLVMGetHostTripleTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMParseTripleTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleOpEqualTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetArchTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetSubArchTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetVendorTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetOsTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleHasEnvironmentTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetEnvironmentTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetEnvironmentVersionTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetObjectFormatTypeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleAsStringTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetArchTypeNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetSubArchTypeNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetVendorTypeNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetOsTypeNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetEnvironmentTypeNameTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMTripleGetObjectFormatTypeNameTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ABI/libllvm-c/ValueBindingsTests.cs b/src/Interop/InteropTests/ABI/libllvm-c/ValueBindingsTests.cs new file mode 100644 index 000000000..b41cfdb1b --- /dev/null +++ b/src/Interop/InteropTests/ABI/libllvm-c/ValueBindingsTests.cs @@ -0,0 +1,102 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ubiquity.NET.Llvm.Interop.UT; + +namespace Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.UT +{ + [TestClass] + public class ValueBindingsTests + { + [SkipTestMethod] + public void LibLLVMIsConstantZeroValueTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMRemoveGlobalFromParentTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetValueKindTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetAliaseeTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetArgumentIndexTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGlobalVariableAddDebugExpressionTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMFunctionAppendBasicBlockTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMValueAsMetadataGetValueTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMCreateValueCacheTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMValueCacheAddTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMValueCacheLookupTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMIsConstantCStringTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetConstantDataSequentialElementCountTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMGetConstantDataSequentialRawDataTest( ) + { + throw new NotImplementedException(); + } + + [SkipTestMethod] + public void LibLLVMHasDbgRecordsTest( ) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Interop/InteropTests/ArchitectureExtensionsTests.cs b/src/Interop/InteropTests/ArchitectureExtensionsTests.cs index 2f80e0a38..1ce0cd737 100644 --- a/src/Interop/InteropTests/ArchitectureExtensionsTests.cs +++ b/src/Interop/InteropTests/ArchitectureExtensionsTests.cs @@ -11,6 +11,7 @@ namespace Ubiquity.NET.Llvm.Interop.UT public class ArchitectureExtensionsTests { [TestMethod] + [TestProperty("Description", "Validates the Ubiquity.NET.Llvm.Interop.ArchitectureExtensions.AsLLVMTarget() extension method")] public void GetLibLLVMTargetTest( ) { Assert.AreEqual(LibLLVMCodeGenTarget.CodeGenTarget_ARM, Architecture.Arm.AsLLVMTarget()); diff --git a/src/Interop/InteropTests/AttributeTests.cs b/src/Interop/InteropTests/AttributeTests.cs deleted file mode 100644 index 946a682bd..000000000 --- a/src/Interop/InteropTests/AttributeTests.cs +++ /dev/null @@ -1,72 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Ubiquity.NET Contributors. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Collections.Immutable; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Ubiquity.NET.InteropHelpers; -using Ubiquity.NET.Llvm.Interop.ABI.libllvm_c; -using Ubiquity.NET.Llvm.Interop.ABI.StringMarshaling; - -using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.AttributeBindings; -using static Ubiquity.NET.Llvm.Interop.ABI.llvm_c.Core; - -namespace Ubiquity.NET.Llvm.Interop.UT -{ - [TestClass] - public class AttributeTests - { - // This tests the underlying behavior of the LLVM and LibLLVM APIs with regard - // to a custom string attribute. ANY key/value pair is valid for a custom attribute - // and LLVM does nothing to validate them. (Though a custom target or pass might - // know more details and provide additional checks) - [TestMethod] - public void CustomAttributeTests( ) - { - using LLVMContextRef ctx = LLVMContextCreate(); - LazyEncodedString name = new("custom"u8); - LazyEncodedString value = "custom value"u8; - - LLVMAttributeRef attribValue = LLVMCreateStringAttribute(ctx, name, value); - - Assert.IsFalse(attribValue.IsNull); - - // LibLLVM should support Custom attributes as well. - LazyEncodedString attribName = new("custom"); - using LLVMErrorRef errorRef = LibLLVMGetAttributeInfo(attribName, out LibLLVMAttributeInfo info); - errorRef.ThrowIfFailed(); - - Assert.AreEqual(LibLLVMAttributeArgKind.LibLLVMAttributeArgKind_String, info.ArgKind); - } - - [TestMethod] - public void AttributeListAttainable( ) - { - int len = checked((int)LibLLVMGetNumKnownAttribs()); - unsafe - { - byte** ppData = stackalloc byte*[len]; - using LLVMErrorRef errorRef = LibLLVMGetKnownAttributeNames(ppData, (nuint)len); - errorRef.ThrowIfFailed(); - - // make sure conversion is plausible. - var bldr = ImmutableArray.CreateBuilder(len); - for(int i=0; i < len; ++i) - { - // https://github.com/microsoft/testfx/issues/5543 -#pragma warning disable MSTEST0037 // Use proper 'Assert' methods - Assert.IsTrue(ppData[i] is not null); -#pragma warning restore MSTEST0037 // Use proper 'Assert' methods - - bldr.Add( LazyEncodedString.FromUnmanaged(ppData[i])!); - } - - var names = bldr.ToImmutable(); - } - } - } -} diff --git a/src/Interop/InteropTests/DataLayoutTests.cs b/src/Interop/InteropTests/DataLayoutTests.cs deleted file mode 100644 index f190c90b9..000000000 --- a/src/Interop/InteropTests/DataLayoutTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Ubiquity.NET Contributors. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Runtime.InteropServices; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Ubiquity.NET.InteropHelpers; - -using static Ubiquity.NET.Llvm.Interop.ABI.libllvm_c.DataLayoutBindings; - -namespace Ubiquity.NET.Llvm.Interop.UT -{ - [TestClass] - public class DataLayoutTests - { - [TestMethod] - public void TestParseKnownBad( ) - { - LazyEncodedString utf8Span = "badlayout"u8; - using var errorRef = LibLLVMParseDataLayout(utf8Span, out LLVMTargetDataRef retVal); - using(retVal) - { - Assert.IsTrue(retVal.IsInvalid); - Assert.IsTrue(errorRef.Failed); - string errMsg = errorRef.ToString(); - Assert.IsFalse(string.IsNullOrWhiteSpace(errMsg), "Failure should have an error message"); - } - } - } -} diff --git a/src/Interop/InteropTests/DebugRecordTests.cs b/src/Interop/InteropTests/DebugRecordTests.cs index c2d1834a3..6a4d92438 100644 --- a/src/Interop/InteropTests/DebugRecordTests.cs +++ b/src/Interop/InteropTests/DebugRecordTests.cs @@ -22,7 +22,9 @@ public class DebugRecordTests // where it (As of LLVM 20.1.3) will just crash if the instruction has no // debug records attached. (Worse it lands in the dreaded Undefined Behavior // if the value is NOT an instruction since it blindly casts it assuming it - // is there's no guarantees on what will happen for any other type of Value...) + // is - there's no guarantees on what will happen for any other type of Value...) + // Thus, LibLLVMHasDbgRecords was introduced to help detect/avoid these problematic + // cases. [TestMethod] public void DebugRecordEnumerationSucceeds( ) { @@ -59,7 +61,7 @@ public void DebugRecordEnumerationSucceeds( ) Assert.IsFalse(LibLLVMHasDbgRecords(mallocInst)); // Now attach debug records to the malloc. - // first create the information to attach (It's alot...) + // first create the information to attach (It's a lot...) using LLVMDIBuilderRef diBuilder = LLVMCreateDIBuilder(module); LLVMMetadataRef int32DiType = LLVMDIBuilderCreateBasicType( diBuilder, @@ -89,7 +91,7 @@ public void DebugRecordEnumerationSucceeds( ) LLVMMetadataRef diLocation = LLVMDIBuilderCreateDebugLocation(ctx, 123,4, scope, default); // Now attach the record to the result of the malloc call - // and retest the status as it should be different + // and retest the status as it should be different now LLVMDbgRecordRef dbgRecord = LLVMDIBuilderInsertDbgValueRecordBefore(diBuilder, mallocInst, int32PtrDiType, emptyExpression, diLocation, mallocInst); Assert.IsTrue(LibLLVMHasDbgRecords(mallocInst)); // this should not crash now... [It shouldn't ever but that's another story...] diff --git a/src/Interop/InteropTests/ModuleFixtures.cs b/src/Interop/InteropTests/ModuleFixtures.cs index 73b715e85..89638da75 100644 --- a/src/Interop/InteropTests/ModuleFixtures.cs +++ b/src/Interop/InteropTests/ModuleFixtures.cs @@ -21,6 +21,13 @@ public static void AssemblyInitialize(TestContext ctx) { ArgumentNullException.ThrowIfNull( ctx ); + //ctx.WriteLine("Hello world!"); // Goes to great bit pool in the sky... [Sort-of.] + // reality: ctx.Write*() calls go to a string writer, the results of that are captured + // stored and then ignored, UNLESS the result of THIS initializer is not success. + // Thus, in the real world those APIs are completely useless in an assembly initializer. + // Instead an implementation can use the DisplayMessage() method to write data to the + // "tests" pane in VS (Where, or if, that is reported in other environments is unknown) + // ctx.DisplayMessage(MessageLevel.Informational, nameof(AssemblyInitialize)); // Goes to "Tests" pane in VS LibLLVM?.Dispose(); LibLLVM = Library.InitializeLLVM(); diff --git a/src/Interop/InteropTests/SkipTestAttribute.cs b/src/Interop/InteropTests/SkipTestAttribute.cs new file mode 100644 index 000000000..ff7a7b701 --- /dev/null +++ b/src/Interop/InteropTests/SkipTestAttribute.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Ubiquity.NET.Llvm.Interop.UT +{ + /// Attribute to mark tests as ignored before completion of development + /// + /// This allows creation of tests that can at least compile but are not yet complete (or + /// even started yet). Such tests act as place-holders for formal testing not yet complete. + /// These are easier to see in code than a completely missing test with a random TODO or + /// work item created somewhere (if you are lucky). Thus tests should be created and intent + /// documented even if they aren't implemented yet (as the underlying code under test is still + /// taking shape). + /// + public sealed class SkipTestMethodAttribute + : TestMethodAttribute + { + public override TestResult[] Execute( ITestMethod testMethod ) + { + return [new() { Outcome = UnitTestOutcome.Ignored }]; + } + } +} diff --git a/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/libllvm-c/DataLayoutBindings.cs b/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/libllvm-c/DataLayoutBindings.cs index d36ddabc7..16009d4a8 100644 --- a/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/libllvm-c/DataLayoutBindings.cs +++ b/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/libllvm-c/DataLayoutBindings.cs @@ -30,6 +30,6 @@ public static LLVMErrorRef LibLLVMParseDataLayout(LazyEncodedString layoutString [LibraryImport( LibraryName )] [UnmanagedCallConv( CallConvs = [ typeof( CallConvCdecl ) ] )] - public static unsafe partial byte* LibLLVMGetDataLayoutString(LLVMTargetDataRefAlias dataLayout, out nuint outLen); + private static unsafe partial byte* LibLLVMGetDataLayoutString(LLVMTargetDataRefAlias dataLayout, out nuint outLen); } } diff --git a/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/llvm-c/Core.cs b/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/llvm-c/Core.cs index ed9f2def3..5116e5464 100644 --- a/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/llvm-c/Core.cs +++ b/src/Interop/Ubiquity.NET.Llvm.Interop/ABI/llvm-c/Core.cs @@ -509,9 +509,35 @@ public static uint LLVMGetEnumAttributeKindForName( LazyEncodedString Name ) [UnmanagedCallConv( CallConvs = [ typeof( CallConvCdecl ) ] )] public static unsafe partial LLVMTypeRef LLVMGetTypeAttributeValue( LLVMAttributeRef A ); - [LibraryImport( LibraryName )] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static LLVMAttributeRef LLVMCreateConstantRangeAttribute( + LLVMContextRefAlias C, + uint KindID, + uint NumBits, + [In] UInt64[] LowerWords, + [In] UInt64[] UpperWords + ) + { +#if DEBUG + long requiredLen = (NumBits / 64) + ((NumBits % 64) == 0 ? 0 : 1); + if (LowerWords.LongLength < requiredLen) + { + // TODO: Intern and localize this error message format + throw new ArgumentException($"Array length ({LowerWords.LongLength}) does not support specified bit width: {NumBits}", nameof(LowerWords)); + } + + if (UpperWords.LongLength < requiredLen) + { + // TODO: Intern and localize this error message format + throw new ArgumentException($"Array length ({UpperWords.LongLength}) does not support specified bit width: {NumBits}", nameof(UpperWords)); + } +#endif + return NativeLLVMCreateConstantRangeAttribute(C, KindID, NumBits, LowerWords, UpperWords); + } + + [LibraryImport( LibraryName, EntryPoint = "LLVMCreateConstantRangeAttribute" )] [UnmanagedCallConv( CallConvs = [ typeof( CallConvCdecl ) ] )] - public static unsafe partial LLVMAttributeRef LLVMCreateConstantRangeAttribute( + private static unsafe partial LLVMAttributeRef NativeLLVMCreateConstantRangeAttribute( LLVMContextRefAlias C, uint KindID, uint NumBits, @@ -3398,9 +3424,20 @@ LazyEncodedString Name [UnmanagedCallConv( CallConvs = [ typeof( CallConvCdecl ) ] )] public static unsafe partial LLVMValueRef LLVMBuildCatchRet( LLVMBuilderRef B, LLVMValueRef CatchPad, LLVMBasicBlockRef BB ); + public static LLVMValueRef LLVMBuildCatchPad( + LLVMBuilderRef B, + LLVMValueRef ParentPad, + LLVMValueRef[]? Args, + LazyEncodedString? Name + ) + { + Args ??= []; + return LLVMBuildCatchPad(B, ParentPad, Args, checked((uint)Args.Length), Name ?? LazyEncodedString.Empty); + } + [LibraryImport( LibraryName )] [UnmanagedCallConv( CallConvs = [ typeof( CallConvCdecl ) ] )] - public static unsafe partial LLVMValueRef LLVMBuildCatchPad( + private static unsafe partial LLVMValueRef LLVMBuildCatchPad( LLVMBuilderRef B, LLVMValueRef ParentPad, //No marshalling attribute exists to set the length, the length of this array MUST be at least NumArgs diff --git a/src/Interop/InteropTests/StringMarshallingTests.cs b/src/Ubiquity.NET.InteropHelpers.UT/StringMarshallingTests.cs similarity index 98% rename from src/Interop/InteropTests/StringMarshallingTests.cs rename to src/Ubiquity.NET.InteropHelpers.UT/StringMarshallingTests.cs index a84009ca1..c3c2c9738 100644 --- a/src/Interop/InteropTests/StringMarshallingTests.cs +++ b/src/Ubiquity.NET.InteropHelpers.UT/StringMarshallingTests.cs @@ -9,9 +9,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Ubiquity.NET.InteropHelpers; - -namespace Ubiquity.NET.Llvm.Interop.UT +namespace Ubiquity.NET.InteropHelpers.UT { // TODO: Test encoding handling [TestClass] diff --git a/src/Ubiquity.NET.Llvm/DataLayoutAlias.cs b/src/Ubiquity.NET.Llvm/DataLayoutAlias.cs index 33cf45efb..a8e66ced7 100644 --- a/src/Ubiquity.NET.Llvm/DataLayoutAlias.cs +++ b/src/Ubiquity.NET.Llvm/DataLayoutAlias.cs @@ -142,12 +142,9 @@ public LazyEncodedString ToLazyEncodedString() return LazyEncodedString.Empty; } - unsafe - { - byte* pStr = LibLLVMGetDataLayoutString(NativeHandle, out nuint len); - Debug.Assert(pStr is not null, "Layout should always have a string representation"); - return LazyEncodedString.FromUnmanaged(pStr, len)!; - } + LazyEncodedString? retVal = LibLLVMGetDataLayoutString(NativeHandle); + Debug.Assert(retVal is not null, "Layout should always have a string representation"); + return retVal; } public override string? ToString( )