[llvm-bugs] [Bug 45268] New: Implement graceful fallback in the case of unsupported instructions
via llvm-bugs
llvm-bugs at lists.llvm.org
Sat Mar 21 01:25:28 PDT 2020
https://bugs.llvm.org/show_bug.cgi?id=45268
Bug ID: 45268
Summary: Implement graceful fallback in the case of unsupported
instructions
Product: clang
Version: unspecified
Hardware: PC
OS: Linux
Status: NEW
Severity: enhancement
Priority: P
Component: LLVM Codegen
Assignee: unassignedclangbugs at nondot.org
Reporter: kolan_n at mail.ru
CC: llvm-bugs at lists.llvm.org, neeilans at live.com,
richard-llvm at metafoo.co.uk
Patches (for example https://reviews.llvm.org/D76458#) introduce insertion of
some instructions (for example, LFENCE, which is a SSE2 instruction) not
available for all CPUs. It may cause problems:
* developers can enable these flags themselves;
* developers of binary dependencies can enable the flags themselves;
* this may be a result of developers of build tooling enabling the flags by
default.
This will essentially cause all the developers to drop support of the hardware
without these instructions. Not necessarily because they want, but because they
have to.
For example, supporting legacy hardware may require them have separate builds
for it or even building all the dependencies themselves, that may be
inaceptible.
The solution of course is enabling instructions opportunistically.
1. the compiler writes additional data into a special section, containing a
table. A record in it has the following structure
enum class InstructionNeeded: uint64_t{
....
};
struct CPUFeature{
bool required: 1; // describes if the code by default requires the feature
enabled
uint16_t id: 15; // feature ID
InstructionNeeded instruction; // instructiins needed for the feature
uint32_t pointers; // offset of a data structure describing pkaces that must
be patched
};
Address collection contains a set of addresses to be patched. No patches are
stored, they are computed by the patcher.
Either runtime or dynamic linker check this section, and do the necessary
patches.
2. A linker/runtime (let's further call it "linker") reads the CPUID and
detects the features of the CPU.
3. The linker reads the table and determines which patches it should apply.
There are 2 kinds of patches, upgrade ones and downgrade ones.
InstructionNeeded cpuFeatures = getFromCPUID();
uint8_t featureSupported = ((cpuFeatures & feature.instructions) ==
feature.instructions);
enum class Action: uint8_t{
noDowngradeNeeded = 0b00,
downgrade = 0b01,
upgrade = 0b10,
noUpgradeNeeded = 0b11
}
Action actionNeeded = static_cast<Action>((featureSupported<<1) |
feature.required);
switch(actionNeeded){
case Action::downgrade:
doDowngrade(feature); # replace newer instructions with older ones
break;
case Action::upgrade:
doUpgrade(feature); # replace older instructions with newer ones.
break;
}
4. When applying a patch the loader reads bytes by the offset, parses them into
instructions, computes the needed replacements and writes them into the memory.
5. There can also be an API, allowing trigger applying the patches
programmatically. This for example can allow applications to enable/disable
protections based on values in their config files.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200321/5a9efbe2/attachment-0001.html>
More information about the llvm-bugs
mailing list