Implements the PowerPC mtfsf and mtfsfi intrinsics as well as introduces semantic error checking code for PowerPC intrinsics
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
We are looking for community input regarding the error handling for these intrinsics (and more PowerPC intrinsics to come):
- Are we ok we doing semantic checking in the handler functions like we are doing for mtfsf/mtfsfi (ie checking if constant op and in valid range)
- How should the errors be reported? The problem with using mlir::emitError is it seems to return code 0 instead of an error code >= 1, but we don't want to use fir::emitFatalError since it crashes, we would just like to terminate compilation with non-zero exit code.
So far, the semantic and evaluate libraries are the place to report user errors. Lowering is only expected to throw errors for internal errors (which may be caused by the lack of a proper semantic check), hence the usage of fir::emitFatalError. As long as having a value out of range will not put the compiler in a bad state (like reading something out of bound at compile time), lowering should rely on the value having been checked by semantics and not re-do checks.
I would say that check-expression.cpp could be the place to detect porcedures from the ppc module and to call some ppc specific validation routine: https://github.com/llvm/llvm-project/blob/27004e027312a59e3b6645f5df58e97c2a2da6ef/flang/lib/Evaluate/check-expression.cpp#L653
Better check with @klausler here though.
flang/lib/Semantics/check-call.cpp is the best place to check calls in general. If any of these new intrinsic module procedures can appear in a specification expression or constant expression, then flang/lib/Evaluate/check-expression.cpp is where that infrastructure resides.
Ping.
I moved the semantic error checking code for PowerPC intrinsics into check-call.cpp. It is called from within expression.cpp
This implementation checks if an intrinsic name (after resolution) begins with "__ppc_" to determine if its a PPC intrinsic (PPC builtins scope must exist). We decided to go with this option since it can be argued that a name collision with (for e.g.) __ppc_mtfsf would be at the fault of the user, especially because double underscore names are typically reserved for the compiler.
An alternative that we also tried was creating a new flag in the Symbol class called PPCIntrinsic and setting it for the generic intrinsic when making the symbol in resolve-names.cpp. We believed the community would be less inclined to this option because of the introduction of the new symbol flag. However, let me know if this option is preferred.
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1232 | Use CHECK(), not assert(). | |
1236 | This isn't unreachable code. Use DIE(...) or common::die(...). | |
1257 | braced initialization here | |
flang/lib/Semantics/check-call.h | ||
42 | Please give names to those "int" arguments in the prototype so that a reader of this code has a fighting chance at knowing what they're supposed to mean. | |
flang/lib/Semantics/expression.cpp | ||
2533 | Delete "const auto ppcBuiltinScope = ". The identifier is not used and even if it were, it's now a bool, not a Scope. |
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1234 | If you really want to copy the actual argument, it doesn't need to be const. If you want a reference to the actual argument, you need to put '&' before the name "argOptional". Either way, use braced initialization here. | |
1240 | You probably want this to be a const reference, not a const-qualified copy. |
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1232 | As long as you're verifying "index", might as well ensure that it's >=0 too. | |
1241 | Braced initialization | |
1244 | This is not an unreachable code error. Just use CHECK(argExpr != nullptr) or (later) use the DEREF() macro. | |
1259 | This is not an unreachable code situation. |
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1246 | Better wording: "Actual argument #%d must be a constant expression". | |
1255 | The error isn't about type conversion; it's that the value was not a constant. The crash message is misleading. If you don't want to reword it, replace this if block with a CHECK(scalarValue.has_value()). | |
1261 | s/expected to be/must be a/ When formatting non-"int" integer types in messages, use %jd formatting and cast the values to std::intmax_t. |
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1261 | Sorry, just confused what you mean by non-"int" integer types. In this case index, upperBound and lowerBound are all of int type. I see other examples in flang where %jd with a static_cast to intmax_t is used when the actual type of the variable is not int. Wondering which variable here you wanted casted here |
flang/lib/Semantics/check-call.cpp | ||
---|---|---|
1261 | Sorry, I misread this code, and assumed that the values had come from ToInt64. Never mind! |
Will wait until tomorrow in case anyone in community has any last minute comments, will land this in the morning.
Thanks for the review!
Sorry about the -Wsign-compare problem in check-call.cpp, thanks @DamonFool for catching it so quickly. I must have been building with different error options locally and missed that error. Will try to be more careful going forward.
We were unsure for scenarios like this, where a trivial error accidentally lands, what the best course of action is. Should we be reverting the patch that caused the issue or should we be opening up a new patch to do the fix (considering its quick/trivial).
Maybe it would be easier to read if you follow the same naming scheme with Void for the return type.