@@ -124,6 +124,8 @@ static StringRef shimSymbolFor(StringRef libSym) {
124124 return " polygeist_cufft_z2z_1d" ;
125125 if (libSym == " cufftC2C_1D_tensor" )
126126 return " polygeist_cufft_c2c_1d" ;
127+ if (libSym == " cutensornetTensorProduct3D_f32_tensor" )
128+ return " polygeist_cutensornet_tensor_product_3d_f32" ;
127129 // NOTE: cudnnConvolution2D_9tap_i{8,16} are intentionally absent — those
128130 // launches route to PVA Solutions' libpva_operator and are lowered by
129131 // a separate pass (see LowerKernelLaunchToPVA.cpp). cuDNN itself has
@@ -1007,6 +1009,71 @@ static LogicalResult lowerCufftC2C1DTensor(LaunchOp launch, ModuleOp module,
10071009 return success ();
10081010}
10091011
1012+ // Tensor-product contraction
1013+ // out[a,b,c] = sum(i,j,k) psi[a,i] psi[b,j] psi[c,k] u[i,j,k]
1014+ // reaches the matcher as five rank-6 submap views over three flat buffers.
1015+ // The first three views share the psi base. Unwrap all views and let the
1016+ // cuTensorNet shim express the full Einstein contraction directly.
1017+ static LogicalResult lowerCutensornetTensorProduct3DF32 (LaunchOp launch,
1018+ ModuleOp module ) {
1019+ if (launch.getNumOperands () != 5 || launch.getNumResults () != 1 )
1020+ return launch.emitError (
1021+ " cuTensorNet tensor product: expected 5 operands and 1 result" );
1022+
1023+ for (Value operand : launch.getOperands ()) {
1024+ auto ty = dyn_cast<RankedTensorType>(operand.getType ());
1025+ if (!ty || ty.getRank () != 6 || !ty.getElementType ().isF32 ())
1026+ return launch.emitError (
1027+ " cuTensorNet tensor product: operands must be rank-6 f32 tensors" );
1028+ auto submap = operand.getDefiningOp <polygeist::SubmapOp>();
1029+ if (!submap || submap.getSizes ().size () != 6 )
1030+ return launch.emitError (
1031+ " cuTensorNet tensor product: operands must be rank-6 submaps" );
1032+ }
1033+
1034+ Value psi0 = resolveSubmapBase (launch.getOperand (0 ));
1035+ Value psi1 = resolveSubmapBase (launch.getOperand (1 ));
1036+ Value psi2 = resolveSubmapBase (launch.getOperand (2 ));
1037+ Value u = resolveSubmapBase (launch.getOperand (3 ));
1038+ Value out = resolveSubmapBase (launch.getOperand (4 ));
1039+ if (psi0 != psi1 || psi0 != psi2)
1040+ return launch.emitError (
1041+ " cuTensorNet tensor product: first three views must share psi base" );
1042+
1043+ auto psiTy = dyn_cast<RankedTensorType>(psi0.getType ());
1044+ auto uTy = dyn_cast<RankedTensorType>(u.getType ());
1045+ auto outTy = dyn_cast<RankedTensorType>(out.getType ());
1046+ if (!psiTy || !uTy || !outTy || !psiTy.getElementType ().isF32 () ||
1047+ !uTy.getElementType ().isF32 () || !outTy.getElementType ().isF32 ())
1048+ return launch.emitError (
1049+ " cuTensorNet tensor product: submap bases must be f32 tensors" );
1050+
1051+ auto firstView = launch.getOperand (0 ).getDefiningOp <polygeist::SubmapOp>();
1052+ OpBuilder b (launch);
1053+ Location loc = launch.getLoc ();
1054+ Value KQ = valueAsI32 (b, loc, firstView.getSizes ()[0 ]);
1055+ Value KP = valueAsI32 (b, loc, firstView.getSizes ()[3 ]);
1056+ Value psiMr = tensorToMemref (b, loc, psi0);
1057+ Value uMr = tensorToMemref (b, loc, u);
1058+ Value outMr = tensorToMemref (b, loc, out);
1059+ Value psiPtr = memrefBasePtr (b, loc, psiMr);
1060+ Value uPtr = memrefBasePtr (b, loc, uMr);
1061+ Value outPtr = memrefBasePtr (b, loc, outMr);
1062+
1063+ auto ptrTy = LLVM::LLVMPointerType::get (b.getContext ());
1064+ SmallVector<Type> argTypes = {b.getI32Type (), b.getI32Type (), ptrTy,
1065+ ptrTy, ptrTy};
1066+ func::FuncOp shim = ensureShimDecl (
1067+ module , " polygeist_cutensornet_tensor_product_3d_f32" , argTypes, b);
1068+ b.create <func::CallOp>(loc, shim,
1069+ ValueRange{KQ , KP , psiPtr, uPtr, outPtr});
1070+
1071+ Value updatedOut = memrefToTensor (b, loc, outMr, out.getType ());
1072+ rewireLaunchResult (launch, updatedOut);
1073+ launch.erase ();
1074+ return success ();
1075+ }
1076+
10101077// Darknet im2col+GEMM reaches the matcher as rank-3 broadcasted submaps:
10111078// A(m, k, n) -> weights[m, k]
10121079// B(m, k, n) -> workspace[k, n]
@@ -2974,6 +3041,8 @@ struct LowerKernelLaunchToCuBLASPass
29743041 } else if (libSym == " cufftZ2Z_1D_tensor" ||
29753042 libSym == " cufftC2C_1D_tensor" ) {
29763043 r = lowerCufftC2C1DTensor (launch, module , shim);
3044+ } else if (libSym == " cutensornetTensorProduct3D_f32_tensor" ) {
3045+ r = lowerCutensornetTensorProduct3DF32 (launch, module );
29773046 } else if (libSym == " cudnnConvolutionFwd_batched" ) {
29783047 r = lowerCudnnConv2dBatched (launch, module );
29793048 } else if (libSym == " cudnnConvolutionFwd_im2col_gemm" ) {
0 commit comments