We would like to add an std.assert
operation with single Boolean operand and a message attribute to the standard dialect.
The operation will not have a pre-defined lowering but instead the operation can be used to hook-in a custom lowering propagating errors to a runtime.
+1 Both, an std.assert and an std.assume I believe have been missing.
I think it is important to flesh out a bit more the semantics if you’d like this in the “std” dialect: in particular in term of execution behavior. For example is the execution guaranteed to abort? Can we reorder these asserts? Etc.
I feel this should always abort on failure (although the revision doesn’t specify this). And to be consistent with that, reordering of such asserts would be disallowed since they would be seen as having a side-effect on the “external execution environment” or at least on input/output given the error message.
An std.assume could be used if the intention is to not abort but make use of that information for better optimization and imply undefined behavior if the condition doesn’t hold true. Reordering assume
's should be possible because they would have a different kind of side effect that’d allow commuting (and even CSE but not DCE).
So, we will clarify the documentation to ensure that std.assert
always aborts the execution.
The error message is a required attribute for the operation but what it is used for is still up to the user.
Should we implement a default lowering to llvm.trap
or would that be difficult to replace later?
+1 for for having an assert op.
Sounds good to me. I’m not sure what the right LLVM mapping for this will be - but trap sounds good or we could make a call to assert()
itself.
I would leave this unimplemented. It is very runtime specific where this should go. Calling assert()
assumes a libc like target.
We already assume malloc
and free
are present. I don’t think that assuming so is assert
is an issue. Since it’s a pattern, specific lowering pipelines can choose to ignore it, but I wouldn’t leave it unimplemented.
I’m on the same line on this.
Unfortunately, assert is a C macro and its implementation varies widely across execution environments. There’s no assert
symbol available across C-like execution environments that we can just emit an LLVM call to the way we do for malloc
/free
.
This is from a typical Linux man page, and given this, it would be reasonable to emit an assert
with an integer argument?
POSIX.1-2001, POSIX.1-2008, C89, C99. In C89, expression is required to be of type int and undefined behavior results if it is not, but in C99 it may have any scalar type.
The man page also states
This macro can help programmers find bugs in their programs, or handle exceptional cases via a crash that will produce limited debugging output.
So it is indeed a macro and not something we can call directly as we do with free and malloc. We would need a wrapper library that defined a linkable symbol that contains a call to the assert
macro. This is what @_sean_silva was referring to.
So, I still think we should not ship a default lowering but instead have users customize this to their own runtime needs.
The implementation of that macro that I found delegates to __assert_fail
which we can call. The standard lowering could then realize the assertion test and delegate only in case of failure (if we want that).
Lowering std.assert to if(cond) abort();
seems like an OK default?
I think you won’t get the file name, line number, and the text this way, but looks good as the minimal thing to start with.