llvm.org GIT mirror llvm / 5ebefb8
[inlineasm] Propagate operand constraints to the backend When SelectionDAGISel transforms a node representing an inline asm block, memory constraint information is not preserved. This can cause constraints to be broken when a memory offset is of the form: offset + frame index when the frame is resolved. By propagating the constraints all the way to the backend, targets can enforce memory operands of inline assembly to conform to their constraints. For MIPSR6, some instructions had their offsets reduced to 9 bits from 16 bits such as ll/sc. This becomes problematic when using inline assembly to perform atomic operations, as an offset can generated that is too big to encode in the instruction. Reviewers: dsanders, vkalintris Differential Review: https://reviews.llvm.org/D21615 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275786 91177308-0d34-0410-b5e6-96231b3b80d8 Simon Dardis 4 years ago
5 changed file(s) with 133 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
271271 return Kind | (NumOps << 3);
272272 }
273273
274 static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;}
275 static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; }
276 static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; }
277 static bool isRegDefEarlyClobberKind(unsigned Flag) {
278 return getKind(Flag) == Kind_RegDefEarlyClobber;
279 }
280 static bool isClobberKind(unsigned Flag) {
281 return getKind(Flag) == Kind_Clobber;
282 }
283
274284 /// getFlagWordForMatchingOp - Augment an existing flag word returned by
275285 /// getFlagWord with information indicating that this input operand is tied
276286 /// to a previous output operand.
289299 static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC) {
290300 // Store RC + 1, reserve the value 0 to mean 'no register class'.
291301 ++RC;
302 assert(!isImmKind(InputFlag) && "Immediates cannot have a register class");
303 assert(!isMemKind(InputFlag) && "Memory operand cannot have a register class");
292304 assert(RC <= 0x7fff && "Too large register class ID");
293305 assert((InputFlag & ~0xffff) == 0 && "High bits already contain data");
294306 return InputFlag | (RC << 16);
297309 /// Augment an existing flag word returned by getFlagWord with the constraint
298310 /// code for a memory constraint.
299311 static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) {
312 assert(isMemKind(InputFlag) && "InputFlag is not a memory constraint!");
300313 assert(Constraint <= 0x7fff && "Too large a memory constraint ID");
301314 assert(Constraint <= Constraints_Max && "Unknown constraint ID");
302315 assert((InputFlag & ~0xffff) == 0 && "High bits already contain data");
310323
311324 static unsigned getKind(unsigned Flags) {
312325 return Flags & 7;
313 }
314
315 static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;}
316 static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; }
317 static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; }
318 static bool isRegDefEarlyClobberKind(unsigned Flag) {
319 return getKind(Flag) == Kind_RegDefEarlyClobber;
320 }
321 static bool isClobberKind(unsigned Flag) {
322 return getKind(Flag) == Kind_Clobber;
323326 }
324327
325328 static unsigned getMemoryConstraintID(unsigned Flag) {
12001200
12011201 unsigned Flag = getOperand(FlagIdx).getImm();
12021202 unsigned RCID;
1203 if (InlineAsm::hasRegClassConstraint(Flag, RCID))
1203 if ((InlineAsm::getKind(Flag) == InlineAsm::Kind_RegUse ||
1204 InlineAsm::getKind(Flag) == InlineAsm::Kind_RegDef ||
1205 InlineAsm::getKind(Flag) == InlineAsm::Kind_RegDefEarlyClobber) &&
1206 InlineAsm::hasRegClassConstraint(Flag, RCID))
12041207 return TRI->getRegClass(RCID);
12051208
12061209 // Assume that all registers in a memory operand are pointers.
18251828 }
18261829
18271830 unsigned RCID = 0;
1828 if (InlineAsm::hasRegClassConstraint(Flag, RCID)) {
1831 if (!InlineAsm::isImmKind(Flag) && !InlineAsm::isMemKind(Flag) &&
1832 InlineAsm::hasRegClassConstraint(Flag, RCID)) {
18291833 if (TRI) {
18301834 OS << ':' << TRI->getRegClassName(TRI->getRegClass(RCID));
18311835 } else
18321836 OS << ":RC" << RCID;
1837 }
1838
1839 if (InlineAsm::isMemKind(Flag)) {
1840 unsigned MCID = InlineAsm::getMemoryConstraintID(Flag);
1841 switch (MCID) {
1842 case InlineAsm::Constraint_es: OS << ":es"; break;
1843 case InlineAsm::Constraint_i: OS << ":i"; break;
1844 case InlineAsm::Constraint_m: OS << ":m"; break;
1845 case InlineAsm::Constraint_o: OS << ":o"; break;
1846 case InlineAsm::Constraint_v: OS << ":v"; break;
1847 case InlineAsm::Constraint_Q: OS << ":Q"; break;
1848 case InlineAsm::Constraint_R: OS << ":R"; break;
1849 case InlineAsm::Constraint_S: OS << ":S"; break;
1850 case InlineAsm::Constraint_T: OS << ":T"; break;
1851 case InlineAsm::Constraint_Um: OS << ":Um"; break;
1852 case InlineAsm::Constraint_Un: OS << ":Un"; break;
1853 case InlineAsm::Constraint_Uq: OS << ":Uq"; break;
1854 case InlineAsm::Constraint_Us: OS << ":Us"; break;
1855 case InlineAsm::Constraint_Ut: OS << ":Ut"; break;
1856 case InlineAsm::Constraint_Uv: OS << ":Uv"; break;
1857 case InlineAsm::Constraint_Uy: OS << ":Uy"; break;
1858 case InlineAsm::Constraint_X: OS << ":X"; break;
1859 case InlineAsm::Constraint_Z: OS << ":Z"; break;
1860 case InlineAsm::Constraint_ZC: OS << ":ZC"; break;
1861 case InlineAsm::Constraint_Zy: OS << ":Zy"; break;
1862 default: OS << ":?"; break;
1863 }
18331864 }
18341865
18351866 unsigned TiedTo = 0;
19491949
19501950 // Otherwise, this is a memory operand. Ask the target to select it.
19511951 std::vector SelOps;
1952 if (SelectInlineAsmMemoryOperand(InOps[i+1],
1953 InlineAsm::getMemoryConstraintID(Flags),
1954 SelOps))
1952 unsigned ConstraintID = InlineAsm::getMemoryConstraintID(Flags);
1953 if (SelectInlineAsmMemoryOperand(InOps[i+1], ConstraintID, SelOps))
19551954 report_fatal_error("Could not match memory address. Inline asm"
19561955 " failure!");
19571956
19581957 // Add this to the output node.
19591958 unsigned NewFlags =
19601959 InlineAsm::getFlagWord(InlineAsm::Kind_Mem, SelOps.size());
1960 NewFlags = InlineAsm::getFlagWordForMem(NewFlags, ConstraintID);
19611961 Ops.push_back(CurDAG->getTargetConstant(NewFlags, DL, MVT::i32));
19621962 Ops.insert(Ops.end(), SelOps.begin(), SelOps.end());
19631963 i += 2;
5959 return &Mips::GPR64RegClass;
6060 }
6161
62 /// Get the size of the offset supported by the given load/store.
62 /// Get the size of the offset supported by the given load/store/inline asm.
6363 /// The result includes the effects of any scale factors applied to the
6464 /// instruction immediate.
65 static inline unsigned getLoadStoreOffsetSizeInBits(const unsigned Opcode) {
65 static inline unsigned getLoadStoreOffsetSizeInBits(const unsigned Opcode,
66 MachineOperand MO) {
6667 switch (Opcode) {
6768 case Mips::LD_B:
6869 case Mips::ST_B:
7677 case Mips::LD_D:
7778 case Mips::ST_D:
7879 return 10 + 3 /* scale factor */;
80 case Mips::LL:
81 case Mips::LL64:
82 case Mips::LLD:
83 case Mips::LLE:
84 case Mips::SC:
85 case Mips::SC64:
86 case Mips::SCD:
87 case Mips::SCE:
88 return 16;
89 case Mips::LLE_MM:
90 case Mips::LLE_MMR6:
91 case Mips::LL_MM:
92 case Mips::SCE_MM:
93 case Mips::SCE_MMR6:
94 case Mips::SC_MM:
95 return 12;
96 case Mips::LL64_R6:
97 case Mips::LL_R6:
98 case Mips::LLD_R6:
99 case Mips::SC64_R6:
100 case Mips::SCD_R6:
101 case Mips::SC_R6:
102 return 9;
103 case Mips::INLINEASM: {
104 unsigned ConstraintID = InlineAsm::getMemoryConstraintID(MO.getImm());
105 switch (ConstraintID) {
106 case InlineAsm::Constraint_ZC: {
107 const MipsSubtarget &Subtarget = MO.getParent()
108 ->getParent()
109 ->getParent()
110 ->getSubtarget();
111 if (Subtarget.inMicroMipsMode())
112 return 12;
113
114 if (Subtarget.hasMips32r6())
115 return 9;
116
117 return 16;
118 }
119 default:
120 return 16;
121 }
122 }
79123 default:
80124 return 16;
81125 }
165209 // Make sure Offset fits within the field available.
166210 // For MSA instructions, this is a 10-bit signed immediate (scaled by
167211 // element size), otherwise it is a 16-bit signed immediate.
168 unsigned OffsetBitSize = getLoadStoreOffsetSizeInBits(MI.getOpcode());
212 unsigned OffsetBitSize =
213 getLoadStoreOffsetSizeInBits(MI.getOpcode(), MI.getOperand(OpNo - 1));
169214 unsigned OffsetAlign = getLoadStoreOffsetAlign(MI.getOpcode());
170215
171216 if (OffsetBitSize < 16 && isInt<16>(Offset) &&
0 ; RUN: llc -march=mips -mcpu=mips32r6 < %s | FileCheck %s --check-prefixes=ALL,R6
1 ; RUN: llc -march=mips -mcpu=mips64r6 -target-abi=n64 < %s | FileCheck %s --check-prefixes=ALL,R6
2 ; RUN: llc -march=mips -mcpu=mips32 < %s | FileCheck %s --check-prefixes=ALL,PRER6
3 ; RUN: llc -march=mips -mcpu=mips64 -target-abi=n64 < %s | FileCheck %s --check-prefixes=ALL,PRER6
4
5
6 %struct.anon = type { [63 x i32], i32, i32 }
7
8 define i32 @Atomic() {
9 ; CHECK-LABEL: Atomic:
10 entry:
11 %s = alloca %struct.anon, align 4
12 %0 = bitcast %struct.anon* %s to i8*
13 %count = getelementptr inbounds %struct.anon, %struct.anon* %s, i64 0, i32 1
14 store i32 0, i32* %count, align 4
15 ; R6: addiu $[[R0:[0-9a-z]+]], $sp, {{[0-9]+}}
16
17 ; ALL: #APP
18
19 ; R6: ll ${{[0-9a-z]+}}, 0($[[R0]])
20 ; R6: sc ${{[0-9a-z]+}}, 0($[[R0]])
21
22 ; PRER6: ll ${{[0-9a-z]+}}, {{[0-9]+}}(${{[0-9a-z]+}})
23 ; PRER6: sc ${{[0-9a-z]+}}, {{[0-9]+}}(${{[0-9a-z]+}})
24
25 ; ALL: #NO_APP
26
27 %1 = call { i32, i32 } asm sideeffect ".set push\0A.set noreorder\0A1:\0All $0, $2\0Aaddu $1, $0, $3\0Asc $1, $2\0Abeqz $1, 1b\0Aaddu $1, $0, $3\0A.set pop\0A", "=&r,=&r,=*^ZC,Ir,*^ZC,~{memory},~{$1}"(i32* %count, i32 10, i32* %count)
28 %asmresult1.i = extractvalue { i32, i32 } %1, 1
29 %cmp = icmp ne i32 %asmresult1.i, 10
30 %conv = zext i1 %cmp to i32
31 %call2 = call i32 @f(i32 signext %conv)
32 ret i32 %call2
33 }
34
35 declare i32 @f(i32 signext)