Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -25580,71 +25580,40 @@ // Otherwise, check to see if this is a register class of the wrong value // type. For example, we want to map "{ax},i32" -> {eax}, we don't want it to // turn into {ax},{dx}. - if (Res.second->hasType(VT)) + // MVT::Other is used to specify clobber names. + if (Res.second->hasType(VT) || VT == MVT::Other) return Res; // Correct type already, nothing to do. - // All of the single-register GCC register classes map their values onto - // 16-bit register pieces "ax","dx","cx","bx","si","di","bp","sp". If we - // really want an 8-bit or 32-bit register, map to the appropriate register - // class and return the appropriate register. - if (Res.second == &X86::GR16RegClass) { - if (VT == MVT::i8 || VT == MVT::i1) { - unsigned DestReg = 0; - switch (Res.first) { - default: break; - case X86::AX: DestReg = X86::AL; break; - case X86::DX: DestReg = X86::DL; break; - case X86::CX: DestReg = X86::CL; break; - case X86::BX: DestReg = X86::BL; break; - } - if (DestReg) { - Res.first = DestReg; - Res.second = &X86::GR8RegClass; - } - } else if (VT == MVT::i32 || VT == MVT::f32) { - unsigned DestReg = 0; - switch (Res.first) { - default: break; - case X86::AX: DestReg = X86::EAX; break; - case X86::DX: DestReg = X86::EDX; break; - case X86::CX: DestReg = X86::ECX; break; - case X86::BX: DestReg = X86::EBX; break; - case X86::SI: DestReg = X86::ESI; break; - case X86::DI: DestReg = X86::EDI; break; - case X86::BP: DestReg = X86::EBP; break; - case X86::SP: DestReg = X86::ESP; break; - } - if (DestReg) { - Res.first = DestReg; - Res.second = &X86::GR32RegClass; - } - } else if (VT == MVT::i64 || VT == MVT::f64) { - unsigned DestReg = 0; - switch (Res.first) { - default: break; - case X86::AX: DestReg = X86::RAX; break; - case X86::DX: DestReg = X86::RDX; break; - case X86::CX: DestReg = X86::RCX; break; - case X86::BX: DestReg = X86::RBX; break; - case X86::SI: DestReg = X86::RSI; break; - case X86::DI: DestReg = X86::RDI; break; - case X86::BP: DestReg = X86::RBP; break; - case X86::SP: DestReg = X86::RSP; break; - } - if (DestReg) { - Res.first = DestReg; - Res.second = &X86::GR64RegClass; - } - } - } else if (Res.second == &X86::FR32RegClass || - Res.second == &X86::FR64RegClass || - Res.second == &X86::VR128RegClass || - Res.second == &X86::VR256RegClass || - Res.second == &X86::FR32XRegClass || - Res.second == &X86::FR64XRegClass || - Res.second == &X86::VR128XRegClass || - Res.second == &X86::VR256XRegClass || - Res.second == &X86::VR512RegClass) { + // Get a matching integer of the correct size. i.e. "ax" with MVT::32 should + // return "eax". This should even work for things like getting 64bit integer + // registers when given an f64 type. + const TargetRegisterClass *Class = Res.second; + if (Class == &X86::GR8RegClass || Class == &X86::GR16RegClass || + Class == &X86::GR32RegClass || Class == &X86::GR64RegClass) { + unsigned Size = VT.getSizeInBits(); + MVT::SimpleValueType SimpleTy = Size == 1 || Size == 8 ? MVT::i8 + : Size == 16 ? MVT::i16 + : Size == 32 ? MVT::i32 + : Size == 64 ? MVT::i64 + : MVT::Other; + unsigned DestReg = getX86SubSuperRegisterOrZero(Res.first, SimpleTy); + if (DestReg > 0) { + Res.first = DestReg; + Res.second = SimpleTy == MVT::i8 ? &X86::GR8RegClass + : SimpleTy == MVT::i16 ? &X86::GR16RegClass + : SimpleTy == MVT::i32 ? &X86::GR32RegClass + : &X86::GR64RegClass; + assert(Res.second->contains(Res.first) && "Register in register class"); + } else { + // No register found/type mismatch. + Res.first = 0; + Res.second = nullptr; + } + } else if (Class == &X86::FR32RegClass || Class == &X86::FR64RegClass || + Class == &X86::VR128RegClass || Class == &X86::VR256RegClass || + Class == &X86::FR32XRegClass || Class == &X86::FR64XRegClass || + Class == &X86::VR128XRegClass || Class == &X86::VR256XRegClass || + Class == &X86::VR512RegClass) { // Handle references to XMM physical registers that got mapped into the // wrong class. This can happen with constraints like {xmm0} where the // target independent register mapper will just pick the first match it can @@ -25660,6 +25629,11 @@ Res.second = &X86::VR256RegClass; else if (X86::VR512RegClass.hasType(VT)) Res.second = &X86::VR512RegClass; + else { + // Type mismatch and not a clobber: Return an error; + Res.first = 0; + Res.second = nullptr; + } } return Res; Index: llvm/trunk/lib/Target/X86/X86RegisterInfo.h =================================================================== --- llvm/trunk/lib/Target/X86/X86RegisterInfo.h +++ llvm/trunk/lib/Target/X86/X86RegisterInfo.h @@ -128,11 +128,16 @@ unsigned getSlotSize() const { return SlotSize; } }; -// getX86SubSuperRegister - X86 utility function. It returns the sub or super -// register of a specific X86 register. -// e.g. getX86SubSuperRegister(X86::EAX, MVT::i16) return X86:AX +/// Returns the sub or super register of a specific X86 register. +/// e.g. getX86SubSuperRegister(X86::EAX, MVT::i16) returns X86::AX. +/// Aborts on error. unsigned getX86SubSuperRegister(unsigned, MVT::SimpleValueType, bool High=false); +/// Returns the sub or super register of a specific X86 register. +/// Like getX86SubSuperRegister() but returns 0 on error. +unsigned getX86SubSuperRegisterOrZero(unsigned, MVT::SimpleValueType, + bool High = false); + //get512BitRegister - X86 utility - returns 512-bit super register unsigned get512BitSuperRegister(unsigned Reg); Index: llvm/trunk/lib/Target/X86/X86RegisterInfo.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86RegisterInfo.cpp +++ llvm/trunk/lib/Target/X86/X86RegisterInfo.cpp @@ -598,10 +598,10 @@ } namespace llvm { -unsigned getX86SubSuperRegister(unsigned Reg, MVT::SimpleValueType VT, - bool High) { +unsigned getX86SubSuperRegisterOrZero(unsigned Reg, MVT::SimpleValueType VT, + bool High) { switch (VT) { - default: llvm_unreachable("Unexpected VT"); + default: return 0; case MVT::i8: if (High) { switch (Reg) { @@ -625,7 +625,7 @@ } } else { switch (Reg) { - default: llvm_unreachable("Unexpected register"); + default: return 0; case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: return X86::AL; case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: @@ -662,7 +662,7 @@ } case MVT::i16: switch (Reg) { - default: llvm_unreachable("Unexpected register"); + default: return 0; case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: return X86::AX; case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: @@ -698,7 +698,7 @@ } case MVT::i32: switch (Reg) { - default: llvm_unreachable("Unexpected register"); + default: return 0; case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: return X86::EAX; case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: @@ -734,7 +734,7 @@ } case MVT::i64: switch (Reg) { - default: llvm_unreachable("Unexpected register"); + default: return 0; case X86::AH: case X86::AL: case X86::AX: case X86::EAX: case X86::RAX: return X86::RAX; case X86::DH: case X86::DL: case X86::DX: case X86::EDX: case X86::RDX: @@ -771,6 +771,14 @@ } } +unsigned getX86SubSuperRegister(unsigned Reg, MVT::SimpleValueType VT, + bool High) { + unsigned Res = getX86SubSuperRegisterOrZero(Reg, VT, High); + if (Res == 0) + llvm_unreachable("Unexpected register or VT"); + return Res; +} + unsigned get512BitSuperRegister(unsigned Reg) { if (Reg >= X86::XMM0 && Reg <= X86::XMM31) return X86::ZMM0 + (Reg - X86::XMM0); Index: llvm/trunk/test/CodeGen/X86/asm-mismatched-types.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/asm-mismatched-types.ll +++ llvm/trunk/test/CodeGen/X86/asm-mismatched-types.ll @@ -0,0 +1,135 @@ +; RUN: llc -o - %s -no-integrated-as | FileCheck %s +target triple = "x86_64--" + +; Allow to specify any of the 8/16/32/64 register names interchangeably in +; constraints + +; Produced by C-programs like this: +; void foo(int p) { register int reg __asm__("r8") = p; +; __asm__ __volatile__("# REG: %0" : : "r" (reg)); } + +; CHECK-LABEL: reg64_as_32: +; CHECK: # REG: %r8d +define void @reg64_as_32(i32 %p) { + call void asm sideeffect "# REG: $0", "{r8}"(i32 %p) + ret void +} + +; CHECK-LABEL: reg64_as_32_float: +; CHECK: # REG: %r8d +define void @reg64_as_32_float(float %p) { + call void asm sideeffect "# REG: $0", "{r8}"(float %p) + ret void +} + +; CHECK-LABEL: reg64_as_16: +; CHECK: # REG: %r9w +define void @reg64_as_16(i16 %p) { + call void asm sideeffect "# REG: $0", "{r9}"(i16 %p) + ret void +} + +; CHECK-LABEL: reg64_as_8: +; CHECK: # REG: %bpl +define void @reg64_as_8(i8 %p) { + call void asm sideeffect "# REG: $0", "{rbp}"(i8 %p) + ret void +} + +; CHECK-LABEL: reg32_as_16: +; CHECK: # REG: %r15w +define void @reg32_as_16(i16 %p) { + call void asm sideeffect "# REG: $0", "{r15d}"(i16 %p) + ret void +} + +; CHECK-LABEL: reg32_as_8: +; CHECK: # REG: %r12b +define void @reg32_as_8(i8 %p) { + call void asm sideeffect "# REG: $0", "{r12d}"(i8 %p) + ret void +} + +; CHECK-LABEL: reg16_as_8: +; CHECK: # REG: %cl +define void @reg16_as_8(i8 %p) { + call void asm sideeffect "# REG: $0", "{cx}"(i8 %p) + ret void +} + +; CHECK-LABEL: reg32_as_64: +; CHECK: # REG: %rbp +define void @reg32_as_64(i64 %p) { + call void asm sideeffect "# REG: $0", "{ebp}"(i64 %p) + ret void +} + +; CHECK-LABEL: reg32_as_64_float: +; CHECK: # REG: %rbp +define void @reg32_as_64_float(double %p) { + call void asm sideeffect "# REG: $0", "{ebp}"(double %p) + ret void +} + +; CHECK-LABEL: reg16_as_64: +; CHECK: # REG: %r13 +define void @reg16_as_64(i64 %p) { + call void asm sideeffect "# REG: $0", "{r13w}"(i64 %p) + ret void +} + +; CHECK-LABEL: reg16_as_64_float: +; CHECK: # REG: %r13 +define void @reg16_as_64_float(double %p) { + call void asm sideeffect "# REG: $0", "{r13w}"(double %p) + ret void +} + +; CHECK-LABEL: reg8_as_64: +; CHECK: # REG: %rax +define void @reg8_as_64(i64 %p) { + call void asm sideeffect "# REG: $0", "{al}"(i64 %p) + ret void +} + +; CHECK-LABEL: reg8_as_64_float: +; CHECK: # REG: %rax +define void @reg8_as_64_float(double %p) { + call void asm sideeffect "# REG: $0", "{al}"(double %p) + ret void +} + +; CHECK-LABEL: reg16_as_32: +; CHECK: # REG: %r11d +define void @reg16_as_32(i32 %p) { + call void asm sideeffect "# REG: $0", "{r11w}"(i32 %p) + ret void +} + +; CHECK-LABEL: reg16_as_32_float: +; CHECK: # REG: %r11d +define void @reg16_as_32_float(float %p) { + call void asm sideeffect "# REG: $0", "{r11w}"(float %p) + ret void +} + +; CHECK-LABEL: reg8_as_32: +; CHECK: # REG: %r9d +define void @reg8_as_32(i32 %p) { + call void asm sideeffect "# REG: $0", "{r9b}"(i32 %p) + ret void +} + +; CHECK-LABEL: reg8_as_32_float: +; CHECK: # REG: %r9d +define void @reg8_as_32_float(float %p) { + call void asm sideeffect "# REG: $0", "{r9b}"(float %p) + ret void +} + +; CHECK-LABEL: reg8_as_16: +; CHECK: # REG: %di +define void @reg8_as_16(i16 %p) { + call void asm sideeffect "# REG: $0", "{dil}"(i16 %p) + ret void +} Index: llvm/trunk/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll +++ llvm/trunk/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll @@ -0,0 +1,8 @@ +; RUN: not llc -o /dev/null %s 2>&1 | FileCheck %s +target triple = "x86_64--" + +; CHECK: error: couldn't allocate output register for constraint '{ax}' +define i128 @blup() { + %v = tail call i128 asm "", "={ax},0"(i128 0) + ret i128 %v +}