From 9e2838e29b0820afc35f6ef2d465d4aca9ed402a Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Tue, 12 Nov 2013 12:56:01 +0000 Subject: [PATCH] [mips][msa] Enable inlinse assembly for MSA. Like GCC, this re-uses the 'f' constraint and a new 'w' print-modifier: asm ("ldi.w %w0, 1", "=f"(result)); Unlike GCC, the 'w' print-modifer is not _required_ to produce the intended output. This is a consequence of differences in the internal handling of the registers in each compiler. To be source-compatible between the compilers, users must use the 'w' print-modifier. MSA registers (including control registers) are supported in clobber lists. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194476 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsAsmPrinter.cpp | 5 +++ lib/Target/Mips/MipsISelLowering.cpp | 55 +++++++++++++++++++++++----- test/CodeGen/Mips/msa/inline-asm.ll | 34 +++++++++++++++++ 3 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 test/CodeGen/Mips/msa/inline-asm.ll diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 3bef2fa0050..45c43982642 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -461,6 +461,11 @@ bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, return false; } } + case 'w': + // Print MSA registers for the 'f' constraint + // In LLVM, the 'w' modifier doesn't need to do anything. + // We can just call printOperand as normal. + break; } } diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 5f82b4e69c8..edba8747e97 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -20,6 +20,7 @@ #include "MipsTargetMachine.h" #include "MipsTargetObjectFile.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -2777,7 +2778,7 @@ MipsTargetLowering::LowerReturn(SDValue Chain, MipsTargetLowering::ConstraintType MipsTargetLowering:: getConstraintType(const std::string &Constraint) const { - // Mips specific constrainy + // Mips specific constraints // GCC config/mips/constraints.md // // 'd' : An address register. Equivalent to r @@ -2828,16 +2829,19 @@ MipsTargetLowering::getSingleConstraintMatchWeight( if (type->isIntegerTy()) weight = CW_Register; break; - case 'f': - if (type->isFloatTy()) + case 'f': // FPU or MSA register + if (Subtarget->hasMSA() && type->isVectorTy() && + cast(type)->getBitWidth() == 128) + weight = CW_Register; + else if (type->isFloatTy()) weight = CW_Register; break; case 'c': // $25 for indirect jumps case 'l': // lo register case 'x': // hilo register pair - if (type->isIntegerTy()) + if (type->isIntegerTy()) weight = CW_SpecificReg; - break; + break; case 'I': // signed 16 bit immediate case 'J': // integer zero case 'K': // unsigned 16 bit immediate @@ -2900,6 +2904,29 @@ parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { RC = TRI->getRegClass(Prefix == "hi" ? Mips::HI32RegClassID : Mips::LO32RegClassID); return std::make_pair(*(RC->begin()), RC); + } else if (Prefix.compare(0, 4, "$msa") == 0) { + // Parse $msa(ir|csr|access|save|modify|request|map|unmap) + + // No numeric characters follow the name. + if (R.second) + return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + + Reg = StringSwitch(Prefix) + .Case("$msair", Mips::MSAIR) + .Case("$msacsr", Mips::MSACSR) + .Case("$msaaccess", Mips::MSAAccess) + .Case("$msasave", Mips::MSASave) + .Case("$msamodify", Mips::MSAModify) + .Case("$msarequest", Mips::MSARequest) + .Case("$msamap", Mips::MSAMap) + .Case("$msaunmap", Mips::MSAUnmap) + .Default(0); + + if (!Reg) + return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + + RC = TRI->getRegClass(Mips::MSACtrlRegClassID); + return std::make_pair(Reg, RC); } if (!R.second) @@ -2917,8 +2944,10 @@ parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { assert(Reg % 2 == 0); Reg >>= 1; } - } else if (Prefix == "$fcc") { // Parse $fcc0-$fcc7. + } else if (Prefix == "$fcc") // Parse $fcc0-$fcc7. RC = TRI->getRegClass(Mips::FCCRegClassID); + else if (Prefix == "$w") { // Parse $w0-$w31. + RC = getRegClassFor((VT == MVT::Other) ? MVT::v16i8 : VT); } else { // Parse $0-$31. assert(Prefix == "$"); RC = getRegClassFor((VT == MVT::Other) ? MVT::i32 : VT); @@ -2950,10 +2979,18 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const return std::make_pair(0U, &Mips::GPR64RegClass); // This will generate an error message return std::make_pair(0u, static_cast(0)); - case 'f': - if (VT == MVT::f32) + case 'f': // FPU or MSA register + if (VT == MVT::v16i8) + return std::make_pair(0U, &Mips::MSA128BRegClass); + else if (VT == MVT::v8i16 || VT == MVT::v8f16) + return std::make_pair(0U, &Mips::MSA128HRegClass); + else if (VT == MVT::v4i32 || VT == MVT::v4f32) + return std::make_pair(0U, &Mips::MSA128WRegClass); + else if (VT == MVT::v2i64 || VT == MVT::v2f64) + return std::make_pair(0U, &Mips::MSA128DRegClass); + else if (VT == MVT::f32) return std::make_pair(0U, &Mips::FGR32RegClass); - if ((VT == MVT::f64) && (!Subtarget->isSingleFloat())) { + else if ((VT == MVT::f64) && (!Subtarget->isSingleFloat())) { if (Subtarget->isFP64bit()) return std::make_pair(0U, &Mips::FGR64RegClass); return std::make_pair(0U, &Mips::AFGR64RegClass); diff --git a/test/CodeGen/Mips/msa/inline-asm.ll b/test/CodeGen/Mips/msa/inline-asm.ll new file mode 100644 index 00000000000..4a34273f3c0 --- /dev/null +++ b/test/CodeGen/Mips/msa/inline-asm.ll @@ -0,0 +1,34 @@ +; A basic inline assembly test + +; RUN: llc -march=mips -mattr=+msa,+fp64 < %s | FileCheck %s + +@v4i32_r = global <4 x i32> zeroinitializer, align 16 + +define void @test1() nounwind { +entry: + ; CHECK-LABEL: test1: + %0 = call <4 x i32> asm "ldi.w ${0:w}, 1", "=f"() + ; CHECK: ldi.w $w{{[1-3]?[0-9]}}, 1 + store <4 x i32> %0, <4 x i32>* @v4i32_r + ret void +} + +define void @test2() nounwind { +entry: + ; CHECK-LABEL: test2: + %0 = load <4 x i32>* @v4i32_r + %1 = call <4 x i32> asm "addvi.w ${0:w}, ${1:w}, 1", "=f,f"(<4 x i32> %0) + ; CHECK: addvi.w $w{{[1-3]?[0-9]}}, $w{{[1-3]?[0-9]}}, 1 + store <4 x i32> %1, <4 x i32>* @v4i32_r + ret void +} + +define void @test3() nounwind { +entry: + ; CHECK-LABEL: test3: + %0 = load <4 x i32>* @v4i32_r + %1 = call <4 x i32> asm sideeffect "addvi.w ${0:w}, ${1:w}, 1", "=f,f,~{$w0}"(<4 x i32> %0) + ; CHECK: addvi.w $w{{([1-9]|[1-3][0-9])}}, $w{{([1-9]|[1-3][0-9])}}, 1 + store <4 x i32> %1, <4 x i32>* @v4i32_r + ret void +}