From 4e9f1e7d98742ad464568ac1426294cc0bfc51f0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 3 Feb 2017 15:54:08 -0500 Subject: [PATCH] Add (constant) conditional operations --- Sources/LLVM/Constant.swift | 33 +++++++++++++++++++++++++++++++ Sources/LLVM/IRBuilder.swift | 38 +++++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Sources/LLVM/Constant.swift b/Sources/LLVM/Constant.swift index 16635725..a1f7e26f 100644 --- a/Sources/LLVM/Constant.swift +++ b/Sources/LLVM/Constant.swift @@ -487,4 +487,37 @@ extension Constant where Repr: IntegralConstantRepresentation { return Constant(llvm: LLVMConstXor(lhs.llvm, rhs.llvm)) } + + // MARK: Bitshifting Operations + + /// A constant left-shift of the first value by the second amount. + /// + /// - parameter lhs: The first operand. + /// - parameter rhs: The second operand. + /// + /// - returns: A constant value representing the value of the first operand + /// shifted left by the number of bits specified in the second operand. + public static func <<(lhs: Constant, rhs: Constant) -> Constant { + precondition(lhs.repr == rhs.repr, "Mixed-representation constant operations are disallowed") + + return Constant(llvm: LLVMConstShl(lhs.llvm, rhs.llvm)) + } + + + // MARK: Conditional Operations + + /// A constant select using the given condition to select among two values. + /// + /// - parameter cond: The condition to evaluate. It must have type `i1` or + /// be a vector of `i1`. + /// - parameter then: The value to select if the given condition is true. + /// - parameter else: The value to select if the given condition is false. + /// + /// - returns: A constant value representing the constant value selected for + /// by the condition. + public static func select(_ cond: Constant, then: Constant, else: Constant) -> Constant { + precondition(then.repr == `else`.repr, "Mixed-representation constant operations are disallowed") + + return Constant(llvm: LLVMConstSelect(cond.llvm, then.llvm, `else`.llvm)) + } } diff --git a/Sources/LLVM/IRBuilder.swift b/Sources/LLVM/IRBuilder.swift index aca196ef..a8ba41b2 100644 --- a/Sources/LLVM/IRBuilder.swift +++ b/Sources/LLVM/IRBuilder.swift @@ -746,7 +746,7 @@ public class IRBuilder { } } - // MARK: Declaration Instructions + // MARK: Conditional Instructions /// Build a phi node with the given type acting as the result of any incoming /// basic blocks. @@ -760,14 +760,26 @@ public class IRBuilder { return PhiNode(llvm: value) } - /// Build a named function body with the given type. + /// Build a select instruction to choose a value based on a condition without + /// IR-level branching. /// - /// - parameter name: The name of the newly defined function. - /// - parameter type: The type of the newly defined function. + /// - parameter cond: The condition to evaluate. It must have type `i1` or + /// be a vector of `i1`. + /// - parameter then: The value to select if the given condition is true. + /// - parameter else: The value to select if the given condition is false. + /// - parameter name: The name for the newly inserted instruction. /// - /// - returns: A value representing the newly inserted function definition. - public func addFunction(_ name: String, type: FunctionType) -> Function { - return Function(llvm: LLVMAddFunction(module.llvm, name, type.asLLVM())) + /// - returns: A value representing the value selected for by the condition. + public func buildSelect(_ cond: IRValue, then: IRValue, else: IRValue, name: String = "") -> IRValue { + if let ty = cond.type as? IntType { + precondition(ty.width == 1, "Switch statement condition must have bitwidth of 1, instead has bitwidth of \(ty.width)") + return LLVMBuildSelect(llvm, cond.asLLVM(), then.asLLVM(), `else`.asLLVM(), name) + } else if let ty = cond.type as? VectorType, let intTy = ty.elementType as? IntType { + precondition(intTy.width == 1, "Switch statement condition must have bitwidth of 1, instead has bitwidth of \(intTy.width)") + return LLVMBuildSelect(llvm, cond.asLLVM(), then.asLLVM(), `else`.asLLVM(), name) + } else { + fatalError("Condition must have type i1 or ") + } } /// Build a branch table that branches on the given value with the given @@ -790,6 +802,18 @@ public class IRBuilder { UInt32(caseCount))!) } + // MARK: Declaration Instructions + + /// 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(module.llvm, name, type.asLLVM())) + } + /// Build a named structure definition. /// /// - parameter name: The name of the structure.