SMEABIPass.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //===--------- SMEABI - SME ABI-------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This pass implements parts of the the SME ABI, such as:
  10. // * Using the lazy-save mechanism before enabling the use of ZA.
  11. // * Setting up the lazy-save mechanism around invokes.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "AArch64.h"
  15. #include "Utils/AArch64BaseInfo.h"
  16. #include "Utils/AArch64SMEAttributes.h"
  17. #include "llvm/ADT/SmallVector.h"
  18. #include "llvm/ADT/StringRef.h"
  19. #include "llvm/IR/Constants.h"
  20. #include "llvm/IR/IRBuilder.h"
  21. #include "llvm/IR/Instructions.h"
  22. #include "llvm/IR/IntrinsicInst.h"
  23. #include "llvm/IR/IntrinsicsAArch64.h"
  24. #include "llvm/IR/LLVMContext.h"
  25. #include "llvm/InitializePasses.h"
  26. #include "llvm/Support/Debug.h"
  27. #include "llvm/Transforms/Utils/Cloning.h"
  28. using namespace llvm;
  29. #define DEBUG_TYPE "aarch64-sme-abi"
  30. namespace {
  31. struct SMEABI : public FunctionPass {
  32. static char ID; // Pass identification, replacement for typeid
  33. SMEABI() : FunctionPass(ID) {
  34. initializeSMEABIPass(*PassRegistry::getPassRegistry());
  35. }
  36. bool runOnFunction(Function &F) override;
  37. private:
  38. bool updateNewZAFunctions(Module *M, Function *F, IRBuilder<> &Builder);
  39. };
  40. } // end anonymous namespace
  41. char SMEABI::ID = 0;
  42. static const char *name = "SME ABI Pass";
  43. INITIALIZE_PASS_BEGIN(SMEABI, DEBUG_TYPE, name, false, false)
  44. INITIALIZE_PASS_END(SMEABI, DEBUG_TYPE, name, false, false)
  45. FunctionPass *llvm::createSMEABIPass() { return new SMEABI(); }
  46. //===----------------------------------------------------------------------===//
  47. // Utility functions
  48. //===----------------------------------------------------------------------===//
  49. // Utility function to emit a call to __arm_tpidr2_save and clear TPIDR2_EL0.
  50. void emitTPIDR2Save(Module *M, IRBuilder<> &Builder) {
  51. auto *TPIDR2SaveTy =
  52. FunctionType::get(Builder.getVoidTy(), {}, /*IsVarArgs=*/false);
  53. auto Attrs =
  54. AttributeList()
  55. .addFnAttribute(M->getContext(), "aarch64_pstate_sm_compatible")
  56. .addFnAttribute(M->getContext(), "aarch64_pstate_za_preserved");
  57. FunctionCallee Callee =
  58. M->getOrInsertFunction("__arm_tpidr2_save", TPIDR2SaveTy, Attrs);
  59. CallInst *Call = Builder.CreateCall(Callee);
  60. Call->setCallingConv(
  61. CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0);
  62. // A save to TPIDR2 should be followed by clearing TPIDR2_EL0.
  63. Function *WriteIntr =
  64. Intrinsic::getDeclaration(M, Intrinsic::aarch64_sme_set_tpidr2);
  65. Builder.CreateCall(WriteIntr->getFunctionType(), WriteIntr,
  66. Builder.getInt64(0));
  67. }
  68. /// This function generates code to commit a lazy save at the beginning of a
  69. /// function marked with `aarch64_pstate_za_new`. If the value read from
  70. /// TPIDR2_EL0 is not null on entry to the function then the lazy-saving scheme
  71. /// is active and we should call __arm_tpidr2_save to commit the lazy save.
  72. /// Additionally, PSTATE.ZA should be enabled at the beginning of the function
  73. /// and disabled before returning.
  74. bool SMEABI::updateNewZAFunctions(Module *M, Function *F,
  75. IRBuilder<> &Builder) {
  76. LLVMContext &Context = F->getContext();
  77. BasicBlock *OrigBB = &F->getEntryBlock();
  78. // Create the new blocks for reading TPIDR2_EL0 & enabling ZA state.
  79. auto *SaveBB = OrigBB->splitBasicBlock(OrigBB->begin(), "save.za", true);
  80. auto *PreludeBB = BasicBlock::Create(Context, "prelude", F, SaveBB);
  81. // Read TPIDR2_EL0 in PreludeBB & branch to SaveBB if not 0.
  82. Builder.SetInsertPoint(PreludeBB);
  83. Function *TPIDR2Intr =
  84. Intrinsic::getDeclaration(M, Intrinsic::aarch64_sme_get_tpidr2);
  85. auto *TPIDR2 = Builder.CreateCall(TPIDR2Intr->getFunctionType(), TPIDR2Intr,
  86. {}, "tpidr2");
  87. auto *Cmp =
  88. Builder.CreateCmp(ICmpInst::ICMP_NE, TPIDR2, Builder.getInt64(0), "cmp");
  89. Builder.CreateCondBr(Cmp, SaveBB, OrigBB);
  90. // Create a call __arm_tpidr2_save, which commits the lazy save.
  91. Builder.SetInsertPoint(&SaveBB->back());
  92. emitTPIDR2Save(M, Builder);
  93. // Enable pstate.za at the start of the function.
  94. Builder.SetInsertPoint(&OrigBB->front());
  95. Function *EnableZAIntr =
  96. Intrinsic::getDeclaration(M, Intrinsic::aarch64_sme_za_enable);
  97. Builder.CreateCall(EnableZAIntr->getFunctionType(), EnableZAIntr);
  98. // Before returning, disable pstate.za
  99. for (BasicBlock &BB : *F) {
  100. Instruction *T = BB.getTerminator();
  101. if (!T || !isa<ReturnInst>(T))
  102. continue;
  103. Builder.SetInsertPoint(T);
  104. Function *DisableZAIntr =
  105. Intrinsic::getDeclaration(M, Intrinsic::aarch64_sme_za_disable);
  106. Builder.CreateCall(DisableZAIntr->getFunctionType(), DisableZAIntr);
  107. }
  108. F->addFnAttr("aarch64_expanded_pstate_za");
  109. return true;
  110. }
  111. bool SMEABI::runOnFunction(Function &F) {
  112. Module *M = F.getParent();
  113. LLVMContext &Context = F.getContext();
  114. IRBuilder<> Builder(Context);
  115. if (F.isDeclaration() || F.hasFnAttribute("aarch64_expanded_pstate_za"))
  116. return false;
  117. bool Changed = false;
  118. SMEAttrs FnAttrs(F);
  119. if (FnAttrs.hasNewZAInterface())
  120. Changed |= updateNewZAFunctions(M, &F, Builder);
  121. return Changed;
  122. }