Skip to content

Commit 79d16eb

Browse files
authored
Merge pull request #109 from CodaFi/const-vector
Constant Vector Operations
2 parents a2e8974 + ae221d0 commit 79d16eb

File tree

4 files changed

+181
-17
lines changed

4 files changed

+181
-17
lines changed

Sources/LLVM/Constant.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public enum Signed: IntegralConstantRepresentation {}
1717
public enum Floating: NumericalConstantRepresentation {}
1818
/// Represents struct types and operations.
1919
public enum Struct: ConstantRepresentation {}
20+
/// Represents vector types and operations.
21+
public enum Vector: ConstantRepresentation {}
2022

2123
/// A `Constant` represents a value initialized to a constant. Constant values
2224
/// may be manipulated with standard Swift arithmetic operations and used with
@@ -952,6 +954,27 @@ extension Constant where Repr == Struct {
952954
}
953955
}
954956

957+
// MARK: Vector Operations
958+
959+
extension Constant where Repr == Vector {
960+
/// Builds a constant operation to construct a permutation of elements
961+
/// from the two given input vectors, returning a vector with the same element
962+
/// type as the inputs and length that is the same as the shuffle mask.
963+
///
964+
/// - parameter vector1: The first constant vector to shuffle.
965+
/// - parameter vector2: The second constant vector to shuffle.
966+
/// - parameter mask: A constant vector of `i32` values that acts as a mask
967+
/// for the shuffled vectors.
968+
///
969+
/// - returns: A value representing a constant vector with the same element
970+
/// type as the inputs and length that is the same as the shuffle mask.
971+
public static func buildShuffleVector(_ vector1: Constant, and vector2: Constant, mask: Constant) -> Constant {
972+
guard let maskTy = mask.type as? VectorType, maskTy.elementType is IntType else {
973+
fatalError("Vector shuffle mask's elements must be 32-bit integers")
974+
}
975+
return Constant(llvm: LLVMConstShuffleVector(vector1.asLLVM(), vector2.asLLVM(), mask.asLLVM()))
976+
}
977+
}
955978

956979
// MARK: Swift Operators
957980

@@ -1384,3 +1407,49 @@ extension Constant where Repr: IntegralConstantRepresentation {
13841407
return Constant(llvm: LLVMConstNot(lhs.llvm))
13851408
}
13861409
}
1410+
1411+
// MARK: Undef
1412+
1413+
extension Constant where Repr: IntegralConstantRepresentation {
1414+
/// Returns the special LLVM `undef` value for this type.
1415+
///
1416+
/// The `undef` value can be used anywhere a constant is expected, and
1417+
/// indicates that the user of the value may receive an unspecified
1418+
/// bit-pattern.
1419+
public static func undef(_ ty: IntType) -> Constant {
1420+
return Constant<Repr>(llvm: ty.undef().asLLVM())
1421+
}
1422+
}
1423+
1424+
extension Constant where Repr == Floating {
1425+
/// Returns the special LLVM `undef` value for this type.
1426+
///
1427+
/// The `undef` value can be used anywhere a constant is expected, and
1428+
/// indicates that the user of the value may receive an unspecified
1429+
/// bit-pattern.
1430+
public static func undef(_ ty: FloatType) -> Constant {
1431+
return Constant(llvm: ty.undef().asLLVM())
1432+
}
1433+
}
1434+
1435+
extension Constant where Repr == Struct {
1436+
/// Returns the special LLVM `undef` value for this type.
1437+
///
1438+
/// The `undef` value can be used anywhere a constant is expected, and
1439+
/// indicates that the user of the value may receive an unspecified
1440+
/// bit-pattern.
1441+
public static func undef(_ ty: StructType) -> Constant {
1442+
return Constant(llvm: ty.undef().asLLVM())
1443+
}
1444+
}
1445+
1446+
extension Constant where Repr == Vector {
1447+
/// Returns the special LLVM `undef` value for this type.
1448+
///
1449+
/// The `undef` value can be used anywhere a constant is expected, and
1450+
/// indicates that the user of the value may receive an unspecified
1451+
/// bit-pattern.
1452+
public static func undef(_ ty: VectorType) -> Constant {
1453+
return Constant(llvm: ty.undef().asLLVM())
1454+
}
1455+
}

