[ARM] add common parts for PACBTI-M support in the backend

This patch encapsulates decision logic about when and how to generate
PAC/BTI related code. It's a part shared by PAC-RET, BTI placement,
build attribute emission, etc, so it make sense committing it
separately in order to unblock the aforementioned parts, which can
proceed concurrently.

This patch adds a few member functions to `ARMFunctionInfo`, which are currently
unused, therefore there is no testing for them at the moment. This code is
tested in follow-up PAC/BTI code gen patches.

This patch is part of a series that adds support for the PACBTI-M extension of
the Armv8.1-M architecture, as detailed here:

https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension

The PACBTI-M specification can be found in the Armv8-M Architecture Reference
Manual:

https://developer.arm.com/documentation/ddi0553/latest

The following people contributed to this patch:

- Momchil Velikov
- Ties Stuij

Reviewed By: danielkiss

Differential Revision: https://reviews.llvm.org/D112423
This commit is contained in:
Ties Stuij 2021-12-01 10:48:30 +00:00
parent ab2611d099
commit c12c7a84b0
2 changed files with 81 additions and 1 deletions

View File

@ -13,8 +13,63 @@ using namespace llvm;
void ARMFunctionInfo::anchor() {}
static bool GetBranchTargetEnforcement(MachineFunction &MF) {
const auto &Subtarget = MF.getSubtarget<ARMSubtarget>();
if (!Subtarget.isMClass() || !Subtarget.hasV7Ops())
return false;
const Function &F = MF.getFunction();
if (!F.hasFnAttribute("branch-target-enforcement")) {
if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
F.getParent()->getModuleFlag("branch-target-enforcement")))
return BTE->getZExtValue();
return false;
}
const StringRef BTIEnable =
F.getFnAttribute("branch-target-enforcement").getValueAsString();
assert(BTIEnable.equals_insensitive("true") ||
BTIEnable.equals_insensitive("false"));
return BTIEnable.equals_insensitive("true");
}
// The pair returns values for the ARMFunctionInfo members
// SignReturnAddress and SignReturnAddressAll respectively.
static std::pair<bool, bool> GetSignReturnAddress(const Function &F) {
if (!F.hasFnAttribute("sign-return-address")) {
const Module &M = *F.getParent();
if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
M.getModuleFlag("sign-return-address"))) {
if (Sign->getZExtValue()) {
if (const auto *All = mdconst::extract_or_null<ConstantInt>(
M.getModuleFlag("sign-return-address-all")))
return {true, All->getZExtValue()};
return {true, false};
}
}
return {false, false};
}
StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString();
if (Scope.equals("none"))
return {false, false};
if (Scope.equals("all"))
return {true, true};
assert(Scope.equals("non-leaf"));
return {true, false};
}
ARMFunctionInfo::ARMFunctionInfo(MachineFunction &MF)
: isThumb(MF.getSubtarget<ARMSubtarget>().isThumb()),
hasThumb2(MF.getSubtarget<ARMSubtarget>().hasThumb2()),
IsCmseNSEntry(MF.getFunction().hasFnAttribute("cmse_nonsecure_entry")),
IsCmseNSCall(MF.getFunction().hasFnAttribute("cmse_nonsecure_call")) {}
IsCmseNSCall(MF.getFunction().hasFnAttribute("cmse_nonsecure_call")),
BranchTargetEnforcement(GetBranchTargetEnforcement(MF)) {
const auto &Subtarget = MF.getSubtarget<ARMSubtarget>();
if (Subtarget.isMClass() && Subtarget.hasV7Ops())
std::tie(SignReturnAddress, SignReturnAddressAll) =
GetSignReturnAddress(MF.getFunction());
}

View File

@ -142,6 +142,17 @@ class ARMFunctionInfo : public MachineFunctionInfo {
/// con/destructors).
bool PreservesR0 = false;
/// True if the function should sign its return address.
bool SignReturnAddress = false;
/// True if the fucntion should sign its return address, even if LR is not
/// saved.
bool SignReturnAddressAll = false;
/// True if BTI instructions should be placed at potential indirect jump
/// destinations.
bool BranchTargetEnforcement = false;
public:
ARMFunctionInfo() = default;
@ -268,6 +279,20 @@ public:
void setPreservesR0() { PreservesR0 = true; }
bool getPreservesR0() const { return PreservesR0; }
bool shouldSignReturnAddress() const {
return shouldSignReturnAddress(LRSpilled);
}
bool shouldSignReturnAddress(bool SpillsLR) const {
if (!SignReturnAddress)
return false;
if (SignReturnAddressAll)
return true;
return LRSpilled;
}
bool branchTargetEnforcement() const { return BranchTargetEnforcement; }
};
} // end namespace llvm