aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorchenli <chenli@loongson.cn>2023-07-25 09:02:14 +0800
committerWeining Lu <luweining@loongson.cn>2023-07-25 09:02:29 +0800
commitd25c79dc70008b835312e5cc7ef48b199fda3165 (patch)
treef62d8adb179cf33809dfd12c092419bd4f32512a /llvm
parentc299efbf284fae92bb8d7d29110f76912f089daf (diff)
downloadllvm-d25c79dc70008b835312e5cc7ef48b199fda3165.zip
llvm-d25c79dc70008b835312e5cc7ef48b199fda3165.tar.gz
llvm-d25c79dc70008b835312e5cc7ef48b199fda3165.tar.bz2
[LoongArch] Support InlineAsm for LSX and LASX
The author of the following files is licongtian <licongtian@loongson.cn>: - clang/lib/Basic/Targets/LoongArch.cpp - llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp - llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp The files mentioned above implement InlineAsm for LSX and LASX as follows: - Enable clang parsing LSX/LASX register name, such as $vr0. - Support the case which operand type is 128bit or 256bit when the constraints is 'f'. - Support the way of specifying LSX/LASX register by using constraint, such as "={$xr0}". - Support the operand modifiers 'u' and 'w'. - Support and legalize the data types and register classes involved in LSX/LASX in the lowering process. Reviewed By: xen0n, SixWeining Differential Revision: https://reviews.llvm.org/D154931
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp14
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp17
-rw-r--r--llvm/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.ll14
-rw-r--r--llvm/test/CodeGen/LoongArch/lasx/inline-asm-reg-names.ll58
-rw-r--r--llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.ll14
-rw-r--r--llvm/test/CodeGen/LoongArch/lsx/inline-asm-reg-names.ll58
6 files changed, 174 insertions, 1 deletions
diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
index 5cf0673..27979a8 100644
--- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
@@ -75,6 +75,20 @@ bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
return false;
}
break;
+ case 'w': // Print LSX registers.
+ if (MO.getReg().id() >= LoongArch::VR0 &&
+ MO.getReg().id() <= LoongArch::VR31)
+ break;
+ // The modifier is 'w' but the operand is not an LSX register; Report an
+ // unknown operand error.
+ return true;
+ case 'u': // Print LASX registers.
+ if (MO.getReg().id() >= LoongArch::XR0 &&
+ MO.getReg().id() <= LoongArch::XR31)
+ break;
+ // The modifier is 'u' but the operand is not an LASX register; Report an
+ // unknown operand error.
+ return true;
// TODO: handle other extra codes if any.
}
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 9487166..b6e9210 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -53,6 +53,14 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
if (Subtarget.hasBasicD())
addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
+ if (Subtarget.hasExtLSX())
+ for (auto VT : {MVT::v4f32, MVT::v2f64, MVT::v16i8, MVT::v8i16, MVT::v4i32,
+ MVT::v2i64})
+ addRegisterClass(VT, &LoongArch::LSX128RegClass);
+ if (Subtarget.hasExtLASX())
+ for (auto VT : {MVT::v8f32, MVT::v4f64, MVT::v32i8, MVT::v16i16, MVT::v8i32,
+ MVT::v4i64})
+ addRegisterClass(VT, &LoongArch::LASX256RegClass);
setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
MVT::i1, Promote);
@@ -3048,6 +3056,12 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint(
return std::make_pair(0U, &LoongArch::FPR32RegClass);
if (Subtarget.hasBasicD() && VT == MVT::f64)
return std::make_pair(0U, &LoongArch::FPR64RegClass);
+ if (Subtarget.hasExtLSX() &&
+ TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
+ return std::make_pair(0U, &LoongArch::LSX128RegClass);
+ if (Subtarget.hasExtLASX() &&
+ TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
+ return std::make_pair(0U, &LoongArch::LASX256RegClass);
break;
default:
break;
@@ -3065,7 +3079,8 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint(
// decode the usage of register name aliases into their official names. And
// AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
// official register names.
- if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) {
+ if (Constraint.startswith("{$r") || Constraint.startswith("{$f") ||
+ Constraint.startswith("{$vr") || Constraint.startswith("{$xr")) {
bool IsFP = Constraint[2] == 'f';
std::pair<StringRef, StringRef> Temp = Constraint.split('$');
std::pair<unsigned, const TargetRegisterClass *> R;
diff --git a/llvm/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.ll b/llvm/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.ll
new file mode 100644
index 0000000..201e34c
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s
+
+define void @test_u() nounwind {
+; CHECK-LABEL: test_u:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: xvldi $xr0, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "=f"()
+ ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lasx/inline-asm-reg-names.ll b/llvm/test/CodeGen/LoongArch/lasx/inline-asm-reg-names.ll
new file mode 100644
index 0000000..dd400ecf
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/inline-asm-reg-names.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s
+
+define void @register_xr1() nounwind {
+; CHECK-LABEL: register_xr1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: xvldi $xr1, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "={$xr1}"()
+ ret void
+}
+
+define void @register_xr7() nounwind {
+; CHECK-LABEL: register_xr7:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: xvldi $xr7, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "={$xr7}"()
+ ret void
+}
+
+define void @register_xr23() nounwind {
+; CHECK-LABEL: register_xr23:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: xvldi $xr23, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "={$xr23}"()
+ ret void
+}
+
+;; The lower 64-bit of the vector register '$xr31' is overlapped with
+;; the floating-point register '$f31' ('$fs7'). And '$f31' ('$fs7')
+;; is a callee-saved register which is preserved across calls.
+;; That's why the fst.d and fld.d instructions are emitted.
+define void @register_xr31() nounwind {
+; CHECK-LABEL: register_xr31:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addi.d $sp, $sp, -16
+; CHECK-NEXT: fst.d $fs7, $sp, 8 # 8-byte Folded Spill
+; CHECK-NEXT: #APP
+; CHECK-NEXT: xvldi $xr31, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: fld.d $fs7, $sp, 8 # 8-byte Folded Reload
+; CHECK-NEXT: addi.d $sp, $sp, 16
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "={$xr31}"()
+ ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.ll b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.ll
new file mode 100644
index 0000000..c46e624
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s
+
+define void @test_w() nounwind {
+; CHECK-LABEL: test_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: vldi $vr0, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "=f"()
+ ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/inline-asm-reg-names.ll b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-reg-names.ll
new file mode 100644
index 0000000..ceea362
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/inline-asm-reg-names.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s
+
+define void @register_vr1() nounwind {
+; CHECK-LABEL: register_vr1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: vldi $vr1, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "={$vr1}"()
+ ret void
+}
+
+define void @register_vr7() nounwind {
+; CHECK-LABEL: register_vr7:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: vldi $vr7, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "={$vr7}"()
+ ret void
+}
+
+define void @register_vr23() nounwind {
+; CHECK-LABEL: register_vr23:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: vldi $vr23, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "={$vr23}"()
+ ret void
+}
+
+;; The lower half of the vector register '$vr31' is overlapped with
+;; the floating-point register '$f31'. And '$f31' is a callee-saved
+;; register which is preserved across calls. That's why the
+;; fst.d and fld.d instructions are emitted.
+define void @register_vr31() nounwind {
+; CHECK-LABEL: register_vr31:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addi.d $sp, $sp, -16
+; CHECK-NEXT: fst.d $fs7, $sp, 8 # 8-byte Folded Spill
+; CHECK-NEXT: #APP
+; CHECK-NEXT: vldi $vr31, 1
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: fld.d $fs7, $sp, 8 # 8-byte Folded Reload
+; CHECK-NEXT: addi.d $sp, $sp, 16
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "={$vr31}"()
+ ret void
+}