[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