Upon invocation of a function with memref arguments, the strides for
all dimensions are currently set to 0. This causes dynamic offsets to
be calculated incorrectly in the function body.
This patch replaces the placeholder values with the actual strides for
each dimension and adds a test with parametric slice extraction from a
tensor that triggers dynamic indexing.
[----------] Global test environment tear-down
[==========] 7 tests from 1 test suite ran. (1513 ms total)
[ PASSED ] 7 tests.
YOU HAVE 2 DISABLED TESTS
[----------] Global test environment tear-down
[==========] 6 tests from 1 test suite ran. (1513 ms total)
[ PASSED ] 6 tests.
YOU HAVE 3 DISABLED TESTS
Compared to previous commit, a fatal test is disabled
[----------] Global test environment tear-down
[==========] 6 tests from 1 test suite ran. (1327 ms total)
[ PASSED ] 5 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] Lambda_check_param.scalar_tensor_to_tensor_good_number_param
1 FAILED TEST
YOU HAVE 3 DISABLED TESTS
Resolves#288
example
before:
Failed to lower to LLVM dialect
after:
Failed to lower to LLVM dialect
test.mlir:3:10: error: unexpected error: 'linalg.copy' op expected indexing_map #1 to have 2 dim(s) to match the number of loops
%0 = tensor.extract_slice %arg0[0, 0] [3, 1] [1, 1] : tensor<3x2x!HLFHE.eint<3>> to tensor<3x!HLFHE.eint<3>>
^
Try to find the runtime library automatically (should only work on
proper installation of the package), and fail silently by not passing
any RT lib. The RT lib can also be specified manually. The RT lib will
be used as a shared library by the JIT compiler.
Add a new method `JITLambda::Arguments::getResultWidth` returning the
width of a scalar result or the element type of a tensor result at a
given position.
Currently, `JITLambda::Arguments` assumes result tensors are always
composed of `uint64_t` elements. This change adds support for
arbitrary scalar element types.
All results in code compiled by zamacompiler are passed as return
values, which means that all tensors passed as function arguments are
constant inputs that are never written.
This patch changes the arguments used as data pointers for input
tensors in `JITLambda::Arguments::setArg()` from `void*` to `const
void*` to emphasize their use as inputs and to allow for constant
arrays to be passed as function inputs.
By default, `mlir::SourceMgrDiagnosticVerifierHandler` used by
`CompilerEngine::compile()` prints parse errors to
`llvm::errs()`. This makes it impossible for a caller of
`CompilerEngine::compile()` to process parse errors or to suppress the
emission of error messages to the standard error stream altogether.
This change captures parse errors in a string via a string-backed
output stream and forwards the error message in the `llvm::Error`
instance of the return value.
This commit contains several incremental improvements towards a clear
interface for lambdas:
- Unification of static and JIT compilation by using the static
compilation path of `CompilerEngine` within a new subclass
`JitCompilerEngine`.
- Clear ownership for compilation artefacts through
`CompilationContext`, making it impossible to destroy objects used
directly or indirectly before destruction of their users.
- Clear interface for lambdas generated by the compiler through
`JitCompilerEngine::Lambda` with a templated call operator,
encapsulating otherwise manual orchestration of `CompilerEngine`,
`JITLambda`, and `CompilerEngine::Argument`.
- Improved error handling through `llvm::Expected<T>` and proper
error checking following the conventions for `llvm::Expected<T>`
and `llvm::Error`.
Co-authored-by: youben11 <ayoub.benaissa@zama.ai>
Composing error messages for `llvm::Error` is either done by using
`llvm::createStringError()` with an appropriate format string and
arguments or by writing to a `std::string`-backed
`llvm::raw_string_ostream` and passing the result to
`llvm::make_error<llvm::StringError>()` verbatim.
The new class `StreamStringError` encapsulates the latter solution
into a class with an appropriate stream operator and implicit cast
operators to `llvm::Error` and `llvm::Expected`.
Example usage:
llvm::Error foo(int i, size_t s, ...) {
...
if(...) {
return StreamStringError()
<< "Some error message with an integer: "
<< i << " and a size_t: " << s;
}
...
}
LLVM errors should be handled/consumed. Creating a new one and leaving
the previous one alive will crash the compiler. Whenever we don't want a
crash (e.g. logging the error is enough), but still wanna continue the
execution, we can just consume it.
This replaces the default FHE circuit constrains (maximum encrypted
integer width of 7 bits and a Minimal Arithmetic Noise Padding of 10
with the results of the `MaxMANP` pass, which determines these values
automatically from the input program.
Since the maximum encrypted integer width and the maximum value for
the Minimal Arithmetic Noise Padding can only be derived from HLFHE
operations, the circuit constraints are determined automatically by
`zamacompiler` only if the option `--entry-dialect=hlfhe` was
specified.
For lower-level dialects, `zamacompiler` has been provided with the
options `--assume-max-eint-precision=...` and `--assume-max-manp=...`
that allow a user to specify the values for the maximum required
precision and maximum values for the Minimal Arithmetic Noise Padding.
A value of 1 is perfectly valid for the 2-norm of the constant vector
of a dot operation. Hence, the log2 of that value of 0 is also
perfectly valid. However, the offset of -1 in `getV0Parameter` applied
to that value yields an offset into a static lookup table of -1, which
triggers a segmentation fault.
This patch removes the offset of -1 for the log2 value of the 2-norm
in `getV0Parameter`.
The new option --acion=dump-hlfhe-manp invokes the Minimal Arithmetic
Noise Padding Analysis pass based on the squared 2-norm metric from
`lib/Dialect/HLFHE/Analysis/MANP.cpp` and dumps the module afterwards
with an extra attribute `MANP` for each HLFHE operation.
This refactoring commit restructures the compilation pipeline of
`zamacompiler`, such that it is possible to enter and exit the
pipeline at different points, effectively defining the level of
abstraction at the input and the required level of abstraction for the
output.
The entry point is specified using the `--entry-dialect`
argument. Valid choices are:
`--entry-dialect=hlfhe`: Source contains HLFHE operations
`--entry-dialect=midlfhe`: Source contains MidLFHE operations
`--entry-dialect=lowlfhe`: Source contains LowLFHE operations
`--entry-dialect=std`: Source does not contain any FHE Operations
`--entry-dialect=llvm`: Source is in LLVM dialect
The exit point is defined by an action, specified using --action.
`--action=roundtrip`:
Parse the source file to in-memory representation and immediately
dump as text without any processing
`--action=dump-midlfhe`:
Lower source to MidLFHE and dump result as text
`--action=dump-lowlfhe`:
Lower source to LowLFHE and dump result as text
`--action=dump-std`:
Lower source to only standard MLIR dialects (i.e., all FHE
operations have already been lowered)
`--action=dump-llvm-dialect`:
Lower source to MLIR's LLVM dialect (i.e., the LLVM dialect, not
LLVM IR)
`--action=dump-llvm-ir`:
Lower source to plain LLVM IR (i.e., not the LLVM dialect, but
actual LLVM IR)
`--action=dump-optimized-llvm-ir`:
Lower source to plain LLVM IR (i.e., not the LLVM dialect, but
actual LLVM IR), pass the result through the LLVM optimizer and
print the result.
`--action=dump-jit-invoke`:
Execute the full lowering pipeline to optimized LLVM IR, JIT
compile the result, invoke the function specified in
`--jit-funcname` with the parameters from `--jit-args` and print
the functions return value.
The function `getV0Parameter()` returns a pointer to a static array,
which is not intended to be mutable. Reflect this in the return type
of the function.
Replace the macros `LOG_VERBOSE` and `LOG_ERROR` with C++-style
streams retrieved through `log_verbose()` and `log_error()`. This
aligns with the `MLIR` infrastructure and avoids pollution of the
global namespace through a common header file in subsequent
refactoring commits splitting the functionality of `src/main.cpp` into
multiple files.