Sources/LLVM/VectorType.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,23 @@ public struct VectorType: IRType {
2222
self.count = count
2323
}
2424

25+
/// Creates a constant value of this vector type initialized with the given
26+
/// list of values.
27+
///
28+
/// - precondition: values.count == vector.count
29+
/// - parameter values: A list of values of elements of this vector.
30+
///
31+
/// - returns: A value representing a constant value of this vector type.
32+
public func constant(_ values: [IRValue]) -> Constant<Vector> {
33+
assert(numericCast(values.count) == LLVMGetVectorSize(asLLVM()),
34+
"The number of values must match the number of elements in the vector")
35+
var vals = values.map { $0.asLLVM() as Optional }
36+
return vals.withUnsafeMutableBufferPointer { buf in
37+
return Constant(llvm: LLVMConstVector(buf.baseAddress,
38+
UInt32(buf.count)))
39+
}
40+
}
41+
2542
/// Retrieves the underlying LLVM type object.
2643
public func asLLVM() -> LLVMTypeRef {
2744
return LLVMVectorType(elementType.asLLVM(), UInt32(count))

Tests/LLVMTests/ConstantSpec.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,62 @@ class ConstantSpec : XCTestCase {
138138
// STRUCTCONSTGETELEMENT-NEXT: }
139139
module.dump()
140140
})
141+
142+
XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["VECTORCONSTSHUFFLE-IDENTITY"]) {
143+
// VECTORCONSTSHUFFLE-IDENTITY: ; ModuleID = '[[ModuleName:ConstantTest]]'
144+
// VECTORCONSTSHUFFLE-IDENTITY-NEXT: source_filename = "[[ModuleName]]"
145+
let module = Module(name: "ConstantTest")
146+
let builder = IRBuilder(module: module)
147+
148+
let vecTy = VectorType(elementType: IntType.int32, count: 4)
149+
// VECTORCONSTSHUFFLE-IDENTITY: define <4 x i32> @main() {
150+
let main = builder.addFunction("main",
151+
type: FunctionType(argTypes: [],
152+
returnType: vecTy))
153+
154+
let vec1 = vecTy.constant([ 1, 2, 3, 4 ] as [Int32])
155+
let mask = vecTy.constant([ 0, 1, 2, 3 ] as [Int32])
156+
157+
// VECTORCONSTSHUFFLE-IDENTITY-NEXT: entry:
158+
let entry = main.appendBasicBlock(named: "entry")
159+
builder.positionAtEnd(of: entry)
160+
161+
let firstElement = Constant<Vector>.buildShuffleVector(vec1, and: .undef(vecTy), mask: mask)
162+
163+
// VECTORCONSTSHUFFLE-IDENTITY-NEXT: ret <4 x i32> <i32 1, i32 2, i32 3, i32 4>
164+
builder.buildRet(firstElement)
165+
// VECTORCONSTSHUFFLE-IDENTITY-NEXT: }
166+
module.dump()
167+
})
168+
169+
XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["VECTORCONSTSHUFFLE"]) {
170+
// VECTORCONSTSHUFFLE: ; ModuleID = '[[ModuleName:ConstantTest]]'
171+
// VECTORCONSTSHUFFLE-NEXT: source_filename = "[[ModuleName]]"
172+
let module = Module(name: "ConstantTest")
173+
let builder = IRBuilder(module: module)
174+
175+
let maskTy = VectorType(elementType: IntType.int32, count: 8)
176+
// VECTORCONSTSHUFFLE: define <8 x i32> @main() {
177+
let main = builder.addFunction("main",
178+
type: FunctionType(argTypes: [],
179+
returnType: maskTy))
180+
181+
let vecTy = VectorType(elementType: IntType.int32, count: 4)
182+
let vec1 = vecTy.constant([ 1, 2, 3, 4 ] as [Int32])
183+
let vec2 = vecTy.constant([ 5, 6, 7, 8 ] as [Int32])
184+
let mask = maskTy.constant([ 1, 3, 5, 7, 0, 2, 4, 6 ] as [Int32])
185+
186+
// VECTORCONSTSHUFFLE-NEXT: entry:
187+
let entry = main.appendBasicBlock(named: "entry")
188+
builder.positionAtEnd(of: entry)
189+
190+
let firstElement = Constant<Vector>.buildShuffleVector(vec1, and: vec2, mask: mask)
191+
192+
// VECTORCONSTSHUFFLE-NEXT: ret <8 x i32> <i32 2, i32 4, i32 6, i32 8, i32 1, i32 3, i32 5, i32 7>
193+
builder.buildRet(firstElement)
194+
// VECTORCONSTSHUFFLE-NEXT: }
195+
module.dump()
196+
})
141197
}
142198

