Skip to content

Commit 041f9c2

Browse files
authored
Workaround variable+offsets in DMD-style assembly sometimes generating invalid assembly. (#4632)
1 parent 4cff23d commit 041f9c2

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

gen/asm-x86.h

+41-4
Original file line numberDiff line numberDiff line change
@@ -2862,6 +2862,9 @@ struct AsmProcessor {
28622862
}
28632863
operand = &operands[i];
28642864

2865+
// This is used only in the case of `operand->cls` being `Opr_Mem`.
2866+
bool hasConstDisplacement = false;
2867+
28652868
switch (operand->cls) {
28662869
case Opr_Immediate:
28672870
// for implementing offset:
@@ -2959,9 +2962,13 @@ struct AsmProcessor {
29592962
"branching instruction");
29602963
}
29612964
}
2962-
if ((operand->segmentPrefix != Reg_Invalid &&
2963-
operand->symbolDisplacement.length == 0) ||
2964-
operand->constDisplacement) {
2965+
2966+
// We make note of this for later on, as if a const-displacement is in play we
2967+
// may need to change the asm template to avoid it expanding to an invalid syntax.
2968+
hasConstDisplacement = (operand->segmentPrefix != Reg_Invalid &&
2969+
operand->symbolDisplacement.length == 0) ||
2970+
operand->constDisplacement;
2971+
if (hasConstDisplacement) {
29652972
insnTemplate << operand->constDisplacement;
29662973
if (operand->symbolDisplacement.length) {
29672974
insnTemplate << '+';
@@ -3057,6 +3064,29 @@ struct AsmProcessor {
30573064
// addOperand2("${", ":c}", Arg_Pointer, e,
30583065
// asmcode);
30593066
} else {
3067+
// We don't know ahead of time what kind of memory operand will be generated for
3068+
// our template: it could be a symbolic reference, or a Scale-Index-Base with or without
3069+
// an offset. So, if we have a const-displacement of 4, it could look like one of:
3070+
// `4+someGlobalVariable`, or `4+8(%ebp)`, or `4+(%ebp)`.
3071+
// Notice how that last possibility is an invalid syntax, it should be `4(%ebp)`.
3072+
// But, if we removed the `+`, then the other possibilities would become invalid or wrong.
3073+
// We don't know which form will be generated, but we can force the third possibility to
3074+
// be like the second possibility.
3075+
//
3076+
// For x86 assembly templates, memory operands can be marked with the `H` modifier, which
3077+
// unconditionally adds an offset of 8 to the memory operand.
3078+
// If we subtract 8 from our const-displacement, then we can use the `H` modifier to ensure
3079+
// that we always end up with a valid syntax for a memory operand with an offset.
3080+
// So, we do just that when we have const-displacement in play.
3081+
// (Only for non-naked asm, as this isn't an issue for naked asm.)
3082+
//
3083+
// See also: https://lists.llvm.org/pipermail/llvm-dev/2017-August/116244.html
3084+
const auto forceLeadingDisplacement = hasConstDisplacement && !sc->func->isNaked();
3085+
if (forceLeadingDisplacement) {
3086+
// Subtract 8 from our const-displacement, and prepare to add the 8 from the `H` modifier.
3087+
insnTemplate << "-8+";
3088+
}
3089+
30603090
if (use_star) {
30613091
insnTemplate << '*';
30623092
use_star = false;
@@ -3069,7 +3099,14 @@ struct AsmProcessor {
30693099
e->type = tt;
30703100
}
30713101

3072-
addOperand(fmt, Arg_Memory, e, asmcode, mode);
3102+
if (forceLeadingDisplacement) {
3103+
// We have a const-displacement in play, so we add the `H` modifier, as described earlier.
3104+
insnTemplate << "${" << "<<" << (mode == Mode_Input ? "in" : "out")
3105+
<< asmcode->args.size() << ">>" << ":H}";
3106+
asmcode->args.push_back(AsmArg(Arg_Memory, e, mode));
3107+
} else {
3108+
addOperand(fmt, Arg_Memory, e, asmcode, mode);
3109+
}
30733110
}
30743111
}
30753112
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// REQUIRES: target_X86
2+
3+
// RUN: %ldc -mtriple=i686-pc-windows-msvc -O -output-s -of=%t.s %s && FileCheck %s < %t.s
4+
5+
uint getHighHalfWithoutDisplacement(ulong value)
6+
{
7+
asm
8+
{
9+
// CHECK: movl 4(%esp), %eax
10+
mov EAX, dword ptr [value + 4];
11+
}
12+
}
13+
14+
uint getHighHalfWithDisplacement(uint value1, uint value2)
15+
{
16+
asm
17+
{
18+
// CHECK: movl -2(%ebp), %eax
19+
mov EAX, word ptr 2[value1];
20+
}
21+
}
22+
23+
extern(C) __gshared ulong someGlobalVariable;
24+
25+
uint getHighHalfOfGlobal(ulong value)
26+
{
27+
asm
28+
{
29+
// CHECK: movl ((4+(-8))+_someGlobalVariable)+8, %eax
30+
mov EAX, dword ptr [someGlobalVariable + 4];
31+
}
32+
}
33+
34+
void foo()
35+
{
36+
align(32) uint[4] a;
37+
asm pure nothrow @nogc
38+
{
39+
// CHECK: movl %ebx, 4(%esp)
40+
mov a+4, EBX;
41+
}
42+
}

0 commit comments

Comments
 (0)