From 1a934bc4cc9094fa8a7fea3814791924da9699cc Mon Sep 17 00:00:00 2001 From: Murat Toprak Date: Wed, 15 Jul 2026 18:44:42 +0300 Subject: [PATCH] Fix aliasing bug in OpenFHE emitter for InsertOp with shared buffers --- lib/Target/OpenFhePke/OpenFhePkeEmitter.cpp | 19 ++++++++++++---- tests/Emitter/Openfhe/emit_insert_copy.mlir | 25 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 tests/Emitter/Openfhe/emit_insert_copy.mlir diff --git a/lib/Target/OpenFhePke/OpenFhePkeEmitter.cpp b/lib/Target/OpenFhePke/OpenFhePkeEmitter.cpp index 5ddcea7b1f..26b932c2b5 100644 --- a/lib/Target/OpenFhePke/OpenFhePkeEmitter.cpp +++ b/lib/Target/OpenFhePke/OpenFhePkeEmitter.cpp @@ -1707,11 +1707,19 @@ LogicalResult OpenFhePkeEmitter::printOperation( LogicalResult OpenFhePkeEmitter::printOperation(tensor::InsertOp op) { // For a tensor.insert MLIR statement, we assign the destination vector and - // then map the result value to the destination value. + // then map the result value to the destination value if they are equal. // %result = tensor.insert %scalar into %dest[%idx] // dest[idx] = scalar; - os << variableNames->getNameForValue(op.getDest()); - os << "["; + std::string destName = variableNames->getNameForValue(op.getDest()); + std::string resultName = variableNames->getNameForValue(op.getResult()); + if (destName != resultName) { + if (failed(emitType(op.getResult().getType(), op->getLoc()))) { + return failure(); + } + os << " " << resultName << "(" << destName << ");\n"; + } + + os << resultName << "["; if (op.getIndices().empty()) { os << "0"; } else { @@ -1724,7 +1732,10 @@ LogicalResult OpenFhePkeEmitter::printOperation(tensor::InsertOp op) { os << "]"; os << " = " << variableNames->getNameForValue(op.getScalar()) << ";\n"; - variableNames->mapValueNameToValue(op.getResult(), op.getDest()); + if (destName == resultName) { + variableNames->mapValueNameToValue(op.getResult(), op.getDest()); + } + return success(); } diff --git a/tests/Emitter/Openfhe/emit_insert_copy.mlir b/tests/Emitter/Openfhe/emit_insert_copy.mlir new file mode 100644 index 0000000000..cb2b7750ce --- /dev/null +++ b/tests/Emitter/Openfhe/emit_insert_copy.mlir @@ -0,0 +1,25 @@ +// RUN: heir-translate %s --emit-openfhe-pke | FileCheck %s + +!cc = !openfhe.crypto_context +!ct = !openfhe.ciphertext + +module attributes {scheme.bgv} { + // Two tensor.insert ops sharing the same tensor.empty buffer must produce + // distinct C++ vectors (copy-on-write), not alias both results to the same + // destination variable. + + // CHECK: mm_bug_two_wraps + // CHECK: std::vector<{{.*}}> [[V1:v[0-9]+]]( + // CHECK: [[V1]][0] = %arg1 + // CHECK: std::vector<{{.*}}> [[V2:v[0-9]+]]( + // CHECK: [[V2]][0] = %arg2 + // CHECK: return {[[V1]], [[V2]]}; + func.func @mm_bug_two_wraps(%arg0: !cc, %arg1: !ct, %arg2: !ct) + -> (tensor<1x!ct>, tensor<1x!ct>) { + %c0 = arith.constant 0 : index + %buf = tensor.empty() : tensor<1x!ct> + %wrap1 = tensor.insert %arg1 into %buf[%c0] : tensor<1x!ct> + %wrap2 = tensor.insert %arg2 into %buf[%c0] : tensor<1x!ct> + return %wrap1, %wrap2 : tensor<1x!ct>, tensor<1x!ct> + } +}