This is an archive of the discontinued LLVM Phabricator instance.

[SystemZ] Emit .gnu_attribute for an externally visible vector abi.
ClosedPublic

Authored by jonpa on Jun 28 2021, 4:25 PM.

Details

Summary

This is the SystemZ part originally part of https://reviews.llvm.org/D102894.

On SystemZ, the vector ABI changes depending on the presence of hardware vector support. Therefore, each binary compiled with a visible vector ABI (e.g. calling an external function with a vector argument) should be marked with a .gnu_attribute describing this.

This adds support on SystemZ to emit a gnu attribute for the vector abi both to asm and object files.

Diff Detail

Event Timeline

jonpa created this revision.Jun 28 2021, 4:25 PM
jonpa requested review of this revision.Jun 28 2021, 4:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 28 2021, 4:25 PM
jonpa added a comment.Jun 28 2021, 4:26 PM

This is missing some cases. We need to catch any type that contains a vector type somewhere, which includes in particular aggregate types like array and structs, since the different alignment of the member may in turn trigger a different alignment of the aggregate. E.g. a struct that contains a member of vector type should trigger the attribute.

right... added recursive handling for array/struct types.

We also possibly need to catch function pointer types where the pointed-to function has a vector (or derived) type as argument or return value. (However, that may be overkill: it really only "counts" if such a type is *used* either to perform a call via function pointer, or else if the address of a local function is passed as pointer to some external user. If this is too difficult to determine, then I guess it's OK to just count all function pointer types.)

Added handling for FunctionType. In both these cases the globally called function is found to have a user and then inspected for the function type.

uweigand added inline comments.Jun 29 2021, 1:45 PM
llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
800

Now that isVectorTypeBased supports function types, I think the code below can be replaced by a single call to isVectorTypeBased(FTy).

810

I don't think this implementation of vararg support is quite complete. On the caller side, you check for variable arguments to any direct function with a prototype. However, this misses the case where an *indirect* function call (using a function pointer) has variable arguments.

This also completely misses the *callee* side: every function that takes variable arguments and uses va_arg with a vector type is also dependent on the vector ABI.

jonpa updated this revision to Diff 356489.Jul 5 2021, 5:55 AM
jonpa marked 2 inline comments as done.

I don't think this implementation of vararg support is quite complete. On the caller side, you check for variable arguments to any direct function with a prototype. However, this misses the case where an *indirect* function call (using a function pointer) has variable arguments.

This also completely misses the *callee* side: every function that takes variable arguments and uses va_arg with a vector type is also dependent on the vector ABI.

Patch updated to address these cases as well.

I don't think this implementation of vararg support is quite complete. On the caller side, you check for variable arguments to any direct function with a prototype. However, this misses the case where an *indirect* function call (using a function pointer) has variable arguments.

This also completely misses the *callee* side: every function that takes variable arguments and uses va_arg with a vector type is also dependent on the vector ABI.

Patch updated to address these cases as well.

Unfortunately I think this still catches only a subset of those cases. For the indirect calls, you now check those using a global function pointer variable. But calls via a local function pointer (e.g. a callback argument) have the same problem. For the callee side, you now check exported functions that use va_start - but we also need to handle functions that get a va_list as argument, as well as non-exported functions (you can pass va_list through to other routines).

GCC checks every call instruction in the whole compilation unit that uses variable argument lists, and it also checks every use of va_arg. I believe we may have to do the same. (This is a problem since va_arg is already expanded by the front-end. I'm starting to think this whole logic might be better placed in clang; we can just set a flag there when we expand a call or a va_arg, and don't have to scan everything after the fact ...)

jonpa updated this revision to Diff 357434.Jul 9 2021, 2:02 AM

we also need to handle functions that get a va_list as argument, as well as non-exported functions (you can pass va_list through to other routines).

Patch updated per review.

Callee:

  • if va_arg with vector type is lowered in a global function, VecABI is visible. Needs to be checked in FE (SystemZABIInfo::EmitVAArg).
  • FunctionType of global function is checked in SystemZAsmPrinter.

Caller:

Since we need to inspect all calls (not just to globally declared/defined functions), I thought we either need to do a scan over all functions/instructions in AsmPrinter, or we could check all calls during isel in LowerCall() (Doing it in the FE seems worse as no optimizations at all have taken place yet). I tried now to do it in LowerCall(), but as I did not find any way to set a flag at Module scope each new function has still calls checked until the function attribute is added. Scanning everything in AsmPrinter would stop at the first occurrence on the other hand...

I hope all calls of interest have the CLI.CB pointer (Instruction*) set. The one case I have seen where this is null is for an intrinsic (patch-point)...

It seems that gcc emits attribute if va_start is used, even if va_list is not used. I have simplified this a bit to assume that va_start is always present in a var-arg function.

It seems that gcc is conservative about the va_list being passed on to other functions: As soon as a vector vararg argument is passed, it seems the vector ABI becomes visible, even if calling a static function, and I did the same.

isVectorTypeBased() now moved into SystemZ namespace so that it can be used also in LowerCall().

I tried now to do it in LowerCall(), but as I did not find any way to set a flag at Module scope

You might want to look at the module flags metadata mechanism: https://llvm.org/docs/LangRef.html#module-flags-metadata
See the addModuleFlag / getModuleFlag routines.

jonpa updated this revision to Diff 371542.Sep 9 2021, 3:51 AM

Updated per review to use a module flag instead of function attribute.

No other function changes, but some thoughts:

Not sure if SystemZMachineFunctionInfo.h is the right place for isVectorTypeBased()... It could simply be local to SystemZAsmPrinter.cpp if we scanned for all call instructions there instead of checking them in SystemZISelLowering::LowerCall(). I would feel just slightly more comfortable with that rather than relying on the presence of CLI.CB in detectVisibleVectorABI(), although I guess that should be ok... It might also be slightly more readable to not handle the call sites in a different place, but rather do all the back-end checking in AsmPrinter.

hasVisibleVectorABI() checks varargs also when calling a local function (see comment there). It would have been nice to instead identify va_list in isVectorTypeBased(), but I don't think that's possible. Another way might be to check in the front-end when a va_list is passed to a global function... Not sure how much it matters - I think GCC is being overconservative here.

jonpa updated this revision to Diff 373880.Sep 21 2021, 5:42 AM

Patch rebased.

jonpa updated this revision to Diff 420126.Apr 4 2022, 2:52 AM

Patch rebased with needed changes in order to build with passing tests:

  • Use PTy->getPointerElementType() and not PTy->getElementType().
  • Use CLI.CB->arg_size() instead of CLI.CB->getNumArgOperands().
  • Check for existing module flag before adding "visible-vector-ABI" flag in SystemZABIInfo::EmitVAArg(). This seems to have been needed before as well, but the assertion for this did not trigger (now triggered by systemz-abi-vector.c, not changed by this patch).
Herald added a project: Restricted Project. · View Herald TranscriptApr 4 2022, 2:52 AM
jonpa added a comment.EditedApr 5 2022, 1:27 AM

We also need to think about "opaque pointers" at some point...

jonpa added a comment.Sep 8 2022, 4:00 AM

Tried to rebase today, but got some build error. I also think we probably should consider opaque pointers now as it has become the default, by going through the tests and also type handling of pointers in the patch, I would guess.

First question though is if this patch became so complex that it is more reasonable to abandon it, or is this still under review?

jonpa updated this revision to Diff 463242.Sep 27 2022, 8:38 AM

Patch reworked to support opaque pointers which are now the default and soon mandatory. This was not just a syntactic change, but as far as I understand we have to respect that it is legal to use pointer in any arbitrary way. For example, this program now compiles without warning:

define void @fun(ptr %Src, ptr %Dst) {
  %L1 = load <4 x i32>, ptr %Src
  store <4 x i32> %L1, ptr %Dst
  %L2 = load i32, ptr %Src
  store i32 %L2, ptr %Dst

  call void %Src()

  ret void
}

I have updated the patch according to the conservative assumption that a pointer could always potentially expose the vector ABI. This seems necessary when handling this in the backend at least. This leads to a somewhat more simple handling, but I am not sure if this is acceptable. I guess the only alternative would be to handle everything in the front end instead, where hopefully these things are known. Then again, as I believe we have discussed before, that has the drawback of deciding on this before optimizations have run, which also could mean over-conservative results.

jonpa updated this revision to Diff 478123.Nov 27 2022, 5:13 PM

Patch reworked to do the visible vector ABI detection in the Clang FE instead, which is necessary after the move to opaque pointers.

  • The recursive search of the type is basically moved to the frontend. A set has to be used to avoid revisiting the same type again which is catastrophic in compile time.
  • Tried to ignore unused pointers, but it seems that with C++ isUsed() always returns false, which means the patch is acting conservatively with pointers by assuming they always expose the ABI.
  • Did not find a possible way to check vararg arguments when passed via funtion pointer: The check in CodeGenFunction::EmitCall() with checkFunctionCallABI() does not work for calls via function pointer. I think that either a similar method could be called here as well for the case where only a function prototype is available (and not a declaration), or it could be checked in CodeGenFunction::getVarArgType(). As long as it's only needed for varargs I guess its easier to do it in getVarArgType() (which the patch now does), but on the other hand it might make sense to have the check done in one place regardless of declaration/funptr.
  • Would like to avoid looking up with getModuleFlag() extensively (only based on reasoning, not any compile time measurements), so added a mutable internal flag in SystemZTargetCodeGenInfo as setTargetAttributes() is const. Not sure if that makes a difference...
  • Tried to get some suggestions on the name of the new module flag on Discourse a while ago, but without any replies.
  • In the last minute I noticed that three regression tests are failing. They all fail at the same point when SystemZTargetCodeGenInfo::setTargetAttributes() calls GetGVALinkageForFunction() on a function with the 'inline' keyword without a function body, which triggers an assertion. Not sure if this is a bug in GetGVALinkageForFunction() or if this is a call that should never be made.
clang/test/CodeGen/PR2743-reference-missing-static.c
clang/test/CodeGen/unique-internal-linkage-names.c
clang/test/CoverageMapping/decl.c
jonpa updated this revision to Diff 478224.Nov 28 2022, 6:36 AM

Avoid the problem with GetGVALinkageForFunction() by calling isExternallyVisible() instead, which seems to be the better alternative as well.

jonpa updated this revision to Diff 478601.Nov 29 2022, 8:04 AM

I tried to move the handling of functions into computeInfo(), but found that it is not possible to know from a CGFunctionInfo if the function is externally visible or not. It does however seem like all vararg calls go through here (for normal functions only the declaration/definition is processed), which is fortunate as it happens that even a local vararg call should be regarded (the va_list could be passed to another global function potentially). I could therefore remove the new target hook I had added for the purpose of checking varargs.

uweigand added inline comments.Dec 5 2022, 6:37 AM
clang/lib/CodeGen/TargetInfo.cpp
7394

I'm wondering if it wouldn't be preferable to move those (and the functions operating on them) to SystemZTargetCodeGenInfo instead? There is precedent for mutable members in XCodeTargetCodeGenInfo.

7516

I think this will also have to look into C++ base classes, similar to what is done in isSingleElementStruct, doesn't it?

7628

Not sure about this. I think we need to do this unconditionally. Think e.g. of a global function that gets called with a va_list argument, passes that va_list to another *local* function, which invokes the va_arg on it. This would not be caught by your current code.

jonpa updated this revision to Diff 480520.Dec 6 2022, 9:21 AM
jonpa marked 3 inline comments as done.

Thanks for review - patch updated. Tests vec-abi-gnuattr-14.c and vec-abi-gnuattr-20.cpp strengthened accordingly.

uweigand accepted this revision.Dec 6 2022, 10:11 AM

See one inline comment, otherwise LGTM now. Thanks!

clang/lib/CodeGen/TargetInfo.cpp
7628

Just one minor nit: why use CGF.CGM in some places and CGT.getCGM() in others? These should be the same, but it would be clearer to use the same expression everywhere.

This revision is now accepted and ready to land.Dec 6 2022, 10:11 AM
This revision was landed with ongoing or failed builds.Dec 6 2022, 10:54 AM
This revision was automatically updated to reflect the committed changes.
jonpa marked an inline comment as done.
Herald added a project: Restricted Project. · View Herald TranscriptDec 6 2022, 10:54 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript