From e6e8dfb26bf668fefd16281673d24ad937d464d8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 22 Mar 2019 10:05:28 -0400 Subject: [PATCH] Another try at intrinsics --- Package.swift | 8 +- Sources/LLVM/Intrinsic.swift | 215 ++++++++++++++++++++++++++ Sources/LLVM/Module.swift | 78 +++++++++- Sources/cllvm/shim.h | 1 - Sources/llvmshims/include/shim.h | 11 ++ Sources/llvmshims/src/shim.cpp | 20 +++ Tests/LLVMTests/IRIntrinsicSpec.swift | 174 +++++++++++++++++++++ Tests/LinuxMain.swift | 1 + 8 files changed, 504 insertions(+), 4 deletions(-) create mode 100644 Sources/LLVM/Intrinsic.swift create mode 100644 Sources/llvmshims/include/shim.h create mode 100644 Sources/llvmshims/src/shim.cpp create mode 100644 Tests/LLVMTests/IRIntrinsicSpec.swift diff --git a/Package.swift b/Package.swift index 0233d122..54858f64 100644 --- a/Package.swift +++ b/Package.swift @@ -20,10 +20,14 @@ let package = Package( .brew(["llvm"]), ]), .target( - name: "LLVM", + name: "llvmshims", dependencies: ["cllvm"]), + .target( + name: "LLVM", + dependencies: ["cllvm", "llvmshims"]), .testTarget( name: "LLVMTests", dependencies: ["LLVM", "FileCheck"]), - ] + ], + cxxLanguageStandard: .cxx14 ) diff --git a/Sources/LLVM/Intrinsic.swift b/Sources/LLVM/Intrinsic.swift new file mode 100644 index 00000000..10a88899 --- /dev/null +++ b/Sources/LLVM/Intrinsic.swift @@ -0,0 +1,215 @@ +#if SWIFT_PACKAGE +import cllvm +import llvmshims +#endif +import Foundation + +/// An `Intrinsic` represents an intrinsic known to LLVM. +/// +/// Intrinsic functions have well known names and semantics and are required to +/// follow certain restrictions. Overall, these intrinsics represent an +/// extension mechanism for the LLVM language that does not require changing all +/// of the transformations in LLVM when adding to the language (or the bitcode +/// reader/writer, the parser, etc…). +/// +/// Intrinsic function names must all start with an `llvm.` prefix. This prefix +/// is reserved in LLVM for intrinsic names; thus, function names may not begin +/// with this prefix. Intrinsic functions must always be external functions: you +/// cannot define the body of intrinsic functions. Intrinsic functions may only +/// be used in call or invoke instructions: it is illegal to take the address of +/// an intrinsic function. +/// +/// Some intrinsic functions can be overloaded, i.e., the intrinsic represents a +/// family of functions that perform the same operation but on different data +/// types. Because LLVM can represent over 8 million different integer types, +/// overloading is used commonly to allow an intrinsic function to operate on +/// any integer type. One or more of the argument types or the result type can +/// be overloaded to accept any integer type. Argument types may also be defined +/// as exactly matching a previous argument’s type or the result type. This +/// allows an intrinsic function which accepts multiple arguments, but needs all +/// of them to be of the same type, to only be overloaded with respect to a +/// single argument or the result. +/// +/// Overloaded intrinsics will have the names of its overloaded argument types +/// encoded into its function name, each preceded by a period. Only those types +/// which are overloaded result in a name suffix. Arguments whose type is +/// matched against another type do not. For example, the llvm.ctpop function +/// can take an integer of any width and returns an integer of exactly the same +/// integer width. This leads to a family of functions such as +/// `i8 @llvm.ctpop.i8(i8 %val)` and `i29 @llvm.ctpop.i29(i29 %val)`. Only one +/// type, the return type, is overloaded, and only one type suffix is required. +/// Because the argument’s type is matched against the return type, it does not +/// require its own name suffix. +/// +/// Dynamic Member Lookup For Intrinsics +/// ==================================== +/// +/// This library provides a dynamic member lookup facility for retrieving +/// intrinsic selectors. For any LLVM intrinsic selector of the form +/// `llvm.foo.bar.baz`, the name of the corresponding dynamic member is that +/// name with any dots replaced by underscores. +/// +/// For example: +/// +/// llvm.foo.bar.baz -> Intrinsic.ID.llvm_foo_bar_baz +/// llvm.stacksave -> Intrinsic.ID.llvm_stacksave +/// llvm.x86.xsave64 -> Intrinsic.ID.llvm_x86_xsave64 +/// +/// Any existing underscores do not need to be replaced, e.g. +/// `llvm.va_copy` becomes `Intrinsic.ID.llvm_va_copy`. +/// +/// For overloaded intrinsics, the non-overloaded prefix excluding the explicit +/// type parameters is used and normalized according to the convention above. +/// +/// For example: +/// +/// llvm.sinf64 -> Intrinsic.ID.llvm_sin +/// llvm.memcpy.p0i8.p0i8.i32 -> Intrinsic.ID.llvm_memcpy +/// llvm.bswap.v4i32 -> Intrinsic.ID.llvm_bswap +public class Intrinsic: Function { + public struct Selector { + let index: UInt32 + fileprivate init(_ index: UInt32) { self.index = index } + } + + /// This type provides a dynamic member lookup facility for LLVM intrinsics. + /// + /// It is not possible to create a `DynamicIntrinsicResolver` in user code. + /// One is provided by `Intrinsic.ID`. + @dynamicMemberLookup public struct DynamicIntrinsicResolver { + private let exceptionalSet: Set + + fileprivate init() { + // LLVM naming conventions for intrinsics is really not consistent at all + // (see llvm.ssa_copy). We need to gather a table of all the intrinsics + // that have underscores in their names so we don't naively replace them + // with dots later. + // + // Luckily, no intrinsics that use underscores in their name also use + // dots. If this changes in the future, we need to be smarter here. + var table = Set() + table.reserveCapacity(16) + for idx in 1.. Intrinsic.ID.llvm_foo_bar_baz + /// llvm.stacksave -> Intrinsic.ID.llvm_stacksave + /// llvm.x86.xsave64 -> Intrinsic.ID.llvm_x86_xsave64 + /// + /// Any existing underscores do not need to be replaced, e.g. + /// `llvm.va_copy` becomes `Intrinsic.ID.llvm_va_copy`. + /// + /// For overloaded intrinsics, the non-overloaded prefix excluding the + /// explicit type parameters is used and normalized according to the + /// convention above. + /// + /// For example: + /// + /// llvm.sinf64 -> Intrinsic.ID.llvm_sin + /// llvm.memcpy.p0i8.p0i8.i32 -> Intrinsic.ID.llvm_memcpy + /// llvm.bswap.v4i32 -> Intrinsic.ID.llvm_bswap + /// + /// - Parameter selector: The LLVMSwift form of an intrinsic selector. + public subscript(dynamicMember selector: String) -> Selector { + precondition(selector.starts(with: "llvm_")) + + let prefix = "llvm." + let suffix = selector.dropFirst("llvm_".count) + let finalSelector: String + if self.exceptionalSet.contains(prefix + suffix) { + // If the exceptions set contains an entry for this selector, then it + // has an underscore and no dots so we can just concatenate prefix and + // suffix. + finalSelector = prefix + suffix + } else { + // Else, naively replace all the underscores with dots. + finalSelector = selector.replacingOccurrences(of: "_", with: ".") + } + + let index = LLVMLookupIntrinsicID(finalSelector, finalSelector.count) + assert(index > 0, "Member does not correspond to an LLVM intrinsic") + return Selector(index) + } + } + + /// The default dynamic intrinsic resolver. + public static let ID = DynamicIntrinsicResolver() + + /// Retrieves the name of this intrinsic if it is not overloaded. + public var name: String { + precondition(!self.isOverloaded, + "Cannot retrieve the full name of an overloaded intrinsic") + var count = 0 + guard let ptr = LLVMIntrinsicGetName(self.identifier, &count) else { + return "" + } + return String(cString: ptr) + } + + /// Retrieves the name of this intrinsic if it is overloaded, resolving it + /// with the given parameter types. + public func overloadedName(for parameterTypes: [IRType]) -> String { + precondition(self.isOverloaded, + "Cannot retrieve the overloaded name of a non-overloaded intrinsic") + var argIRTypes = parameterTypes.map { $0.asLLVM() as Optional } + return argIRTypes.withUnsafeMutableBufferPointer { buf -> String in + var count = 0 + guard let ptr = LLVMIntrinsicCopyOverloadedName(self.identifier, buf.baseAddress, parameterTypes.count, &count) else { + return "" + } + defer { free(UnsafeMutableRawPointer(mutating: ptr)) } + return String(cString: ptr) + } + } + + /// Retrieves the type of this intrinsic if it is not overloaded. + public var type: IRType { + precondition(!self.isOverloaded, + "Cannot retrieve type of overloaded intrinsic") + return convertType(LLVMTypeOf(asLLVM())) + } + + /// Resolves the type of an overloaded intrinsic using the given parameter + /// types. + /// + /// - Parameters: + /// - context: The context in which to create the type. + /// - parameterTypes: The type of the parameters to the intrinsic. + /// - Returns: The type of the intrinsic function with its overloaded + /// parameter types resolved. + public func overloadedType(in context: Context = .global, with parameterTypes: [IRType]) -> IRType { + var argIRTypes = parameterTypes.map { $0.asLLVM() as Optional } + return argIRTypes.withUnsafeMutableBufferPointer { buf -> IRType in + guard let ty = LLVMIntrinsicGetType(context.llvm, self.identifier, buf.baseAddress, parameterTypes.count) else { + fatalError("Could not retrieve type of intrinsic") + } + return convertType(ty) + } + } + + /// Retrieves if this intrinsic is overloaded. + public var isOverloaded: Bool { + return LLVMIntrinsicIsOverloaded(self.identifier) != 0 + } + + /// Retrieves the ID number of this intrinsic function. + public var identifier: UInt32 { + return LLVMGetIntrinsicID(self.llvm) + } +} diff --git a/Sources/LLVM/Module.swift b/Sources/LLVM/Module.swift index 37fad0e4..a036fcfd 100644 --- a/Sources/LLVM/Module.swift +++ b/Sources/LLVM/Module.swift @@ -371,13 +371,79 @@ extension Module { /// /// - parameter name: The name of the function to create. /// - /// - returns: A representation of the newly created function with the given + /// - returns: A representation of a function with the given /// name or nil if such a representation could not be created. public func function(named name: String) -> Function? { guard let fn = LLVMGetNamedFunction(llvm, name) else { return nil } return Function(llvm: fn) } + /// Searches for and retrieves an intrinsic with the given name in this module + /// if that name references an intrinsic. + /// + /// - Parameters: + /// - name: The name of the intrinsic to search for. + /// - parameters: The type of the parameters of the intrinsic to resolve any + /// ambiguity caused by overloads. + /// - returns: A representation of an intrinsic with the given name or nil + /// if such an intrinsic could not be found. + public func intrinsic(named name: String, parameters: [IRType] = []) -> Intrinsic? { + guard let intrinsic = self.function(named: name) else { + return nil + } + + let index = LLVMGetIntrinsicID(intrinsic.asLLVM()) + guard index != 0 else { return nil } + + guard LLVMIntrinsicIsOverloaded(index) != 0 else { + return Intrinsic(llvm: intrinsic.asLLVM()) + } + + var argIRTypes = parameters.map { $0.asLLVM() as Optional } + return argIRTypes.withUnsafeMutableBufferPointer { buf -> Intrinsic in + guard let value = LLVMGetIntrinsicDeclaration(self.llvm, index, buf.baseAddress, parameters.count) else { + fatalError("Could not retrieve type of intrinsic") + } + return Intrinsic(llvm: value) + } + } + + /// Searches for and retrieves an intrinsic with the given selector in this + /// module if that selector references an intrinsic. + /// + /// Unlike `Module.intrinsic(named:parameters:)`, the intrinsic function need + /// not be declared. If the module contains a declaration of the intrinsic + /// function, it will be returned. Else, a declaration for the intrinsic + /// will be created and appended to this module. + /// + /// LLVMSwift intrinsic selector syntax differs from the LLVM naming + /// conventions for intrinsics in one crucial way: all dots are replaced by + /// underscores. + /// + /// For example: + /// + /// llvm.foo.bar.baz -> Intrinsic.ID.llvm_foo_bar_baz + /// llvm.sin -> Intrinsic.ID.llvm_sin + /// llvm.stacksave -> Intrinsic.ID.llvm_stacksave + /// llvm.x86.xsave64 -> Intrinsic.ID.llvm_x86_xsave64 + /// + /// - Parameters: + /// - selector: The selector of the intrinsic to search for. + /// - parameters: The type of the parameters of the intrinsic to resolve any + /// ambiguity caused by overloads. + /// - returns: A representation of an intrinsic with the given name or nil + /// if such an intrinsic could not be found. + public func intrinsic(_ selector: Intrinsic.Selector, parameters: [IRType] = []) -> Intrinsic? { + var argIRTypes = parameters.map { $0.asLLVM() as Optional } + return argIRTypes.withUnsafeMutableBufferPointer { buf -> Intrinsic in + guard let value = LLVMGetIntrinsicDeclaration(self.llvm, selector.index, buf.baseAddress, parameters.count) else { + fatalError("Could not retrieve type of intrinsic") + } + return Intrinsic(llvm: value) + } + } + + /// Searches for and retrieves an alias with the given name in this module /// if that name references an existing alias. /// @@ -414,6 +480,16 @@ extension Module { return NamedMetadata(module: self, llvm: LLVMGetOrInsertNamedMetadata(self.llvm, name, name.count)) } + /// Build a named function body with the given type. + /// + /// - parameter name: The name of the newly defined function. + /// - parameter type: The type of the newly defined function. + /// + /// - returns: A value representing the newly inserted function definition. + public func addFunction(_ name: String, type: FunctionType) -> Function { + return Function(llvm: LLVMAddFunction(self.llvm, name, type.asLLVM())) + } + /// Build a named global of the given type. /// /// - parameter name: The name of the newly inserted global value. diff --git a/Sources/cllvm/shim.h b/Sources/cllvm/shim.h index 5fe60341..638e8eed 100644 --- a/Sources/cllvm/shim.h +++ b/Sources/cllvm/shim.h @@ -29,4 +29,3 @@ #include #include #include - diff --git a/Sources/llvmshims/include/shim.h b/Sources/llvmshims/include/shim.h new file mode 100644 index 00000000..f499f789 --- /dev/null +++ b/Sources/llvmshims/include/shim.h @@ -0,0 +1,11 @@ +#include + +#ifndef LLVMSWIFT_LLVM_SHIM_H +#define LLVMSWIFT_LLVM_SHIM_H + +size_t LLVMSwiftCountIntrinsics(void); +const char *LLVMSwiftGetIntrinsicAtIndex(size_t index); +unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen); + + +#endif /* LLVMSWIFT_LLVM_SHIM_H */ diff --git a/Sources/llvmshims/src/shim.cpp b/Sources/llvmshims/src/shim.cpp new file mode 100644 index 00000000..b007b068 --- /dev/null +++ b/Sources/llvmshims/src/shim.cpp @@ -0,0 +1,20 @@ +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Function.h" + +extern "C" { + size_t LLVMSwiftCountIntrinsics(void); + const char *LLVMSwiftGetIntrinsicAtIndex(size_t index); + unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen); +} + +size_t LLVMSwiftCountIntrinsics(void) { + return llvm::Intrinsic::num_intrinsics; +} + +const char *LLVMSwiftGetIntrinsicAtIndex(size_t index) { + return llvm::Intrinsic::getName(static_cast(index)).data(); +} + +unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen) { + return llvm::Function::lookupIntrinsicID({Name, NameLen}); +} diff --git a/Tests/LLVMTests/IRIntrinsicSpec.swift b/Tests/LLVMTests/IRIntrinsicSpec.swift new file mode 100644 index 00000000..c341bf71 --- /dev/null +++ b/Tests/LLVMTests/IRIntrinsicSpec.swift @@ -0,0 +1,174 @@ +import LLVM +import XCTest +import FileCheck +import Foundation +import cllvm +import llvmshims + +class IRIntrinsicSpec : XCTestCase { + func testIRIntrinsics() { + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["IRINTRINSIC"]) { + // IRINTRINSIC: ; ModuleID = '[[ModuleName:IRIntrinsicTest]]' + // IRINTRINSIC-NEXT: source_filename = "[[ModuleName]]" + let module = Module(name: "IRIntrinsicTest") + let builder = IRBuilder(module: module) + + // IRINTRINSIC: define i32 @readOneArg(i32, ...) { + let main = builder.addFunction("readOneArg", + type: FunctionType(argTypes: [IntType.int32], + returnType: IntType.int32, + isVarArg: true)) + // IRINTRINSIC-NEXT: entry: + let entry = main.appendBasicBlock(named: "entry") + builder.positionAtEnd(of: entry) + + // IRINTRINSIC-NEXT: [[VA_BUF:%[0-9]+]] = alloca i8* + let ap = builder.buildAlloca(type: PointerType(pointee: IntType.int8)) + // IRINTRINSIC-NEXT: [[CAST_VA_BUF:%[0-9]+]] = bitcast i8** [[VA_BUF]] to i8* + let ap2 = builder.buildBitCast(ap, type: PointerType(pointee: IntType.int8)) + + // IRINTRINSIC-NEXT: call void @llvm.va_start(i8* [[CAST_VA_BUF]]) + let vaStart = module.intrinsic(Intrinsic.ID.llvm_va_start)! + _ = builder.buildCall(vaStart, args: [ ap2 ]) + + // IRINTRINSIC-NEXT: [[RET_VAL:%[0-9]+]] = va_arg i8** [[VA_BUF]], i32 + let tmp = builder.buildVAArg(ap, type: IntType.int32) + + // IRINTRINSIC-NEXT: [[VA_COPY_BUF:%[0-9]+]] = alloca i8* + let aq = builder.buildAlloca(type: PointerType(pointee: IntType.int8)) + // IRINTRINSIC-NEXT: [[CAST_VA_COPY_BUF:%[0-9]+]] = bitcast i8** [[VA_COPY_BUF]] to i8* + let aq2 = builder.buildBitCast(aq, type: PointerType(pointee: IntType.int8)) + + // IRINTRINSIC-NEXT: call void @llvm.va_copy(i8* [[CAST_VA_BUF]], i8* [[CAST_VA_COPY_BUF]]) + let vaCopy = module.intrinsic(Intrinsic.ID.llvm_va_copy)! + _ = builder.buildCall(vaCopy, args: [ ap2, aq2 ]) + + // IRINTRINSIC-NEXT: call void @llvm.va_end(i8* [[CAST_VA_COPY_BUF]]) + let vaEnd = module.intrinsic(Intrinsic.ID.llvm_va_end)! + _ = builder.buildCall(vaEnd, args: [ aq2 ]) + + // IRINTRINSIC-NEXT: i32 [[RET_VAL]] + builder.buildRet(tmp) + // IRINTRINSIC-NEXT: } + module.dump() + + // IRINTRINSIC: ; Function Attrs: nounwind + // IRINTRINSIC-NEXT: declare void @llvm.va_start(i8*) #0 + + // IRINTRINSIC: ; Function Attrs: nounwind + // IRINTRINSIC-NEXT: declare void @llvm.va_copy(i8*, i8*) #0 + + // IRINTRINSIC: ; Function Attrs: nounwind + // IRINTRINSIC-NEXT: declare void @llvm.va_end(i8*) #0 + }) + + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["VIRTUALOVERLOAD-IRINTRINSIC"]) { + // VIRTUALOVERLOAD-IRINTRINSIC: ; ModuleID = '[[ModuleName:IRIntrinsicTest]]' + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: source_filename = "[[ModuleName]]" + let module = Module(name: "IRIntrinsicTest") + let builder = IRBuilder(module: module) + // VIRTUALOVERLOAD-IRINTRINSIC: define i32 @main() { + let main = builder.addFunction("main", + type: FunctionType(argTypes: [], + returnType: IntType.int32)) + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: entry: + let entry = main.appendBasicBlock(named: "entry") + builder.positionAtEnd(of: entry) + + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: [[VAR_PTR:%[0-9]+]] = alloca i32 + let variable = builder.buildAlloca(type: IntType.int32) + + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: store i32 1, i32* [[VAR_PTR]] + builder.buildStore(IntType.int32.constant(1), to: variable) + + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: [[COPY_PTR:%[0-9]+]] = call i32* @llvm.ssa.copy.p0i32(i32* %0) + let intrinsic = module.intrinsic(Intrinsic.ID.llvm_ssa_copy, parameters: [ PointerType(pointee: IntType.int32) ])! + let cpyVar = builder.buildCall(intrinsic, args: [variable]) + + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: [[LOAD_VAR:%[0-9]+]] = load i32, i32* [[COPY_PTR]] + let loadVar = builder.buildLoad(cpyVar) + + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: ret i32 [[LOAD_VAR]] + builder.buildRet(loadVar) + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: } + module.dump() + + // VIRTUALOVERLOAD-IRINTRINSIC: ; Function Attrs: nounwind readnone + // VIRTUALOVERLOAD-IRINTRINSIC-NEXT: declare i32* @llvm.ssa.copy.p0i32(i32* returned) #0 + }) + + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["INTRINSIC-FAMILY-RESOLVE"]) { + // INTRINSIC-FAMILY-RESOLVE: ; ModuleID = '[[ModuleName:IRIntrinsicTest]]' + // INTRINSIC-FAMILY-RESOLVE-NEXT: source_filename = "[[ModuleName]]" + let module = Module(name: "IRIntrinsicTest") + let builder = IRBuilder(module: module) + // INTRINSIC-FAMILY-RESOLVE: define i32 @main() { + let main = builder.addFunction("main", + type: FunctionType(argTypes: [], + returnType: IntType.int32)) + // INTRINSIC-FAMILY-RESOLVE-NEXT: entry: + let entry = main.appendBasicBlock(named: "entry") + builder.positionAtEnd(of: entry) + + let doubleAlloca = builder.buildAlloca(type: FloatType.double) + builder.buildStore(FloatType.double.constant(1.0), to: doubleAlloca) + let double = builder.buildLoad(doubleAlloca) + + let floatAlloca = builder.buildAlloca(type: FloatType.float) + builder.buildStore(FloatType.float.constant(1.0), to: floatAlloca) + let float = builder.buildLoad(floatAlloca) + + let halfAlloca = builder.buildAlloca(type: FloatType.half) + builder.buildStore(FloatType.half.constant(1.0), to: halfAlloca) + let half = builder.buildLoad(halfAlloca) + + // INTRINSIC-FAMILY-RESOLVE: call double @llvm.sin.f64(double + let sinf64 = module.intrinsic(Intrinsic.ID.llvm_sin, parameters: [ FloatType.double ])! + _ = builder.buildCall(sinf64, args: [double]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call double @llvm.cos.f64(double + let cosf64 = module.intrinsic(Intrinsic.ID.llvm_cos, parameters: [ FloatType.double ])! + _ = builder.buildCall(cosf64, args: [double]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call double @llvm.sqrt.f64(double + let sqrtf64 = module.intrinsic(Intrinsic.ID.llvm_sqrt, parameters: [ FloatType.double ])! + _ = builder.buildCall(sqrtf64, args: [double]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call double @llvm.log.f64(double + let logf64 = module.intrinsic(Intrinsic.ID.llvm_log, parameters: [ FloatType.double ])! + _ = builder.buildCall(logf64, args: [double]) + + // INTRINSIC-FAMILY-RESOLVE: call float @llvm.sin.f32(float + let sinf32 = module.intrinsic(Intrinsic.ID.llvm_sin, parameters: [ FloatType.float ])! + _ = builder.buildCall(sinf32, args: [float]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call float @llvm.cos.f32(float + let cosf32 = module.intrinsic(Intrinsic.ID.llvm_cos, parameters: [ FloatType.float ])! + _ = builder.buildCall(cosf32, args: [float]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call float @llvm.sqrt.f32(float + let sqrtf32 = module.intrinsic(Intrinsic.ID.llvm_sqrt, parameters: [ FloatType.float ])! + _ = builder.buildCall(sqrtf32, args: [float]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call float @llvm.log.f32(float + let logf32 = module.intrinsic(Intrinsic.ID.llvm_log, parameters: [ FloatType.float ])! + _ = builder.buildCall(logf32, args: [float]) + + // INTRINSIC-FAMILY-RESOLVE: call half @llvm.sin.f16(half + let sinf16 = module.intrinsic(Intrinsic.ID.llvm_sin, parameters: [ FloatType.half ])! + _ = builder.buildCall(sinf16, args: [half]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call half @llvm.cos.f16(half + let cosf16 = module.intrinsic(Intrinsic.ID.llvm_cos, parameters: [ FloatType.half ])! + _ = builder.buildCall(cosf16, args: [half]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call half @llvm.sqrt.f16(half + let sqrtf16 = module.intrinsic(Intrinsic.ID.llvm_sqrt, parameters: [ FloatType.half ])! + _ = builder.buildCall(sqrtf16, args: [half]) + // INTRINSIC-FAMILY-RESOLVE-NEXT: call half @llvm.log.f16(half + let logf16 = module.intrinsic(Intrinsic.ID.llvm_log, parameters: [ FloatType.half ])! + _ = builder.buildCall(logf16, args: [half]) + + builder.buildRet(IntType.int32.zero()) + module.dump() + }) + } + + #if !os(macOS) + static var allTests = testCase([ + ("testIRIntrinsics", testIRIntrinsics), + ]) + #endif +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index b239d54f..80b32a1f 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -12,6 +12,7 @@ XCTMain([ IRBuilderSpec.allTests, IRExceptionSpec.allTests, IRGlobalSpec.allTests, + IRIntrinsicSpec.allTests, IRMetadataSpec.allTests, IROperationSpec.allTests, // FIXME: These tests cannot run on Linux without SEGFAULT'ing.