llvm.org GIT mirror llvm / 7839b00
X86: Rework inline asm integer register specification. This is a new version of http://reviews.llvm.org/D10260. It turned out that when you specify an integer register in inline asm on x86 you get the register of the required type size back. That means that X86TargetLowering::getRegForInlineAsmConstraint() has to accept any of the integer registers and adapt its size to the given target size which may be any 8/16/32/64 bit sized type. Surprisingly that means given a constraint of "{ax}" and a type of MVT::F32 we need to return X86::EAX. This change makes this face explicit, the previous code seemed like working by accident because there it never returned an error once a register was found. On the other hand this rewrite allows to actually return errors for invalid situations like requesting an integer register for an i128 type. Related to rdar://21042280 Differential Revision: http://reviews.llvm.org/D10813 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241002 91177308-0d34-0410-b5e6-96231b3b80d8 Matthias Braun 5 years ago
5 changed file(s) with 203 addition(s) and 73 deletion(s). Raw diff Collapse all Expand all
2557925579 // Otherwise, check to see if this is a register class of the wrong value
2558025580 // type. For example, we want to map "{ax},i32" -> {eax}, we don't want it to
2558125581 // turn into {ax},{dx}.
25582 if (Res.second->hasType(VT))
25582 // MVT::Other is used to specify clobber names.
25583 if (Res.second->hasType(VT) || VT == MVT::Other)
2558325584 return Res; // Correct type already, nothing to do.
2558425585
25585 // All of the single-register GCC register classes map their values onto
25586 // 16-bit register pieces "ax","dx","cx","bx","si","di","bp","sp". If we
25587 // really want an 8-bit or 32-bit register, map to the appropriate register
25588 // class and return the appropriate register.
25589 if (Res.second == &X86::GR16RegClass) {
25590 if (VT == MVT::i8 || VT == MVT::i1) {
25591 unsigned DestReg = 0;
25592 switch (Res.first) {
25593 default: break;
25594 case X86::AX: DestReg = X86::AL; break;
25595 case X86::DX: DestReg = X86::DL; break;
25596 case X86::CX: DestReg = X86::CL; break;
25597 case X86::BX: DestReg = X86::BL; break;
25598 }
25599 if (DestReg) {
25600 Res.first = DestReg;
25601 Res.second = &X86::GR8RegClass;
25602 }
25603 } else if (VT == MVT::i32 || VT == MVT::f32) {
25604 unsigned DestReg = 0;
25605 switch (Res.first) {
25606 default: break;
25607 case X86::AX: DestReg = X86::EAX; break;
25608 case X86::DX: DestReg = X86::EDX; break;
25609 case X86::CX: DestReg = X86::ECX; break;
25610 case X86::BX: DestReg = X86::EBX; break;
25611 case X86::SI: DestReg = X86::ESI; break;
25612 case X86::DI: DestReg = X86::EDI; break;
25613 case X86::BP: DestReg = X86::EBP; break;
25614 case X86::SP: DestReg = X86::ESP; break;
25615 }
25616 if (DestReg) {
25617 Res.first = DestReg;
25618 Res.second = &X86::GR32RegClass;
25619 }
25620 } else if (VT == MVT::i64 || VT == MVT::f64) {
25621 unsigned DestReg = 0;
25622 switch (Res.first) {
25623 default: break;
25624 case X86::AX: DestReg = X86::RAX; break;
25625 case X86::DX: DestReg = X86::RDX; break;
25626 case X86::CX: DestReg = X86::RCX; break;
25627 case X86::BX: DestReg = X86::RBX; break;
25628 case X86::SI: DestReg = X86::RSI; break;
25629 case X86::DI: DestReg = X86::RDI; break;
25630 case X86::BP: DestReg = X86::RBP; break;
25631 case X86::SP: DestReg = X86::RSP; break;
25632 }
25633 if (DestReg) {
25634 Res.first = DestReg;
25635 Res.second = &X86::GR64RegClass;
25636 }
25637 }
25638 } else if (Res.second == &X86::FR32RegClass ||
25639 Res.second == &X86::FR64RegClass ||
25640 Res.second == &X86::VR128RegClass ||
25641 Res.second == &X86::VR256RegClass ||
25642 Res.second == &X86::FR32XRegClass ||
25643 Res.second == &X86::FR64XRegClass ||
25644 Res.second == &X86::VR128XRegClass ||
25645 Res.second == &X86::VR256XRegClass ||
25646 Res.second == &X86::VR512RegClass) {
25586 // Get a matching integer of the correct size. i.e. "ax" with MVT::32 should
25587 // return "eax". This should even work for things like getting 64bit integer
25588 // registers when given an f64 type.
25589 const TargetRegisterClass *Class = Res.second;
25590 if (Class == &X86::GR8RegClass || Class == &X86::GR16RegClass ||
25591 Class == &X86::GR32RegClass || Class == &X86::GR64RegClass) {
25592 unsigned Size = VT.getSizeInBits();
25593 MVT::SimpleValueType SimpleTy = Size == 1 || Size == 8 ? MVT::i8
25594 : Size == 16 ? MVT::i16
25595 : Size == 32 ? MVT::i32
25596 : Size == 64 ? MVT::i64
25597 : MVT::Other;
25598 unsigned DestReg = getX86SubSuperRegisterOrZero(Res.first, SimpleTy);
25599 if (DestReg > 0) {
25600 Res.first = DestReg;
25601 Res.second = SimpleTy == MVT::i8 ? &X86::GR8RegClass
25602 : SimpleTy == MVT::i16 ? &X86::GR16RegClass
25603 : SimpleTy == MVT::i32 ? &X86::GR32RegClass
25604 : &X86::GR64RegClass;
25605 assert(Res.second->contains(Res.first) && "Register in register class");
25606 } else {
25607 // No register found/type mismatch.
25608 Res.first = 0;
25609 Res.second = nullptr;
25610 }
25611 } else if (Class == &X86::FR32RegClass || Class == &X86::FR64RegClass ||
25612 Class == &X86::VR128RegClass || Class == &X86::VR256RegClass ||
25613 Class == &X86::FR32XRegClass || Class == &X86::FR64XRegClass ||
25614 Class == &X86::VR128XRegClass || Class == &X86::VR256XRegClass ||
25615 Class == &X86::VR512RegClass) {
2564725616 // Handle references to XMM physical registers that got mapped into the
2564825617 // wrong class. This can happen with constraints like {xmm0} where the
2564925618 // target independent register mapper will just pick the first match it can
2565925628 Res.second = &X86::VR256RegClass;
2566025629 else if (X86::VR512RegClass.hasType(VT))
2566125630 Res.second = &X86::VR512RegClass;
25631 else {
25632 // Type mismatch and not a clobber: Return an error;
25633 Res.first = 0;
25634 Res.second = nullptr;
25635 }
2566225636 }
2566325637
2566425638 return Res;
597597 }
598598
599599 namespace llvm {
600 unsigned getX86SubSuperRegister(unsigned Reg, MVT::SimpleValueType VT,
601 bool High) {
600 unsigned getX86SubSuperRegisterOrZero(unsigned Reg, MVT::SimpleValueType VT,
601 bool High) {
602602 switch (VT) {
603 default: llvm_unreachable("Unexpected VT");
603 default: return 0;
604604 case MVT::i8:
605605 if (High) {
606606 switch (Reg) {
624624 }
625625 } else {
626626 switch (Reg) {
627 default: llvm_unreachable("Unexpected register");
627 default: return 0;
628628 case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX:
629629 return X86::AL;
630630 case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX:
661661 }
662662 case MVT::i16:
663663 switch (Reg) {
664 default: llvm_unreachable("Unexpected register");
664 default: return 0;
665665 case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX:
666666 return X86::AX;
667667 case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX:
697697 }
698698 case MVT::i32:
699699 switch (Reg) {
700 default: llvm_unreachable("Unexpected register");
700 default: return 0;
701701 case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX:
702702 return X86::EAX;
703703 case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX:
733733 }
734734 case MVT::i64:
735735 switch (Reg) {
736 default: llvm_unreachable("Unexpected register");
736 default: return 0;
737737 case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX:
738738 return X86::RAX;
739739 case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX:
770770 }
771771 }
772772
773 unsigned getX86SubSuperRegister(unsigned Reg, MVT::SimpleValueType VT,
774 bool High) {
775 unsigned Res = getX86SubSuperRegisterOrZero(Reg, VT, High);
776 if (Res == 0)
777 llvm_unreachable("Unexpected register or VT");
778 return Res;
779 }
780
773781 unsigned get512BitSuperRegister(unsigned Reg) {
774782 if (Reg >= X86::XMM0 && Reg <= X86::XMM31)
775783 return X86::ZMM0 + (Reg - X86::XMM0);
127127 unsigned getSlotSize() const { return SlotSize; }
128128 };
129129
130 // getX86SubSuperRegister - X86 utility function. It returns the sub or super
131 // register of a specific X86 register.
132 // e.g. getX86SubSuperRegister(X86::EAX, MVT::i16) return X86:AX
130 /// Returns the sub or super register of a specific X86 register.
131 /// e.g. getX86SubSuperRegister(X86::EAX, MVT::i16) returns X86::AX.
132 /// Aborts on error.
133133 unsigned getX86SubSuperRegister(unsigned, MVT::SimpleValueType, bool High=false);
134
135 /// Returns the sub or super register of a specific X86 register.
136 /// Like getX86SubSuperRegister() but returns 0 on error.
137 unsigned getX86SubSuperRegisterOrZero(unsigned, MVT::SimpleValueType,
138 bool High = false);
134139
135140 //get512BitRegister - X86 utility - returns 512-bit super register
136141 unsigned get512BitSuperRegister(unsigned Reg);
0 ; RUN: llc -o - %s -no-integrated-as | FileCheck %s
1 target triple = "x86_64--"
2
3 ; Allow to specify any of the 8/16/32/64 register names interchangeably in
4 ; constraints
5
6 ; Produced by C-programs like this:
7 ; void foo(int p) { register int reg __asm__("r8") = p;
8 ; __asm__ __volatile__("# REG: %0" : : "r" (reg)); }
9
10 ; CHECK-LABEL: reg64_as_32:
11 ; CHECK: # REG: %r8d
12 define void @reg64_as_32(i32 %p) {
13 call void asm sideeffect "# REG: $0", "{r8}"(i32 %p)
14 ret void
15 }
16
17 ; CHECK-LABEL: reg64_as_32_float:
18 ; CHECK: # REG: %r8d
19 define void @reg64_as_32_float(float %p) {
20 call void asm sideeffect "# REG: $0", "{r8}"(float %p)
21 ret void
22 }
23
24 ; CHECK-LABEL: reg64_as_16:
25 ; CHECK: # REG: %r9w
26 define void @reg64_as_16(i16 %p) {
27 call void asm sideeffect "# REG: $0", "{r9}"(i16 %p)
28 ret void
29 }
30
31 ; CHECK-LABEL: reg64_as_8:
32 ; CHECK: # REG: %bpl
33 define void @reg64_as_8(i8 %p) {
34 call void asm sideeffect "# REG: $0", "{rbp}"(i8 %p)
35 ret void
36 }
37
38 ; CHECK-LABEL: reg32_as_16:
39 ; CHECK: # REG: %r15w
40 define void @reg32_as_16(i16 %p) {
41 call void asm sideeffect "# REG: $0", "{r15d}"(i16 %p)
42 ret void
43 }
44
45 ; CHECK-LABEL: reg32_as_8:
46 ; CHECK: # REG: %r12b
47 define void @reg32_as_8(i8 %p) {
48 call void asm sideeffect "# REG: $0", "{r12d}"(i8 %p)
49 ret void
50 }
51
52 ; CHECK-LABEL: reg16_as_8:
53 ; CHECK: # REG: %cl
54 define void @reg16_as_8(i8 %p) {
55 call void asm sideeffect "# REG: $0", "{cx}"(i8 %p)
56 ret void
57 }
58
59 ; CHECK-LABEL: reg32_as_64:
60 ; CHECK: # REG: %rbp
61 define void @reg32_as_64(i64 %p) {
62 call void asm sideeffect "# REG: $0", "{ebp}"(i64 %p)
63 ret void
64 }
65
66 ; CHECK-LABEL: reg32_as_64_float:
67 ; CHECK: # REG: %rbp
68 define void @reg32_as_64_float(double %p) {
69 call void asm sideeffect "# REG: $0", "{ebp}"(double %p)
70 ret void
71 }
72
73 ; CHECK-LABEL: reg16_as_64:
74 ; CHECK: # REG: %r13
75 define void @reg16_as_64(i64 %p) {
76 call void asm sideeffect "# REG: $0", "{r13w}"(i64 %p)
77 ret void
78 }
79
80 ; CHECK-LABEL: reg16_as_64_float:
81 ; CHECK: # REG: %r13
82 define void @reg16_as_64_float(double %p) {
83 call void asm sideeffect "# REG: $0", "{r13w}"(double %p)
84 ret void
85 }
86
87 ; CHECK-LABEL: reg8_as_64:
88 ; CHECK: # REG: %rax
89 define void @reg8_as_64(i64 %p) {
90 call void asm sideeffect "# REG: $0", "{al}"(i64 %p)
91 ret void
92 }
93
94 ; CHECK-LABEL: reg8_as_64_float:
95 ; CHECK: # REG: %rax
96 define void @reg8_as_64_float(double %p) {
97 call void asm sideeffect "# REG: $0", "{al}"(double %p)
98 ret void
99 }
100
101 ; CHECK-LABEL: reg16_as_32:
102 ; CHECK: # REG: %r11d
103 define void @reg16_as_32(i32 %p) {
104 call void asm sideeffect "# REG: $0", "{r11w}"(i32 %p)
105 ret void
106 }
107
108 ; CHECK-LABEL: reg16_as_32_float:
109 ; CHECK: # REG: %r11d
110 define void @reg16_as_32_float(float %p) {
111 call void asm sideeffect "# REG: $0", "{r11w}"(float %p)
112 ret void
113 }
114
115 ; CHECK-LABEL: reg8_as_32:
116 ; CHECK: # REG: %r9d
117 define void @reg8_as_32(i32 %p) {
118 call void asm sideeffect "# REG: $0", "{r9b}"(i32 %p)
119 ret void
120 }
121
122 ; CHECK-LABEL: reg8_as_32_float:
123 ; CHECK: # REG: %r9d
124 define void @reg8_as_32_float(float %p) {
125 call void asm sideeffect "# REG: $0", "{r9b}"(float %p)
126 ret void
127 }
128
129 ; CHECK-LABEL: reg8_as_16:
130 ; CHECK: # REG: %di
131 define void @reg8_as_16(i16 %p) {
132 call void asm sideeffect "# REG: $0", "{dil}"(i16 %p)
133 ret void
134 }
0 ; RUN: not llc -o /dev/null %s 2>&1 | FileCheck %s
1 target triple = "x86_64--"
2
3 ; CHECK: error: couldn't allocate output register for constraint '{ax}'
4 define i128 @blup() {
5 %v = tail call i128 asm "", "={ax},0"(i128 0)
6 ret i128 %v
7 }