mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 03:23:01 +02:00
[RISCV] Add basic support for inline asm constraints
llvm-svn: 322217
This commit is contained in:
parent
7d25eb9809
commit
22e7f0dc96
@ -41,6 +41,13 @@ public:
|
||||
|
||||
void EmitInstruction(const MachineInstr *MI) override;
|
||||
|
||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode,
|
||||
raw_ostream &OS) override;
|
||||
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode,
|
||||
raw_ostream &OS) override;
|
||||
|
||||
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
||||
const MachineInstr *MI);
|
||||
|
||||
@ -65,6 +72,54 @@ void RISCVAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant,
|
||||
const char *ExtraCode, raw_ostream &OS) {
|
||||
if (AsmVariant != 0)
|
||||
report_fatal_error("There are no defined alternate asm variants");
|
||||
|
||||
// First try the generic code, which knows about modifiers like 'c' and 'n'.
|
||||
if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
|
||||
return false;
|
||||
|
||||
if (!ExtraCode) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Immediate:
|
||||
OS << MO.getImm();
|
||||
return false;
|
||||
case MachineOperand::MO_Register:
|
||||
OS << RISCVInstPrinter::getRegisterName(MO.getReg());
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
||||
unsigned OpNo, unsigned AsmVariant,
|
||||
const char *ExtraCode,
|
||||
raw_ostream &OS) {
|
||||
if (AsmVariant != 0)
|
||||
report_fatal_error("There are no defined alternate asm variants");
|
||||
|
||||
if (!ExtraCode) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
// For now, we only support register memory operands in registers and
|
||||
// assume there is no addend
|
||||
if (!MO.isReg())
|
||||
return true;
|
||||
|
||||
OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
|
||||
}
|
||||
|
||||
// Force static initialization.
|
||||
extern "C" void LLVMInitializeRISCVAsmPrinter() {
|
||||
RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
|
||||
|
@ -44,6 +44,9 @@ public:
|
||||
|
||||
void Select(SDNode *Node) override;
|
||||
|
||||
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
|
||||
std::vector<SDValue> &OutOps) override;
|
||||
|
||||
bool SelectAddrFI(SDValue Addr, SDValue &Base);
|
||||
|
||||
// Include the pieces autogenerated from the target description.
|
||||
@ -93,6 +96,22 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
|
||||
SelectCode(Node);
|
||||
}
|
||||
|
||||
bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
|
||||
const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
|
||||
switch (ConstraintID) {
|
||||
case InlineAsm::Constraint_i:
|
||||
case InlineAsm::Constraint_m:
|
||||
// We just support simple memory operands that have a single address
|
||||
// operand and need no special handling.
|
||||
OutOps.push_back(Op);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
|
||||
if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
||||
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
|
||||
|
@ -994,3 +994,21 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::pair<unsigned, const TargetRegisterClass *>
|
||||
RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||
StringRef Constraint,
|
||||
MVT VT) const {
|
||||
// First, see if this is a constraint that directly corresponds to a
|
||||
// RISCV register class.
|
||||
if (Constraint.size() == 1) {
|
||||
switch (Constraint[0]) {
|
||||
case 'r':
|
||||
return std::make_pair(0U, &RISCV::GPRRegClass);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
|
||||
}
|
||||
|
@ -43,6 +43,10 @@ public:
|
||||
// This method returns the name of a target specific DAG node.
|
||||
const char *getTargetNodeName(unsigned Opcode) const override;
|
||||
|
||||
std::pair<unsigned, const TargetRegisterClass *>
|
||||
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||
StringRef Constraint, MVT VT) const override;
|
||||
|
||||
MachineBasicBlock *
|
||||
EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MachineBasicBlock *BB) const override;
|
||||
|
83
test/CodeGen/RISCV/inline-asm.ll
Normal file
83
test/CodeGen/RISCV/inline-asm.ll
Normal file
@ -0,0 +1,83 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
|
||||
; RUN: | FileCheck -check-prefix=RV32I %s
|
||||
|
||||
@gi = external global i32
|
||||
|
||||
define i32 @constraint_r(i32 %a) {
|
||||
; RV32I-LABEL: constraint_r:
|
||||
; RV32I: # %bb.0:
|
||||
; RV32I-NEXT: addi sp, sp, -16
|
||||
; RV32I-NEXT: sw ra, 12(sp)
|
||||
; RV32I-NEXT: sw s0, 8(sp)
|
||||
; RV32I-NEXT: addi s0, sp, 16
|
||||
; RV32I-NEXT: lui a1, %hi(gi)
|
||||
; RV32I-NEXT: addi a1, a1, %lo(gi)
|
||||
; RV32I-NEXT: lw a1, 0(a1)
|
||||
; RV32I-NEXT: #APP
|
||||
; RV32I-NEXT: add a0, a0, a1
|
||||
; RV32I-NEXT: #NO_APP
|
||||
; RV32I-NEXT: lw s0, 8(sp)
|
||||
; RV32I-NEXT: lw ra, 12(sp)
|
||||
; RV32I-NEXT: addi sp, sp, 16
|
||||
; RV32I-NEXT: ret
|
||||
%1 = load i32, i32* @gi
|
||||
%2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1)
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
define i32 @constraint_i(i32 %a) {
|
||||
; RV32I-LABEL: constraint_i:
|
||||
; RV32I: # %bb.0:
|
||||
; RV32I-NEXT: addi sp, sp, -16
|
||||
; RV32I-NEXT: sw ra, 12(sp)
|
||||
; RV32I-NEXT: sw s0, 8(sp)
|
||||
; RV32I-NEXT: addi s0, sp, 16
|
||||
; RV32I-NEXT: #APP
|
||||
; RV32I-NEXT: addi a0, a0, 113
|
||||
; RV32I-NEXT: #NO_APP
|
||||
; RV32I-NEXT: lw s0, 8(sp)
|
||||
; RV32I-NEXT: lw ra, 12(sp)
|
||||
; RV32I-NEXT: addi sp, sp, 16
|
||||
; RV32I-NEXT: ret
|
||||
%1 = load i32, i32* @gi
|
||||
%2 = tail call i32 asm "addi $0, $1, $2", "=r,r,i"(i32 %a, i32 113)
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
define void @constraint_m(i32* %a) {
|
||||
; RV32I-LABEL: constraint_m:
|
||||
; RV32I: # %bb.0:
|
||||
; RV32I-NEXT: addi sp, sp, -16
|
||||
; RV32I-NEXT: sw ra, 12(sp)
|
||||
; RV32I-NEXT: sw s0, 8(sp)
|
||||
; RV32I-NEXT: addi s0, sp, 16
|
||||
; RV32I-NEXT: #APP
|
||||
; RV32I-NEXT: #NO_APP
|
||||
; RV32I-NEXT: lw s0, 8(sp)
|
||||
; RV32I-NEXT: lw ra, 12(sp)
|
||||
; RV32I-NEXT: addi sp, sp, 16
|
||||
; RV32I-NEXT: ret
|
||||
call void asm sideeffect "", "=*m"(i32* %a)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @constraint_m2(i32* %a) {
|
||||
; RV32I-LABEL: constraint_m2:
|
||||
; RV32I: # %bb.0:
|
||||
; RV32I-NEXT: addi sp, sp, -16
|
||||
; RV32I-NEXT: sw ra, 12(sp)
|
||||
; RV32I-NEXT: sw s0, 8(sp)
|
||||
; RV32I-NEXT: addi s0, sp, 16
|
||||
; RV32I-NEXT: #APP
|
||||
; RV32I-NEXT: lw a0, 0(a0)
|
||||
; RV32I-NEXT: #NO_APP
|
||||
; RV32I-NEXT: lw s0, 8(sp)
|
||||
; RV32I-NEXT: lw ra, 12(sp)
|
||||
; RV32I-NEXT: addi sp, sp, 16
|
||||
; RV32I-NEXT: ret
|
||||
%1 = tail call i32 asm "lw $0, $1", "=r,*m"(i32* %a) nounwind
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; TODO: expend tests for more complex constraints, out of range immediates etc
|
Loading…
Reference in New Issue
Block a user