From 7c4255eb2d51165dc66392388c6e19745d4877be Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 30 Jan 2017 18:38:01 -0500 Subject: [PATCH 1/3] Added some missing C standard library functions --- Sources/LLVM/IRBuilder.swift | 89 +++++++++++++++++++++++++++-- Tests/LLVMTests/IRBuilderSpec.swift | 1 + 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/Sources/LLVM/IRBuilder.swift b/Sources/LLVM/IRBuilder.swift index e82165c8..aca196ef 100644 --- a/Sources/LLVM/IRBuilder.swift +++ b/Sources/LLVM/IRBuilder.swift @@ -580,24 +580,32 @@ public class IRBuilder { /// value. /// /// Whether an integer or floating point divide instruction is built is - /// determined by the type of the first given value. Providing operands that + /// determined by the type of the first given value. Providing operands that /// are neither integers nor floating values is a fatal condition. /// /// - parameter lhs: The first value (the dividend). /// - parameter rhs: The second value (the divisor). /// - parameter signed: Whether to emit a signed or unsigned remainder - /// instruction. Defaults to emission of a signed divide instruction. + /// instruction. Defaults to emission of a signed + /// divide instruction. + /// - parameter exact: Whether this division must be exact. Defaults to + /// inexact. /// - parameter name: The name for the newly inserted instruction. /// /// - returns: A value representing the quotient of the first and second /// operands. public func buildDiv(_ lhs: IRValue, _ rhs: IRValue, - signed: Bool = true, name: String = "") -> IRValue { + signed: Bool = true, exact: Bool = false, + name: String = "") -> IRValue { let lhsVal = lhs.asLLVM() let rhsVal = rhs.asLLVM() if lhs.type is IntType { if signed { - return LLVMBuildSDiv(llvm, lhsVal, rhsVal, name) + if exact { + return LLVMBuildExactSDiv(llvm, lhsVal, rhsVal, name) + } else { + return LLVMBuildSDiv(llvm, lhsVal, rhsVal, name) + } } else { return LLVMBuildUDiv(llvm, lhsVal, rhsVal, name) } @@ -960,6 +968,30 @@ public class IRBuilder { return LLVMBuildStructGEP(llvm, ptr.asLLVM(), UInt32(index), name) } + /// Builds an ExtractElement instruction to retrieve an indexed value from a + /// vector value. + /// + /// - parameter vec: The vector you're indexing into. + /// - parameter index: The index at which to extract. + /// + /// - returns: The value in the vector at the provided index. + public func buildExtractElement(_ vec: IRValue, index: IRValue, + name: String = "") -> IRValue { + return LLVMBuildExtractElement(llvm, vec.asLLVM(), index.asLLVM(), name) + } + + /// Builds an ExtractValue instruction to retrieve an indexed value from a + /// struct or array value. + /// + /// - parameter value: The struct or array you're indexing into. + /// - parameter index: The index at which to extract. + /// + /// - returns: The value in the struct at the provided index. + public func buildExtractValue(_ value: IRValue, index: Int, + name: String = "") -> IRValue { + return LLVMBuildExtractValue(llvm, value.asLLVM(), UInt32(index), name) + } + // MARK: Null Test Instructions /// Builds a comparision instruction that returns whether the given operand is @@ -1013,6 +1045,20 @@ public class IRBuilder { public func buildBitCast(_ val: IRValue, type: IRType, name: String = "") -> IRValue { return LLVMBuildBitCast(llvm, val.asLLVM(), type.asLLVM(), name) } + + /// Builds a cast instruction to convert the given floating-point value to a + /// value of the given type. + /// + /// - parameter val: The value to cast. + /// - parameter type: The destination type. + /// - parameter name: The name for the newly inserted instruction. + /// + /// - returns: A value representing the result of casting the given value + /// to fit the given type. + public func buildFPCast(_ val: IRValue, type: IRType, name: String = "") -> IRValue { + return LLVMBuildFPCast(llvm, val.asLLVM(), type.asLLVM(), name) + } + /// Builds a truncate instruction to truncate the given value to the given /// type with a shorter width. /// @@ -1221,6 +1267,41 @@ public class IRBuilder { return LLVMBuildAtomicRMW(llvm, atomicOp.llvm, ptr.asLLVM(), value.asLLVM(), ordering.llvm, singleThreaded.llvm) } + // MARK: C Standard Library Instructions + + /// Builds a call to the C standard library `malloc` instruction. + /// ``` + /// (type *)malloc(sizeof(type)); + /// ``` + /// If `count` is provided, it is equivalent to: + /// ``` + /// (type *)malloc(sizeof(type) * count); + /// ``` + /// + /// - parameter type: The intended result type being allocated. The result + /// of the `malloc` will be a pointer to this type. + /// - parameter count: An optional number of slots to allocate, to simulate a + /// C array. This is equivalent to + /// - parameter name: The intended name for the `malloc`'d value. + public func buildMalloc(_ type: IRType, count: IRValue? = nil, + name: String = "") -> IRValue { + if let count = count { + return LLVMBuildArrayMalloc(llvm, type.asLLVM(), count.asLLVM(), name) + } else { + return LLVMBuildMalloc(llvm, type.asLLVM(), name) + } + } + + /// Builds a call to the C standard library `free` function, with the provided + /// pointer. + /// + /// - parameter ptr: The pointer to `free`. + /// - returns: The `free` instruction. + @discardableResult + public func buildFree(_ ptr: IRValue) -> IRValue { + return LLVMBuildFree(llvm, ptr.asLLVM()) + } + // MARK: Aggregate Instructions /// Builds an instruction to insert a value into a member field in an diff --git a/Tests/LLVMTests/IRBuilderSpec.swift b/Tests/LLVMTests/IRBuilderSpec.swift index 53d06871..74bb6a11 100644 --- a/Tests/LLVMTests/IRBuilderSpec.swift +++ b/Tests/LLVMTests/IRBuilderSpec.swift @@ -259,6 +259,7 @@ class IRBuilderSpec : XCTestCase { let module = Module(name: "IRBuilderTest") let builder = IRBuilder(module: module) + // CAST: define i32 @main() { let main = builder.addFunction("main", type: FunctionType(argTypes: [], From 6afe92fa2699a9e3ec8f85b6c9d7b8535eb01501 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Mon, 30 Jan 2017 18:59:15 -0500 Subject: [PATCH 2/3] Added tests for FPCast --- Tests/LLVMTests/IRBuilderSpec.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Tests/LLVMTests/IRBuilderSpec.swift b/Tests/LLVMTests/IRBuilderSpec.swift index 74bb6a11..8ac17dea 100644 --- a/Tests/LLVMTests/IRBuilderSpec.swift +++ b/Tests/LLVMTests/IRBuilderSpec.swift @@ -253,6 +253,8 @@ class IRBuilderSpec : XCTestCase { module.dump() }) + // MARK: Cast Instructions + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["CAST"]) { // CAST: ; ModuleID = '[[ModuleName:IRBuilderTest]]' // CAST-NEXT: source_filename = "[[ModuleName]]" @@ -285,12 +287,28 @@ class IRBuilderSpec : XCTestCase { // CAST-NEXT: %4 = bitcast i64* %0 to i8* _ = builder.buildBitCast(alloca, type: PointerType.toVoid) + // CAST-NEXT: %5 = alloca double + let dblAlloca = builder.buildAlloca(type: FloatType.double) + + // CAST-NEXT: %6 = load double, double* %5 + let dblVal = builder.buildLoad(dblAlloca) + + // CAST-NEXT: %7 = fptrunc double %6 to float + let fltVal = builder.buildFPCast(dblVal, type: FloatType.float) + + // CAST-NEXT: %8 = fpext float %7 to double + _ = builder.buildFPCast(fltVal, type: FloatType.double) + // CAST-NEXT: ret i32 0 builder.buildRet(IntType.int32.constant(0)) // CAST-NEXT: } module.dump() + + print(module) }) + + // MARK: C Standard Library Instructions } #if !os(macOS) From 216af6807fef22a48179ce05e8afa165b3f0c9da Mon Sep 17 00:00:00 2001 From: Harlan Date: Wed, 1 Feb 2017 23:10:24 -0500 Subject: [PATCH 3/3] Remove errant print --- Tests/LLVMTests/IRBuilderSpec.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/LLVMTests/IRBuilderSpec.swift b/Tests/LLVMTests/IRBuilderSpec.swift index 8ac17dea..d2bde5de 100644 --- a/Tests/LLVMTests/IRBuilderSpec.swift +++ b/Tests/LLVMTests/IRBuilderSpec.swift @@ -304,8 +304,6 @@ class IRBuilderSpec : XCTestCase { // CAST-NEXT: } module.dump() - - print(module) }) // MARK: C Standard Library Instructions