From bbed74b0d6ea0d4b743be84619b0bd4b10d32371 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 27 Sep 2017 17:38:52 -0400 Subject: [PATCH 1/3] Use FileCheck to ignore SSA vals --- Tests/LLVMTests/IRBuilderSpec.swift | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Tests/LLVMTests/IRBuilderSpec.swift b/Tests/LLVMTests/IRBuilderSpec.swift index fb920478..7da2f642 100644 --- a/Tests/LLVMTests/IRBuilderSpec.swift +++ b/Tests/LLVMTests/IRBuilderSpec.swift @@ -46,44 +46,43 @@ class IRBuilderSpec : XCTestCase { let entry = main.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entry) - // IRBUILDERARITH-NEXT: %0 = load i32, i32* @a + // IRBUILDERARITH-NEXT: [[A_LOAD:%[0-9]+]] = load i32, i32* @a let vg1 = builder.buildLoad(g1) - // IRBUILDERARITH-NEXT: %1 = load i32, i32* @b + // IRBUILDERARITH-NEXT: [[B_LOAD:%[0-9]+]] = load i32, i32* @b let vg2 = builder.buildLoad(g2) - // IRBUILDERARITH-NEXT: %2 = add i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = add i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildAdd(vg1, vg2) - // IRBUILDERARITH-NEXT: %3 = sub i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildSub(vg1, vg2) - // IRBUILDERARITH-NEXT: %4 = mul i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildMul(vg1, vg2) - // IRBUILDERARITH-NEXT: %5 = sdiv i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sdiv i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildDiv(vg1, vg2, signed: true) - // IRBUILDERARITH-NEXT: %6 = udiv i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = udiv i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildDiv(vg1, vg2, signed: false) - // IRBUILDERARITH-NEXT: %7 = add nsw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = add nsw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildAdd(vg1, vg2, overflowBehavior: .noSignedWrap) - // IRBUILDERARITH-NEXT: %8 = sub nsw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nsw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildSub(vg1, vg2, overflowBehavior: .noSignedWrap) - // IRBUILDERARITH-NEXT: %9 = mul nsw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul nsw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildMul(vg1, vg2, overflowBehavior: .noSignedWrap) - // IRBUILDERARITH-NEXT: %10 = add nuw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = add nuw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildAdd(vg1, vg2, overflowBehavior: .noUnsignedWrap) - // IRBUILDERARITH-NEXT: %11 = sub nuw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nuw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildSub(vg1, vg2, overflowBehavior: .noUnsignedWrap) - // IRBUILDERARITH-NEXT: %12 = mul nuw i32 %0, %1 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul nuw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildMul(vg1, vg2, overflowBehavior: .noUnsignedWrap) - // IRBUILDERARITH-NEXT: %13 = sub i32 0, %0 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 0, [[A_LOAD]] _ = builder.buildNeg(vg1, overflowBehavior: .default) - // IRBUILDERARITH-NEXT: %14 = sub nuw i32 0, %0 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nuw i32 0, [[A_LOAD]] _ = builder.buildNeg(vg1, overflowBehavior: .noUnsignedWrap) - // IRBUILDERARITH-NEXT: %15 = sub nsw i32 0, %0 + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nsw i32 0, [[A_LOAD]] _ = builder.buildNeg(vg1, overflowBehavior: .noSignedWrap) - // IRBUILDERARITH-NEXT: ret void builder.buildRetVoid() // IRBUILDERARITH-NEXT: } From aba6dabdcb00252fc441811972063fa4ecc98f1f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 27 Sep 2017 18:18:50 -0400 Subject: [PATCH 2/3] Add Undef constant values --- Sources/LLVM/Constant.swift | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/Sources/LLVM/Constant.swift b/Sources/LLVM/Constant.swift index cfc5e08b..40329495 100644 --- a/Sources/LLVM/Constant.swift +++ b/Sources/LLVM/Constant.swift @@ -17,6 +17,8 @@ public enum Signed: IntegralConstantRepresentation {} public enum Floating: NumericalConstantRepresentation {} /// Represents struct types and operations. public enum Struct: ConstantRepresentation {} +/// Represents vector types and operations. +public enum Vector: ConstantRepresentation {} /// A `Constant` represents a value initialized to a constant. Constant values /// may be manipulated with standard Swift arithmetic operations and used with @@ -952,6 +954,27 @@ extension Constant where Repr == Struct { } } +// MARK: Vector Operations + +extension Constant where Repr == Vector { + /// Builds a constant operation to construct a permutation of elements + /// from the two given input vectors, returning a vector with the same element + /// type as the inputs and length that is the same as the shuffle mask. + /// + /// - parameter vector1: The first constant vector to shuffle. + /// - parameter vector2: The second constant vector to shuffle. + /// - parameter mask: A constant vector of `i32` values that acts as a mask + /// for the shuffled vectors. + /// + /// - returns: A value representing a constant vector with the same element + /// type as the inputs and length that is the same as the shuffle mask. + public static func buildShuffleVector(_ vector1: Constant, and vector2: Constant, mask: Constant) -> Constant { + guard let maskTy = mask.type as? VectorType, maskTy.elementType is IntType else { + fatalError("Vector shuffle mask's elements must be 32-bit integers") + } + return Constant(llvm: LLVMConstShuffleVector(vector1.asLLVM(), vector2.asLLVM(), mask.asLLVM())) + } +} // MARK: Swift Operators @@ -1384,3 +1407,49 @@ extension Constant where Repr: IntegralConstantRepresentation { return Constant(llvm: LLVMConstNot(lhs.llvm)) } } + +// MARK: Undef + +extension Constant where Repr: IntegralConstantRepresentation { + /// Returns the special LLVM `undef` value for this type. + /// + /// The `undef` value can be used anywhere a constant is expected, and + /// indicates that the user of the value may receive an unspecified + /// bit-pattern. + public static func undef(_ ty: IntType) -> Constant { + return Constant(llvm: ty.undef().asLLVM()) + } +} + +extension Constant where Repr == Floating { + /// Returns the special LLVM `undef` value for this type. + /// + /// The `undef` value can be used anywhere a constant is expected, and + /// indicates that the user of the value may receive an unspecified + /// bit-pattern. + public static func undef(_ ty: FloatType) -> Constant { + return Constant(llvm: ty.undef().asLLVM()) + } +} + +extension Constant where Repr == Struct { + /// Returns the special LLVM `undef` value for this type. + /// + /// The `undef` value can be used anywhere a constant is expected, and + /// indicates that the user of the value may receive an unspecified + /// bit-pattern. + public static func undef(_ ty: StructType) -> Constant { + return Constant(llvm: ty.undef().asLLVM()) + } +} + +extension Constant where Repr == Vector { + /// Returns the special LLVM `undef` value for this type. + /// + /// The `undef` value can be used anywhere a constant is expected, and + /// indicates that the user of the value may receive an unspecified + /// bit-pattern. + public static func undef(_ ty: VectorType) -> Constant { + return Constant(llvm: ty.undef().asLLVM()) + } +} From ae221d036020d1424bd35b6cf6141464d92001c6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 27 Sep 2017 18:19:10 -0400 Subject: [PATCH 3/3] Add Vector constant values and constant shuffling --- Sources/LLVM/VectorType.swift | 17 +++++++++ Tests/LLVMTests/ConstantSpec.swift | 56 +++++++++++++++++++++++++++++ Tests/LLVMTests/IRBuilderSpec.swift | 23 ++++++++++++ 3 files changed, 96 insertions(+) diff --git a/Sources/LLVM/VectorType.swift b/Sources/LLVM/VectorType.swift index c7cfeb94..88960e3c 100644 --- a/Sources/LLVM/VectorType.swift +++ b/Sources/LLVM/VectorType.swift @@ -22,6 +22,23 @@ public struct VectorType: IRType { self.count = count } + /// Creates a constant value of this vector type initialized with the given + /// list of values. + /// + /// - precondition: values.count == vector.count + /// - parameter values: A list of values of elements of this vector. + /// + /// - returns: A value representing a constant value of this vector type. + public func constant(_ values: [IRValue]) -> Constant { + assert(numericCast(values.count) == LLVMGetVectorSize(asLLVM()), + "The number of values must match the number of elements in the vector") + var vals = values.map { $0.asLLVM() as Optional } + return vals.withUnsafeMutableBufferPointer { buf in + return Constant(llvm: LLVMConstVector(buf.baseAddress, + UInt32(buf.count))) + } + } + /// Retrieves the underlying LLVM type object. public func asLLVM() -> LLVMTypeRef { return LLVMVectorType(elementType.asLLVM(), UInt32(count)) diff --git a/Tests/LLVMTests/ConstantSpec.swift b/Tests/LLVMTests/ConstantSpec.swift index c8528118..f586b9c0 100644 --- a/Tests/LLVMTests/ConstantSpec.swift +++ b/Tests/LLVMTests/ConstantSpec.swift @@ -138,6 +138,62 @@ class ConstantSpec : XCTestCase { // STRUCTCONSTGETELEMENT-NEXT: } module.dump() }) + + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["VECTORCONSTSHUFFLE-IDENTITY"]) { + // VECTORCONSTSHUFFLE-IDENTITY: ; ModuleID = '[[ModuleName:ConstantTest]]' + // VECTORCONSTSHUFFLE-IDENTITY-NEXT: source_filename = "[[ModuleName]]" + let module = Module(name: "ConstantTest") + let builder = IRBuilder(module: module) + + let vecTy = VectorType(elementType: IntType.int32, count: 4) + // VECTORCONSTSHUFFLE-IDENTITY: define <4 x i32> @main() { + let main = builder.addFunction("main", + type: FunctionType(argTypes: [], + returnType: vecTy)) + + let vec1 = vecTy.constant([ 1, 2, 3, 4 ] as [Int32]) + let mask = vecTy.constant([ 0, 1, 2, 3 ] as [Int32]) + + // VECTORCONSTSHUFFLE-IDENTITY-NEXT: entry: + let entry = main.appendBasicBlock(named: "entry") + builder.positionAtEnd(of: entry) + + let firstElement = Constant.buildShuffleVector(vec1, and: .undef(vecTy), mask: mask) + + // VECTORCONSTSHUFFLE-IDENTITY-NEXT: ret <4 x i32> + builder.buildRet(firstElement) + // VECTORCONSTSHUFFLE-IDENTITY-NEXT: } + module.dump() + }) + + XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["VECTORCONSTSHUFFLE"]) { + // VECTORCONSTSHUFFLE: ; ModuleID = '[[ModuleName:ConstantTest]]' + // VECTORCONSTSHUFFLE-NEXT: source_filename = "[[ModuleName]]" + let module = Module(name: "ConstantTest") + let builder = IRBuilder(module: module) + + let maskTy = VectorType(elementType: IntType.int32, count: 8) + // VECTORCONSTSHUFFLE: define <8 x i32> @main() { + let main = builder.addFunction("main", + type: FunctionType(argTypes: [], + returnType: maskTy)) + + let vecTy = VectorType(elementType: IntType.int32, count: 4) + let vec1 = vecTy.constant([ 1, 2, 3, 4 ] as [Int32]) + let vec2 = vecTy.constant([ 5, 6, 7, 8 ] as [Int32]) + let mask = maskTy.constant([ 1, 3, 5, 7, 0, 2, 4, 6 ] as [Int32]) + + // VECTORCONSTSHUFFLE-NEXT: entry: + let entry = main.appendBasicBlock(named: "entry") + builder.positionAtEnd(of: entry) + + let firstElement = Constant.buildShuffleVector(vec1, and: vec2, mask: mask) + + // VECTORCONSTSHUFFLE-NEXT: ret <8 x i32> + builder.buildRet(firstElement) + // VECTORCONSTSHUFFLE-NEXT: } + module.dump() + }) } #if !os(macOS) diff --git a/Tests/LLVMTests/IRBuilderSpec.swift b/Tests/LLVMTests/IRBuilderSpec.swift index 7da2f642..9496e6a7 100644 --- a/Tests/LLVMTests/IRBuilderSpec.swift +++ b/Tests/LLVMTests/IRBuilderSpec.swift @@ -38,6 +38,12 @@ class IRBuilderSpec : XCTestCase { var g2 = builder.addGlobal("b", type: IntType.int32) g2.initializer = Int32(1) + // IRBUILDERARITH-NEXT: @vec1 = global <8 x i64> + // IRBUILDERARITH-NEXT: @vec2 = global <8 x i64> + let vecTy = VectorType(elementType: IntType.int32, count: 8) + let gVec1 = builder.addGlobal("vec1", initializer: vecTy.constant([ 1, 1, 1, 1, 1, 1, 1, 1 ])) + let gVec2 = builder.addGlobal("vec2", initializer: vecTy.constant([ 2, 2, 2, 2, 2, 2, 2, 2 ])) + // IRBUILDERARITH: define void @main() { let main = builder.addFunction("main", type: FunctionType(argTypes: [], @@ -51,6 +57,12 @@ class IRBuilderSpec : XCTestCase { // IRBUILDERARITH-NEXT: [[B_LOAD:%[0-9]+]] = load i32, i32* @b let vg2 = builder.buildLoad(g2) + // IRBUILDERARITH-NEXT: [[VEC1_LOAD:%[0-9]+]] = load <8 x i64>, <8 x i64>* @vec1 + let vgVec1 = builder.buildLoad(gVec1) + + // IRBUILDERARITH-NEXT: [[VEC2_LOAD:%[0-9]+]] = load <8 x i64>, <8 x i64>* @vec2 + let vgVec2 = builder.buildLoad(gVec2) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = add i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildAdd(vg1, vg2) // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 [[A_LOAD]], [[B_LOAD]] @@ -76,6 +88,17 @@ class IRBuilderSpec : XCTestCase { // IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul nuw i32 [[A_LOAD]], [[B_LOAD]] _ = builder.buildMul(vg1, vg2, overflowBehavior: .noUnsignedWrap) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = add <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]] + _ = builder.buildAdd(vgVec1, vgVec2) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]] + _ = builder.buildSub(vgVec1, vgVec2) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]] + _ = builder.buildMul(vgVec1, vgVec2) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sdiv <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]] + _ = builder.buildDiv(vgVec1, vgVec2, signed: true) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = udiv <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]] + _ = builder.buildDiv(vgVec1, vgVec2, signed: false) + // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 0, [[A_LOAD]] _ = builder.buildNeg(vg1, overflowBehavior: .default) // IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nuw i32 0, [[A_LOAD]]