mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-26 14:15:53 +00:00
[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
This commit is contained in:
parent
f681437cb0
commit
9e2838e29b
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<VectorType>(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<unsigned long long>(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<const TargetRegisterClass*>(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);
|
||||
|
34
test/CodeGen/Mips/msa/inline-asm.ll
Normal file
34
test/CodeGen/Mips/msa/inline-asm.ll
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user