summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorAmara Emerson <aemerson@apple.com>2018-12-05 23:53:30 +0000
committerAmara Emerson <aemerson@apple.com>2018-12-05 23:53:30 +0000
commita0b15d8f3e61d7f47810c07fea56ecc88fccd2d0 (patch)
tree80dd6f1ae63500ee055ac96fe69d0e7d01f0cd66 /llvm
parent8adc72d176bb51974b973ce17f50d510277cb1e5 (diff)
downloadbcm5719-llvm-a0b15d8f3e61d7f47810c07fea56ecc88fccd2d0.tar.gz
bcm5719-llvm-a0b15d8f3e61d7f47810c07fea56ecc88fccd2d0.zip
[GlobalISel] Introduce G_BUILD_VECTOR, G_BUILD_VECTOR_TRUNC and G_CONCAT_VECTOR opcodes.
These opcodes are intended to subsume some of the capability of G_MERGE_VALUES, as it was too powerful and thus complex to add deal with throughout the GISel pipeline. G_BUILD_VECTOR creates a vector value from a sequence of uniformly typed scalar values. G_BUILD_VECTOR_TRUNC is a special opcode for handling scalar operands which are larger than the destination vector element type, and therefore does an implicit truncate. G_CONCAT_VECTOR creates a vector by concatenating smaller, uniformly typed, vectors together. These will be used in a subsequent commit. This commit just adds the initial infrastructure. Differential Revision: https://reviews.llvm.org/D53594 llvm-svn: 348430
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h40
-rw-r--r--llvm/include/llvm/Support/TargetOpcodes.def11
-rw-r--r--llvm/include/llvm/Target/GenericOpcodes.td22
-rw-r--r--llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp58
-rw-r--r--llvm/lib/CodeGen/MachineVerifier.cpp57
-rw-r--r--llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir9
-rw-r--r--llvm/test/Verifier/gisel-g_build_vector.mir27
-rw-r--r--llvm/test/Verifier/gisel-g_build_vector_trunc.mir27
-rw-r--r--llvm/test/Verifier/gisel-g_concat_vector.mir29
9 files changed, 280 insertions, 0 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index 802e0c99f3c..965c6b9b61c 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -603,6 +603,46 @@ public:
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildUnmerge(ArrayRef<unsigned> Res, unsigned Op);
+ /// Build and insert \p Res = G_BUILD_VECTOR \p Op0, ...
+ ///
+ /// G_BUILD_VECTOR creates a vector value from multiple scalar registers.
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre The entire register \p Res (and no more) must be covered by the
+ /// input scalar registers.
+ /// \pre The type of all \p Ops registers must be identical.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildBuildVector(unsigned Res, ArrayRef<unsigned> Ops);
+
+ /// Build and insert \p Res = G_BUILD_VECTOR_TRUNC \p Op0, ...
+ ///
+ /// G_BUILD_VECTOR_TRUNC creates a vector value from multiple scalar registers
+ /// which have types larger than the destination vector element type, and
+ /// truncates the values to fit.
+ ///
+ /// If the operands given are already the same size as the vector elt type,
+ /// then this method will instead create a G_BUILD_VECTOR instruction.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre The type of all \p Ops registers must be identical.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildBuildVectorTrunc(unsigned Res,
+ ArrayRef<unsigned> Ops);
+
+ /// Build and insert \p Res = G_CONCAT_VECTORS \p Op0, ...
+ ///
+ /// G_CONCAT_VECTORS creates a vector from the concatenation of 2 or more
+ /// vectors.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre The entire register \p Res (and no more) must be covered by the input
+ /// registers.
+ /// \pre The type of all source operands must be identical.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildConcatVectors(unsigned Res, ArrayRef<unsigned> Ops);
+
MachineInstrBuilder buildInsert(unsigned Res, unsigned Src,
unsigned Op, unsigned Index);
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index a683f053e03..5bf2a7f22db 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -258,6 +258,17 @@ HANDLE_TARGET_OPCODE(G_INSERT)
/// larger register.
HANDLE_TARGET_OPCODE(G_MERGE_VALUES)
+/// Generic instruction to create a vector value from a number of scalar
+/// components.
+HANDLE_TARGET_OPCODE(G_BUILD_VECTOR)
+
+/// Generic instruction to create a vector value from a number of scalar
+/// components, which have types larger than the result vector elt type.
+HANDLE_TARGET_OPCODE(G_BUILD_VECTOR_TRUNC)
+
+/// Generic instruction to create a vector by concatenating multiple vectors.
+HANDLE_TARGET_OPCODE(G_CONCAT_VECTORS)
+
/// Generic pointer to int conversion.
HANDLE_TARGET_OPCODE(G_PTRTOINT)
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index af4fa8a1f04..ae3176c0e62 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -675,6 +675,28 @@ def G_MERGE_VALUES : GenericInstruction {
let hasSideEffects = 0;
}
+/// Create a vector from multiple scalar registers.
+def G_BUILD_VECTOR : GenericInstruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins type1:$src0, variable_ops);
+ let hasSideEffects = 0;
+}
+
+/// Like G_BUILD_VECTOR, but truncates the larger operand types to fit the
+/// destination vector elt type.
+def G_BUILD_VECTOR_TRUNC : GenericInstruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins type1:$src0, variable_ops);
+ let hasSideEffects = 0;
+}
+
+/// Create a vector by concatenating vectors together.
+def G_CONCAT_VECTORS : GenericInstruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins type1:$src0, variable_ops);
+ let hasSideEffects = 0;
+}
+
// Intrinsic without side effects.
def G_INTRINSIC : GenericInstruction {
let OutOperandList = (outs);
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 9f9964078ea..54e007da5f4 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -519,6 +519,64 @@ MachineInstrBuilder MachineIRBuilderBase::buildUnmerge(ArrayRef<unsigned> Res,
return MIB;
}
+MachineInstrBuilder
+MachineIRBuilderBase::buildBuildVector(unsigned Res, ArrayRef<unsigned> Ops) {
+#ifndef NDEBUG
+ assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+ assert(getMRI()->getType(Res).isVector() && "Res type must be a vector");
+ LLT Ty = getMRI()->getType(Ops[0]);
+ for (auto Reg : Ops)
+ assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+ assert(Ops.size() * Ty.getSizeInBits() ==
+ getMRI()->getType(Res).getSizeInBits() &&
+ "input scalars do not exactly cover the outpur vector register");
+#endif
+ MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR);
+ MIB.addDef(Res);
+ for (auto Op : Ops)
+ MIB.addUse(Op);
+ return MIB;
+}
+
+MachineInstrBuilder
+MachineIRBuilderBase::buildBuildVectorTrunc(unsigned Res,
+ ArrayRef<unsigned> Ops) {
+#ifndef NDEBUG
+ assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+ LLT Ty = getMRI()->getType(Ops[0]);
+ for (auto Reg : Ops)
+ assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+#endif
+ if (getMRI()->getType(Ops[0]).getSizeInBits() ==
+ getMRI()->getType(Res).getElementType().getSizeInBits())
+ return buildBuildVector(Res, Ops);
+ MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR_TRUNC);
+ MIB.addDef(Res);
+ for (auto Op : Ops)
+ MIB.addUse(Op);
+ return MIB;
+}
+
+MachineInstrBuilder
+MachineIRBuilderBase::buildConcatVectors(unsigned Res, ArrayRef<unsigned> Ops) {
+ #ifndef NDEBUG
+ assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+ LLT Ty = getMRI()->getType(Ops[0]);
+ for (auto Reg : Ops) {
+ assert(getMRI()->getType(Reg).isVector() && "expected vector operand");
+ assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+ }
+ assert(Ops.size() * Ty.getSizeInBits() ==
+ getMRI()->getType(Res).getSizeInBits() &&
+ "input vectors do not exactly cover the outpur vector register");
+ #endif
+ MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_CONCAT_VECTORS);
+ MIB.addDef(Res);
+ for (auto Op : Ops)
+ MIB.addUse(Op);
+ return MIB;
+}
+
MachineInstrBuilder MachineIRBuilderBase::buildInsert(unsigned Res,
unsigned Src, unsigned Op,
unsigned Index) {
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index b37c421596b..7970dff1eca 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1055,6 +1055,63 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
}
break;
}
+ case TargetOpcode::G_BUILD_VECTOR: {
+ // Source types must be scalars, dest type a vector. Total size of scalars
+ // must match the dest vector size.
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!DstTy.isVector() || SrcEltTy.isVector())
+ report("G_BUILD_VECTOR must produce a vector from scalar operands", MI);
+ for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+ if (MRI->getType(MI->getOperand(1).getReg()) !=
+ MRI->getType(MI->getOperand(i).getReg()))
+ report("G_BUILD_VECTOR source operand types are not homogeneous", MI);
+ }
+ if (DstTy.getSizeInBits() !=
+ SrcEltTy.getSizeInBits() * (MI->getNumOperands() - 1))
+ report("G_BUILD_VECTOR src operands total size don't match dest "
+ "size.",
+ MI);
+ break;
+ }
+ case TargetOpcode::G_BUILD_VECTOR_TRUNC: {
+ // Source types must be scalars, dest type a vector. Scalar types must be
+ // larger than the dest vector elt type, as this is a truncating operation.
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!DstTy.isVector() || SrcEltTy.isVector())
+ report("G_BUILD_VECTOR_TRUNC must produce a vector from scalar operands",
+ MI);
+ for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+ if (MRI->getType(MI->getOperand(1).getReg()) !=
+ MRI->getType(MI->getOperand(i).getReg()))
+ report("G_BUILD_VECTOR_TRUNC source operand types are not homogeneous",
+ MI);
+ }
+ if (SrcEltTy.getSizeInBits() <= DstTy.getElementType().getSizeInBits())
+ report("G_BUILD_VECTOR_TRUNC source operand types are not larger than "
+ "dest elt type",
+ MI);
+ break;
+ }
+ case TargetOpcode::G_CONCAT_VECTORS: {
+ // Source types should be vectors, and total size should match the dest
+ // vector size.
+ LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+ LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+ if (!DstTy.isVector() || !SrcTy.isVector())
+ report("G_CONCAT_VECTOR requires vector source and destination operands",
+ MI);
+ for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+ if (MRI->getType(MI->getOperand(1).getReg()) !=
+ MRI->getType(MI->getOperand(i).getReg()))
+ report("G_CONCAT_VECTOR source operand types are not homogeneous", MI);
+ }
+ if (DstTy.getNumElements() !=
+ SrcTy.getNumElements() * (MI->getNumOperands() - 1))
+ report("G_CONCAT_VECTOR num dest and source elements should match", MI);
+ break;
+ }
case TargetOpcode::COPY: {
if (foundErrors)
break;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index ca059cf1544..1bdd0f1b82a 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -69,6 +69,15 @@
# DEBUG-NEXT: G_MERGE_VALUES (opcode {{[0-9]+}}): 2 type indices
# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected
#
+# DEBUG-NEXT: G_BUILD_VECTOR (opcode {{[0-9]+}}): 2 type indices
+# DEBUG: .. type index coverage check SKIPPED: no rules defined
+#
+# DEBUG-NEXT: G_BUILD_VECTOR_TRUNC (opcode {{[0-9]+}}): 2 type indices
+# DEBUG: .. type index coverage check SKIPPED: no rules defined
+#
+# DEBUG-NEXT: G_CONCAT_VECTORS (opcode {{[0-9]+}}): 2 type indices
+# DEBUG: .. type index coverage check SKIPPED: no rules defined
+#
# DEBUG-NEXT: G_PTRTOINT (opcode {{[0-9]+}}): 2 type indices
# DEBUG: .. the first uncovered type index: 2, OK
#
diff --git a/llvm/test/Verifier/gisel-g_build_vector.mir b/llvm/test/Verifier/gisel-g_build_vector.mir
new file mode 100644
index 00000000000..a40942ef47b
--- /dev/null
+++ b/llvm/test/Verifier/gisel-g_build_vector.mir
@@ -0,0 +1,27 @@
+#RUN: not llc -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: global-isel, aarch64-registered-target
+--- |
+ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+ target triple = "aarch64-unknown-unknown"
+
+ define i32 @g_build_vector() {
+ ret i32 0
+ }
+
+...
+---
+name: g_build_vector
+legalized: true
+regBankSelected: false
+selected: false
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: _, preferred-register: '' }
+liveins:
+body: |
+ bb.0:
+ ; CHECK: Bad machine code: G_BUILD_VECTOR src operands total size don't match dest size
+
+ %0(s32) = IMPLICIT_DEF
+ %1:_(<2 x s32>) = G_BUILD_VECTOR %0, %0, %0, %0
+...
diff --git a/llvm/test/Verifier/gisel-g_build_vector_trunc.mir b/llvm/test/Verifier/gisel-g_build_vector_trunc.mir
new file mode 100644
index 00000000000..3b9b304b667
--- /dev/null
+++ b/llvm/test/Verifier/gisel-g_build_vector_trunc.mir
@@ -0,0 +1,27 @@
+#RUN: not llc -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: global-isel, aarch64-registered-target
+--- |
+ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+ target triple = "aarch64-unknown-unknown"
+
+ define i32 @g_build_vector_trunc() {
+ ret i32 0
+ }
+
+...
+---
+name: g_build_vector_trunc
+legalized: true
+regBankSelected: false
+selected: false
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: _, preferred-register: '' }
+liveins:
+body: |
+ bb.0:
+ ; CHECK: Bad machine code: G_BUILD_VECTOR_TRUNC source operand types are not larger than dest elt type
+
+ %0(s32) = IMPLICIT_DEF
+ %1:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %0, %0
+...
diff --git a/llvm/test/Verifier/gisel-g_concat_vector.mir b/llvm/test/Verifier/gisel-g_concat_vector.mir
new file mode 100644
index 00000000000..640c4a4ceed
--- /dev/null
+++ b/llvm/test/Verifier/gisel-g_concat_vector.mir
@@ -0,0 +1,29 @@
+#RUN: not llc -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: global-isel, aarch64-registered-target
+--- |
+ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+ target triple = "aarch64-unknown-unknown"
+
+ define i32 @g_concat_vectors() {
+ ret i32 0
+ }
+
+...
+---
+name: g_concat_vectors
+legalized: true
+regBankSelected: false
+selected: false
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: _, preferred-register: '' }
+ - { id: 1, class: _, preferred-register: '' }
+liveins:
+body: |
+ bb.0:
+ ; CHECK: Bad machine code: G_CONCAT_VECTOR num dest and source elements should match
+
+ %0(<2 x s32>) = IMPLICIT_DEF
+ %1(<2 x s32>) = IMPLICIT_DEF
+ %2:_(<2 x s32>) = G_CONCAT_VECTORS %0, %1
+...
OpenPOWER on IntegriCloud