forked from OSchip/llvm-project
Revert D134638 "[Clang][LoongArch] Add inline asm support for constraints k/m/ZB/ZC"
This reverts commit b7baddc755
.
Broke CodeGen/X86/callbr-asm-kill.mir
We shall pay attention when adding new constraints.
This commit is contained in:
parent
a41764810f
commit
04a65d62a0
|
@ -67,19 +67,14 @@ bool LoongArchTargetInfo::validateAsmConstraint(
|
||||||
const char *&Name, TargetInfo::ConstraintInfo &Info) const {
|
const char *&Name, TargetInfo::ConstraintInfo &Info) const {
|
||||||
// See the GCC definitions here:
|
// See the GCC definitions here:
|
||||||
// https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html
|
// https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html
|
||||||
// Note that the 'm' constraint is handled in TargetInfo.
|
|
||||||
switch (*Name) {
|
switch (*Name) {
|
||||||
|
// TODO: handle 'k', 'm', "ZB", "ZC".
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case 'f':
|
case 'f':
|
||||||
// A floating-point register (if available).
|
// A floating-point register (if available).
|
||||||
Info.setAllowsRegister();
|
Info.setAllowsRegister();
|
||||||
return true;
|
return true;
|
||||||
case 'k':
|
|
||||||
// A memory operand whose address is formed by a base register and
|
|
||||||
// (optionally scaled) index register.
|
|
||||||
Info.setAllowsMemory();
|
|
||||||
return true;
|
|
||||||
case 'l':
|
case 'l':
|
||||||
// A signed 16-bit constant.
|
// A signed 16-bit constant.
|
||||||
Info.setRequiresImmediate(-32768, 32767);
|
Info.setRequiresImmediate(-32768, 32767);
|
||||||
|
@ -92,38 +87,9 @@ bool LoongArchTargetInfo::validateAsmConstraint(
|
||||||
// An unsigned 12-bit constant (for logic instructions).
|
// An unsigned 12-bit constant (for logic instructions).
|
||||||
Info.setRequiresImmediate(0, 4095);
|
Info.setRequiresImmediate(0, 4095);
|
||||||
return true;
|
return true;
|
||||||
case 'Z':
|
|
||||||
// ZB: An address that is held in a general-purpose register. The offset is
|
|
||||||
// zero.
|
|
||||||
// ZC: A memory operand whose address is formed by a base register
|
|
||||||
// and offset that is suitable for use in instructions with the same
|
|
||||||
// addressing mode as ll.w and sc.w.
|
|
||||||
if (Name[1] == 'C' || Name[1] == 'B') {
|
|
||||||
Info.setAllowsMemory();
|
|
||||||
++Name; // Skip over 'Z'.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
|
||||||
LoongArchTargetInfo::convertConstraint(const char *&Constraint) const {
|
|
||||||
std::string R;
|
|
||||||
switch (*Constraint) {
|
|
||||||
case 'Z':
|
|
||||||
// "ZC"/"ZB" are two-character constraints; add "^" hint for later
|
|
||||||
// parsing.
|
|
||||||
R = "^" + std::string(Constraint, 2);
|
|
||||||
++Constraint;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
R = TargetInfo::convertConstraint(Constraint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return R;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
|
void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||||
MacroBuilder &Builder) const {
|
MacroBuilder &Builder) const {
|
||||||
Builder.defineMacro("__loongarch__");
|
Builder.defineMacro("__loongarch__");
|
||||||
|
|
|
@ -55,7 +55,6 @@ public:
|
||||||
|
|
||||||
bool validateAsmConstraint(const char *&Name,
|
bool validateAsmConstraint(const char *&Name,
|
||||||
TargetInfo::ConstraintInfo &Info) const override;
|
TargetInfo::ConstraintInfo &Info) const override;
|
||||||
std::string convertConstraint(const char *&Constraint) const override;
|
|
||||||
|
|
||||||
bool hasBitIntType() const override { return true; }
|
bool hasBitIntType() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,12 +15,6 @@ void test_f(void) {
|
||||||
asm volatile ("" :: "f"(d));
|
asm volatile ("" :: "f"(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_k(int *p, int idx) {
|
|
||||||
// CHECK-LABEL: define{{.*}} void @test_k(ptr noundef %p, i32 noundef{{.*}} %idx)
|
|
||||||
// CHECK: call void asm sideeffect "", "*k"(ptr elementtype(i32) %{{.*}})
|
|
||||||
asm volatile("" :: "k"(*(p+idx)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_l(void) {
|
void test_l(void) {
|
||||||
// CHECK-LABEL: define{{.*}} void @test_l()
|
// CHECK-LABEL: define{{.*}} void @test_l()
|
||||||
// CHECK: call void asm sideeffect "", "l"(i32 32767)
|
// CHECK: call void asm sideeffect "", "l"(i32 32767)
|
||||||
|
@ -29,12 +23,6 @@ void test_l(void) {
|
||||||
asm volatile ("" :: "l"(-32768));
|
asm volatile ("" :: "l"(-32768));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_m(int *p) {
|
|
||||||
// CHECK-LABEL: define{{.*}} void @test_m(ptr noundef %p)
|
|
||||||
// CHECK: call void asm sideeffect "", "*m"(ptr nonnull elementtype(i32) %{{.*}})
|
|
||||||
asm volatile("" :: "m"(*(p+4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_I(void) {
|
void test_I(void) {
|
||||||
// CHECK-LABEL: define{{.*}} void @test_I()
|
// CHECK-LABEL: define{{.*}} void @test_I()
|
||||||
// CHECK: call void asm sideeffect "", "I"(i32 2047)
|
// CHECK: call void asm sideeffect "", "I"(i32 2047)
|
||||||
|
@ -50,15 +38,3 @@ void test_K(void) {
|
||||||
// CHECK: call void asm sideeffect "", "K"(i32 0)
|
// CHECK: call void asm sideeffect "", "K"(i32 0)
|
||||||
asm volatile ("" :: "K"(0));
|
asm volatile ("" :: "K"(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ZB(int *p) {
|
|
||||||
// CHECK-LABEL: define{{.*}} void @test_ZB(ptr noundef %p)
|
|
||||||
// CHECK: call void asm sideeffect "", "*^ZB"(ptr elementtype(i32) %p)
|
|
||||||
asm volatile ("" :: "ZB"(*p));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ZC(int *p) {
|
|
||||||
// CHECK-LABEL: define{{.*}} void @test_ZC(ptr noundef %p)
|
|
||||||
// CHECK: call void asm sideeffect "", "*^ZC"(ptr elementtype(i32) %p)
|
|
||||||
asm volatile ("" :: "ZC"(*p));
|
|
||||||
}
|
|
||||||
|
|
|
@ -252,7 +252,6 @@ public:
|
||||||
Constraint_Unknown = 0,
|
Constraint_Unknown = 0,
|
||||||
Constraint_es,
|
Constraint_es,
|
||||||
Constraint_i,
|
Constraint_i,
|
||||||
Constraint_k,
|
|
||||||
Constraint_m,
|
Constraint_m,
|
||||||
Constraint_o,
|
Constraint_o,
|
||||||
Constraint_v,
|
Constraint_v,
|
||||||
|
@ -270,7 +269,6 @@ public:
|
||||||
Constraint_Uy,
|
Constraint_Uy,
|
||||||
Constraint_X,
|
Constraint_X,
|
||||||
Constraint_Z,
|
Constraint_Z,
|
||||||
Constraint_ZB,
|
|
||||||
Constraint_ZC,
|
Constraint_ZC,
|
||||||
Constraint_Zy,
|
Constraint_Zy,
|
||||||
|
|
||||||
|
@ -430,8 +428,6 @@ public:
|
||||||
return "es";
|
return "es";
|
||||||
case InlineAsm::Constraint_i:
|
case InlineAsm::Constraint_i:
|
||||||
return "i";
|
return "i";
|
||||||
case InlineAsm::Constraint_k:
|
|
||||||
return "k";
|
|
||||||
case InlineAsm::Constraint_m:
|
case InlineAsm::Constraint_m:
|
||||||
return "m";
|
return "m";
|
||||||
case InlineAsm::Constraint_o:
|
case InlineAsm::Constraint_o:
|
||||||
|
@ -464,8 +460,6 @@ public:
|
||||||
return "X";
|
return "X";
|
||||||
case InlineAsm::Constraint_Z:
|
case InlineAsm::Constraint_Z:
|
||||||
return "Z";
|
return "Z";
|
||||||
case InlineAsm::Constraint_ZB:
|
|
||||||
return "ZB";
|
|
||||||
case InlineAsm::Constraint_ZC:
|
case InlineAsm::Constraint_ZC:
|
||||||
return "ZC";
|
return "ZC";
|
||||||
case InlineAsm::Constraint_Zy:
|
case InlineAsm::Constraint_Zy:
|
||||||
|
|
|
@ -68,35 +68,6 @@ bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
|
||||||
unsigned OpNo,
|
|
||||||
const char *ExtraCode,
|
|
||||||
raw_ostream &OS) {
|
|
||||||
// TODO: handle extra code.
|
|
||||||
if (ExtraCode)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const MachineOperand &BaseMO = MI->getOperand(OpNo);
|
|
||||||
// Base address must be a register.
|
|
||||||
if (!BaseMO.isReg())
|
|
||||||
return true;
|
|
||||||
// Print the base address register.
|
|
||||||
OS << "$" << LoongArchInstPrinter::getRegisterName(BaseMO.getReg());
|
|
||||||
// Print the offset register or immediate if has.
|
|
||||||
if (OpNo + 1 < MI->getNumOperands()) {
|
|
||||||
const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);
|
|
||||||
if (OffsetMO.isReg())
|
|
||||||
OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());
|
|
||||||
else if (OffsetMO.isImm())
|
|
||||||
OS << ", " << OffsetMO.getImm();
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
||||||
AsmPrinter::runOnMachineFunction(MF);
|
AsmPrinter::runOnMachineFunction(MF);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -38,8 +38,6 @@ public:
|
||||||
|
|
||||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||||
const char *ExtraCode, raw_ostream &OS) override;
|
const char *ExtraCode, raw_ostream &OS) override;
|
||||||
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
|
||||||
const char *ExtraCode, raw_ostream &OS) override;
|
|
||||||
|
|
||||||
// tblgen'erated function.
|
// tblgen'erated function.
|
||||||
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
||||||
|
|
|
@ -77,59 +77,6 @@ void LoongArchDAGToDAGISel::Select(SDNode *Node) {
|
||||||
SelectCode(Node);
|
SelectCode(Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
|
|
||||||
const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
|
|
||||||
switch (ConstraintID) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("unexpected asm memory constraint");
|
|
||||||
// Reg+Reg addressing.
|
|
||||||
case InlineAsm::Constraint_k:
|
|
||||||
OutOps.push_back(Op.getOperand(0));
|
|
||||||
OutOps.push_back(Op.getOperand(1));
|
|
||||||
return false;
|
|
||||||
// Reg+simm12 addressing.
|
|
||||||
case InlineAsm::Constraint_m: {
|
|
||||||
SDValue Base = Op;
|
|
||||||
SDValue Offset =
|
|
||||||
CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
|
|
||||||
if (CurDAG->isBaseWithConstantOffset(Op)) {
|
|
||||||
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
|
|
||||||
if (isIntN(12, CN->getSExtValue())) {
|
|
||||||
Base = Op.getOperand(0);
|
|
||||||
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
|
|
||||||
Op.getValueType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutOps.push_back(Base);
|
|
||||||
OutOps.push_back(Offset);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case InlineAsm::Constraint_ZB:
|
|
||||||
OutOps.push_back(Op);
|
|
||||||
// No offset.
|
|
||||||
return false;
|
|
||||||
// Reg+(simm14<<2) addressing.
|
|
||||||
case InlineAsm::Constraint_ZC: {
|
|
||||||
SDValue Base = Op;
|
|
||||||
SDValue Offset =
|
|
||||||
CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
|
|
||||||
if (CurDAG->isBaseWithConstantOffset(Op)) {
|
|
||||||
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
|
|
||||||
if (isIntN(16, CN->getSExtValue()) &&
|
|
||||||
isAligned(Align(4ULL), CN->getZExtValue())) {
|
|
||||||
Base = Op.getOperand(0);
|
|
||||||
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
|
|
||||||
Op.getValueType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutOps.push_back(Base);
|
|
||||||
OutOps.push_back(Offset);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
|
bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
|
||||||
// If this is FrameIndex, select it directly. Otherwise just let it get
|
// If this is FrameIndex, select it directly. Otherwise just let it get
|
||||||
// selected to a register independently.
|
// selected to a register independently.
|
||||||
|
|
|
@ -38,9 +38,6 @@ public:
|
||||||
|
|
||||||
void Select(SDNode *Node) override;
|
void Select(SDNode *Node) override;
|
||||||
|
|
||||||
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
|
|
||||||
std::vector<SDValue> &OutOps) override;
|
|
||||||
|
|
||||||
bool SelectBaseAddr(SDValue Addr, SDValue &Base);
|
bool SelectBaseAddr(SDValue Addr, SDValue &Base);
|
||||||
|
|
||||||
bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
|
bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
|
||||||
|
|
|
@ -2024,27 +2024,14 @@ LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
|
||||||
case 'I':
|
case 'I':
|
||||||
case 'K':
|
case 'K':
|
||||||
return C_Immediate;
|
return C_Immediate;
|
||||||
case 'k':
|
|
||||||
return C_Memory;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Constraint == "ZC" || Constraint == "ZB")
|
// TODO: handle 'k", "ZB" and "ZC".
|
||||||
return C_Memory;
|
|
||||||
|
|
||||||
// 'm' is handled here.
|
|
||||||
return TargetLowering::getConstraintType(Constraint);
|
return TargetLowering::getConstraintType(Constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
|
|
||||||
StringRef ConstraintCode) const {
|
|
||||||
return StringSwitch<unsigned>(ConstraintCode)
|
|
||||||
.Case("k", InlineAsm::Constraint_k)
|
|
||||||
.Case("ZB", InlineAsm::Constraint_ZB)
|
|
||||||
.Case("ZC", InlineAsm::Constraint_ZC)
|
|
||||||
.Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<unsigned, const TargetRegisterClass *>
|
std::pair<unsigned, const TargetRegisterClass *>
|
||||||
LoongArchTargetLowering::getRegForInlineAsmConstraint(
|
LoongArchTargetLowering::getRegForInlineAsmConstraint(
|
||||||
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
|
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
|
||||||
|
|
|
@ -162,8 +162,6 @@ private:
|
||||||
|
|
||||||
ConstraintType getConstraintType(StringRef Constraint) const override;
|
ConstraintType getConstraintType(StringRef Constraint) const override;
|
||||||
|
|
||||||
unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override;
|
|
||||||
|
|
||||||
std::pair<unsigned, const TargetRegisterClass *>
|
std::pair<unsigned, const TargetRegisterClass *>
|
||||||
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||||
StringRef Constraint, MVT VT) const override;
|
StringRef Constraint, MVT VT) const override;
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s \
|
|
||||||
; RUN: | FileCheck %s --check-prefix=ASM
|
|
||||||
; RUN: llc --mtriple=loongarch64 --print-after-isel -o /dev/null 2>&1 < %s \
|
|
||||||
; RUN: | FileCheck %s --check-prefix=MACHINE-INSTR
|
|
||||||
|
|
||||||
;; Note amswap.w is not available on loongarch32.
|
|
||||||
|
|
||||||
define void @ZB(ptr %p) nounwind {
|
|
||||||
; ASM-LABEL: ZB:
|
|
||||||
; ASM: # %bb.0:
|
|
||||||
; ASM-NEXT: #APP
|
|
||||||
; ASM-NEXT: amswap.w $t0, $t1, $a0
|
|
||||||
; ASM-NEXT: #NO_APP
|
|
||||||
; ASM-NEXT: ret
|
|
||||||
;; Make sure machine instr with this "ZB" constraint is printed correctly.
|
|
||||||
; MACHINE-INSTR: INLINEASM{{.*}}[mem:ZB]
|
|
||||||
call void asm "amswap.w $$r12, $$r13, $0", "*^ZB"(ptr elementtype(i32) %p)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
define void @ZB_constant_offset(ptr %p) nounwind {
|
|
||||||
; ASM-LABEL: ZB_constant_offset:
|
|
||||||
; ASM: # %bb.0:
|
|
||||||
; ASM-NEXT: addi.d $a0, $a0, 1
|
|
||||||
; ASM-NEXT: #APP
|
|
||||||
; ASM-NEXT: amswap.w $t0, $t1, $a0
|
|
||||||
; ASM-NEXT: #NO_APP
|
|
||||||
; ASM-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 1
|
|
||||||
;; Make sure machine instr with this "ZB" constraint is printed correctly.
|
|
||||||
; MACHINE-INSTR: INLINEASM{{.*}}[mem:ZB]
|
|
||||||
call void asm "amswap.w $$r12, $$r13, $0", "*^ZB"(ptr elementtype(i32) %1)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
define void @ZB_variable_offset(ptr %p, i32 signext %idx) nounwind {
|
|
||||||
; ASM-LABEL: ZB_variable_offset:
|
|
||||||
; ASM: # %bb.0:
|
|
||||||
; ASM-NEXT: add.d $a0, $a0, $a1
|
|
||||||
; ASM-NEXT: #APP
|
|
||||||
; ASM-NEXT: amswap.w $t0, $t1, $a0
|
|
||||||
; ASM-NEXT: #NO_APP
|
|
||||||
; ASM-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 %idx
|
|
||||||
;; Make sure machine instr with this "ZB" constraint is printed correctly.
|
|
||||||
; MACHINE-INSTR: INLINEASM{{.*}}[mem:ZB]
|
|
||||||
call void asm "amswap.w $$r12, $$r13, $0", "*^ZB"(ptr elementtype(i32) %1)
|
|
||||||
ret void
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
||||||
; RUN: llc --mtriple=loongarch32 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA32
|
|
||||||
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA64
|
|
||||||
|
|
||||||
define i32 @ZC_offset_neg_32769(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_neg_32769:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: lu12i.w $a1, -9
|
|
||||||
; LA32-NEXT: ori $a1, $a1, 4095
|
|
||||||
; LA32-NEXT: add.w $a0, $a0, $a1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_neg_32769:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: lu12i.w $a1, -9
|
|
||||||
; LA64-NEXT: ori $a1, $a1, 4095
|
|
||||||
; LA64-NEXT: add.d $a0, $a0, $a1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -32769
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_neg_32768(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_neg_32768:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, -32768
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_neg_32768:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, -32768
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -32768
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_neg_4(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_neg_4:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, -4
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_neg_4:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, -4
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -4
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_neg_1(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_neg_1:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: addi.w $a0, $a0, -1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_neg_1:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: addi.d $a0, $a0, -1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -1
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_0(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_0:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_0:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %p)
|
|
||||||
ret i32 %1
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_1(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_1:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: addi.w $a0, $a0, 1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_1:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: addi.d $a0, $a0, 1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 1
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_32764(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_32764:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 32764
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_32764:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 32764
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 32764
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @ZC_offset_32767(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: ZC_offset_32767:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: lu12i.w $a1, 7
|
|
||||||
; LA32-NEXT: ori $a1, $a1, 4095
|
|
||||||
; LA32-NEXT: add.w $a0, $a0, $a1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: ZC_offset_32767:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: lu12i.w $a1, 7
|
|
||||||
; LA64-NEXT: ori $a1, $a1, 4095
|
|
||||||
; LA64-NEXT: add.d $a0, $a0, $a1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ll.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 32767
|
|
||||||
%2 = call i32 asm "ll.w $0, $1", "=r,*^ZC"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s \
|
|
||||||
; RUN: | FileCheck %s --check-prefix=ASM
|
|
||||||
; RUN: llc --mtriple=loongarch64 --print-after-isel -o /dev/null 2>&1 < %s \
|
|
||||||
; RUN: | FileCheck %s --check-prefix=MACHINE-INSTR
|
|
||||||
|
|
||||||
define i64 @k_variable_offset(ptr %p, i64 %idx) nounwind {
|
|
||||||
; ASM-LABEL: k_variable_offset:
|
|
||||||
; ASM: # %bb.0:
|
|
||||||
; ASM-NEXT: #APP
|
|
||||||
; ASM-NEXT: ldx.d $a0, $a0, $a1
|
|
||||||
; ASM-NEXT: #NO_APP
|
|
||||||
; ASM-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i64 %idx
|
|
||||||
;; Make sure machine instr with this 'k' constraint is printed correctly.
|
|
||||||
; MACHINE-INSTR: INLINEASM{{.*}}[mem:k]
|
|
||||||
%2 = call i64 asm "ldx.d $0, $1", "=r,*k"(ptr elementtype(i64) %1)
|
|
||||||
ret i64 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i64 @k_constant_offset(ptr %p) nounwind {
|
|
||||||
; ASM-LABEL: k_constant_offset:
|
|
||||||
; ASM: # %bb.0:
|
|
||||||
; ASM-NEXT: ori $a1, $zero, 5
|
|
||||||
; ASM-NEXT: #APP
|
|
||||||
; ASM-NEXT: ldx.d $a0, $a0, $a1
|
|
||||||
; ASM-NEXT: #NO_APP
|
|
||||||
; ASM-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i64 5
|
|
||||||
;; Make sure machine instr with this 'k' constraint is printed correctly.
|
|
||||||
; MACHINE-INSTR: INLINEASM{{.*}}[mem:k]
|
|
||||||
%2 = call i64 asm "ldx.d $0, $1", "=r,*k"(ptr elementtype(i64) %1)
|
|
||||||
ret i64 %2
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
||||||
; RUN: llc --mtriple=loongarch32 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA32
|
|
||||||
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA64
|
|
||||||
|
|
||||||
define i32 @m_offset_neg_2049(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_neg_2049:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: lu12i.w $a1, -1
|
|
||||||
; LA32-NEXT: ori $a1, $a1, 2047
|
|
||||||
; LA32-NEXT: add.w $a0, $a0, $a1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_neg_2049:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: lu12i.w $a1, -1
|
|
||||||
; LA64-NEXT: ori $a1, $a1, 2047
|
|
||||||
; LA64-NEXT: add.d $a0, $a0, $a1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -2049
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_neg_2048(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_neg_2048:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, -2048
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_neg_2048:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, -2048
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -2048
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_neg_1(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_neg_1:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, -1
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_neg_1:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, -1
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 -1
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_0(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_0:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_0:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %p)
|
|
||||||
ret i32 %1
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_1(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_1:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, 1
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_1:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, 1
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 1
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_2047(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_2047:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, 2047
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_2047:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, 2047
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 2047
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @m_offset_2048(ptr %p) nounwind {
|
|
||||||
; LA32-LABEL: m_offset_2048:
|
|
||||||
; LA32: # %bb.0:
|
|
||||||
; LA32-NEXT: ori $a1, $zero, 2048
|
|
||||||
; LA32-NEXT: add.w $a0, $a0, $a1
|
|
||||||
; LA32-NEXT: #APP
|
|
||||||
; LA32-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA32-NEXT: #NO_APP
|
|
||||||
; LA32-NEXT: ret
|
|
||||||
;
|
|
||||||
; LA64-LABEL: m_offset_2048:
|
|
||||||
; LA64: # %bb.0:
|
|
||||||
; LA64-NEXT: ori $a1, $zero, 2048
|
|
||||||
; LA64-NEXT: add.d $a0, $a0, $a1
|
|
||||||
; LA64-NEXT: #APP
|
|
||||||
; LA64-NEXT: ld.w $a0, $a0, 0
|
|
||||||
; LA64-NEXT: #NO_APP
|
|
||||||
; LA64-NEXT: ret
|
|
||||||
%1 = getelementptr inbounds i8, ptr %p, i32 2048
|
|
||||||
%2 = call i32 asm "ld.w $0, $1", "=r,*m"(ptr elementtype(i32) %1)
|
|
||||||
ret i32 %2
|
|
||||||
}
|
|
Loading…
Reference in New Issue