<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - Implement graceful fallback in the case of unsupported instructions"
href="https://bugs.llvm.org/show_bug.cgi?id=45268">45268</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>Implement graceful fallback in the case of unsupported instructions
</td>
</tr>
<tr>
<th>Product</th>
<td>clang
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>LLVM Codegen
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>kolan_n@mail.ru
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org, neeilans@live.com, richard-llvm@metafoo.co.uk
</td>
</tr></table>
<p>
<div>
<pre>Patches (for example <a href="https://reviews.llvm.org/D76458">https://reviews.llvm.org/D76458</a>#) 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.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>