143199
#if !os(macOS)

Tests/LLVMTests/IRBuilderSpec.swift

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class IRBuilderSpec : XCTestCase {
3838
var g2 = builder.addGlobal("b", type: IntType.int32)
3939
g2.initializer = Int32(1)
4040

41+
// IRBUILDERARITH-NEXT: @vec1 = global <8 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1>
42+
// IRBUILDERARITH-NEXT: @vec2 = global <8 x i64> <i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2>
43+
let vecTy = VectorType(elementType: IntType.int32, count: 8)
44+
let gVec1 = builder.addGlobal("vec1", initializer: vecTy.constant([ 1, 1, 1, 1, 1, 1, 1, 1 ]))
45+
let gVec2 = builder.addGlobal("vec2", initializer: vecTy.constant([ 2, 2, 2, 2, 2, 2, 2, 2 ]))
46+
4147
// IRBUILDERARITH: define void @main() {
4248
let main = builder.addFunction("main",
4349
type: FunctionType(argTypes: [],
@@ -46,44 +52,60 @@ class IRBuilderSpec : XCTestCase {
4652
let entry = main.appendBasicBlock(named: "entry")
4753
builder.positionAtEnd(of: entry)
4854

49-
// IRBUILDERARITH-NEXT: %0 = load i32, i32* @a
55+
// IRBUILDERARITH-NEXT: [[A_LOAD:%[0-9]+]] = load i32, i32* @a
5056
let vg1 = builder.buildLoad(g1)
51-
// IRBUILDERARITH-NEXT: %1 = load i32, i32* @b
57+
// IRBUILDERARITH-NEXT: [[B_LOAD:%[0-9]+]] = load i32, i32* @b
5258
let vg2 = builder.buildLoad(g2)
5359

54-
// IRBUILDERARITH-NEXT: %2 = add i32 %0, %1
60+
// IRBUILDERARITH-NEXT: [[VEC1_LOAD:%[0-9]+]] = load <8 x i64>, <8 x i64>* @vec1
61+
let vgVec1 = builder.buildLoad(gVec1)
62+
63+
// IRBUILDERARITH-NEXT: [[VEC2_LOAD:%[0-9]+]] = load <8 x i64>, <8 x i64>* @vec2
64+
let vgVec2 = builder.buildLoad(gVec2)
65+
66+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = add i32 [[A_LOAD]], [[B_LOAD]]
5567
_ = builder.buildAdd(vg1, vg2)
56-
// IRBUILDERARITH-NEXT: %3 = sub i32 %0, %1
68+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 [[A_LOAD]], [[B_LOAD]]
5769
_ = builder.buildSub(vg1, vg2)
58-
// IRBUILDERARITH-NEXT: %4 = mul i32 %0, %1
70+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul i32 [[A_LOAD]], [[B_LOAD]]
5971
_ = builder.buildMul(vg1, vg2)
60-
// IRBUILDERARITH-NEXT: %5 = sdiv i32 %0, %1
72+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sdiv i32 [[A_LOAD]], [[B_LOAD]]
6173
_ = builder.buildDiv(vg1, vg2, signed: true)
62-
// IRBUILDERARITH-NEXT: %6 = udiv i32 %0, %1
74+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = udiv i32 [[A_LOAD]], [[B_LOAD]]
6375
_ = builder.buildDiv(vg1, vg2, signed: false)
6476

65-
// IRBUILDERARITH-NEXT: %7 = add nsw i32 %0, %1
77+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = add nsw i32 [[A_LOAD]], [[B_LOAD]]
6678
_ = builder.buildAdd(vg1, vg2, overflowBehavior: .noSignedWrap)
67-
// IRBUILDERARITH-NEXT: %8 = sub nsw i32 %0, %1
79+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nsw i32 [[A_LOAD]], [[B_LOAD]]
6880
_ = builder.buildSub(vg1, vg2, overflowBehavior: .noSignedWrap)
69-
// IRBUILDERARITH-NEXT: %9 = mul nsw i32 %0, %1
81+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul nsw i32 [[A_LOAD]], [[B_LOAD]]
7082
_ = builder.buildMul(vg1, vg2, overflowBehavior: .noSignedWrap)
7183

72-
// IRBUILDERARITH-NEXT: %10 = add nuw i32 %0, %1
84+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = add nuw i32 [[A_LOAD]], [[B_LOAD]]
7385
_ = builder.buildAdd(vg1, vg2, overflowBehavior: .noUnsignedWrap)
74-
// IRBUILDERARITH-NEXT: %11 = sub nuw i32 %0, %1
86+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nuw i32 [[A_LOAD]], [[B_LOAD]]
7587
_ = builder.buildSub(vg1, vg2, overflowBehavior: .noUnsignedWrap)
76-
// IRBUILDERARITH-NEXT: %12 = mul nuw i32 %0, %1
88+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul nuw i32 [[A_LOAD]], [[B_LOAD]]
7789
_ = builder.buildMul(vg1, vg2, overflowBehavior: .noUnsignedWrap)
7890

79-
// IRBUILDERARITH-NEXT: %13 = sub i32 0, %0
91+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = add <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]]
92+
_ = builder.buildAdd(vgVec1, vgVec2)
93+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]]
94+
_ = builder.buildSub(vgVec1, vgVec2)
95+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = mul <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]]
96+
_ = builder.buildMul(vgVec1, vgVec2)
97+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sdiv <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]]
98+
_ = builder.buildDiv(vgVec1, vgVec2, signed: true)
99+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = udiv <8 x i64> [[VEC1_LOAD]], [[VEC2_LOAD]]
100+
_ = builder.buildDiv(vgVec1, vgVec2, signed: false)
101+
102+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub i32 0, [[A_LOAD]]
80103
_ = builder.buildNeg(vg1, overflowBehavior: .default)
81-
// IRBUILDERARITH-NEXT: %14 = sub nuw i32 0, %0
104+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nuw i32 0, [[A_LOAD]]
82105
_ = builder.buildNeg(vg1, overflowBehavior: .noUnsignedWrap)
83-
// IRBUILDERARITH-NEXT: %15 = sub nsw i32 0, %0
106+
// IRBUILDERARITH-NEXT: {{%[0-9]+}} = sub nsw i32 0, [[A_LOAD]]
84107
_ = builder.buildNeg(vg1, overflowBehavior: .noSignedWrap)
85108

86-
87109
// IRBUILDERARITH-NEXT: ret void
88110
builder.buildRetVoid()
89111
// IRBUILDERARITH-NEXT: }

0 commit comments

Comments
 (0)