SpirvShader: Implement OpTranspose

Bug: b/126873455
Tests: dEQP-VK.glsl.matrix.transpose.*
Change-Id: I5b793ecda3d30de456b9ec7f65c386975a86b97f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28470
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 80ac8ed..553633c 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -362,6 +362,7 @@
 			case spv::OpVectorTimesMatrix:
 			case spv::OpMatrixTimesMatrix:
 			case spv::OpOuterProduct:
+			case spv::OpTranspose:
 			case spv::OpVectorExtractDynamic:
 			case spv::OpVectorInsertDynamic:
 			case spv::OpNot: // Unary ops
@@ -1627,6 +1628,9 @@
 		case spv::OpOuterProduct:
 			return EmitOuterProduct(insn, state);
 
+		case spv::OpTranspose:
+			return EmitTranspose(insn, state);
+
 		case spv::OpNot:
 		case spv::OpSNegate:
 		case spv::OpFNegate:
@@ -2291,6 +2295,27 @@
 		return EmitResult::Continue;
 	}
 
+	SpirvShader::EmitResult SpirvShader::EmitTranspose(InsnIterator insn, EmitState *state) const
+	{
+		auto routine = state->routine;
+		auto &type = getType(insn.word(1));
+		auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
+		auto mat = GenericValue(this, routine, insn.word(3));
+
+		auto numCols = type.definition.word(3);
+		auto numRows = getType(type.definition.word(2)).sizeInComponents;
+
+		for (auto col = 0u; col < numCols; col++)
+		{
+			for (auto row = 0u; row < numRows; row++)
+			{
+				dst.move(col * numRows + row, mat.Float(row * numCols + col));
+			}
+		}
+
+		return EmitResult::Continue;
+	}
+
 	SpirvShader::EmitResult SpirvShader::EmitUnaryOp(InsnIterator insn, EmitState *state) const
 	{
 		auto routine = state->routine;
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 34ac47a..bfbe26a 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -649,6 +649,7 @@
 		EmitResult EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitOuterProduct(InsnIterator insn, EmitState *state) const;
+		EmitResult EmitTranspose(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;