Skip to content

Commit

Permalink
[ARM] Add support for mrrc/mrrc2 intrinsics.
Browse files Browse the repository at this point in the history
Reapplying patch as it was reverted when it was first
committed because of an assertion failure when the
mrrc2 intrinsic was called in ARM mode. The failure
was happening because the instruction was being built
in ARMISelDAGToDAG.cpp and the tablegen description for
mrrc2 instruction doesn't allow you to use a predicate.

The ARM architecture manuals do say that mrrc2 in ARM
mode can be predicated with AL in assembly but this has
no effect on the encoding of the instruction as the top
4 bits will always be 1111 not 1110 which is the encoding
for the condition AL.

Differential Revision: http://reviews.llvm.org/D21408

llvm-svn: 272982
  • Loading branch information
rs-arm committed Jun 17, 2016
1 parent a324487 commit 39d2d09
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 19 deletions.
15 changes: 9 additions & 6 deletions llvm/include/llvm/IR/IntrinsicsARM.td
Expand Up @@ -123,12 +123,15 @@ def int_arm_cdp2 : GCCBuiltin<"__builtin_arm_cdp2">,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>;

// Move from two registers to coprocessor
def int_arm_mcrr : GCCBuiltin<"__builtin_arm_mcrr">,
Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;
def int_arm_mcrr2 : GCCBuiltin<"__builtin_arm_mcrr2">,
Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;
def int_arm_mcrr : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;
def int_arm_mcrr2 : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;

def int_arm_mrrc : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;
def int_arm_mrrc2 : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty,
llvm_i32_ty, llvm_i32_ty], []>;

//===----------------------------------------------------------------------===//
// CRC32
Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
Expand Up @@ -3335,6 +3335,41 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
default:
break;

case Intrinsic::arm_mrrc:
case Intrinsic::arm_mrrc2: {
SDLoc dl(N);
SDValue Chain = N->getOperand(0);
unsigned Opc;

if (Subtarget->isThumb())
Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::t2MRRC : ARM::t2MRRC2);
else
Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::MRRC : ARM::MRRC2);

SmallVector<SDValue, 5> Ops;
Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(), dl)); /* coproc */
Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), dl)); /* opc */
Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(4))->getZExtValue(), dl)); /* CRm */

// The mrrc2 instruction in ARM doesn't allow predicates, the top 4 bits of the encoded
// instruction will always be '1111' but it is possible in assembly language to specify
// AL as a predicate to mrrc2 but it doesn't make any difference to the encoded instruction.
if (Opc != ARM::MRRC2) {
Ops.push_back(getAL(CurDAG, dl));
Ops.push_back(CurDAG->getRegister(0, MVT::i32));
}

Ops.push_back(Chain);

// Writes to two registers.
std::vector<EVT> RetType;
RetType.push_back(MVT::i32);
RetType.push_back(MVT::i32);
RetType.push_back(MVT::Other);

ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, RetType, Ops));
return;
}
case Intrinsic::arm_ldaexd:
case Intrinsic::arm_ldrexd: {
SDLoc dl(N);
Expand Down
15 changes: 10 additions & 5 deletions llvm/lib/Target/ARM/ARMInstrInfo.td
Expand Up @@ -5145,9 +5145,9 @@ def MRRC : MovRRCopro<"mrrc", 1 /* from coprocessor to ARM core register */,
(outs GPRnopc:$Rt, GPRnopc:$Rt2),
(ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRm), []>;

class MovRRCopro2<string opc, bit direction, list<dag> pattern = []>
: ABXI<0b1100, (outs), (ins p_imm:$cop, imm0_15:$opc1,
GPRnopc:$Rt, GPRnopc:$Rt2, c_imm:$CRm), NoItinerary,
class MovRRCopro2<string opc, bit direction, dag oops, dag iops,
list<dag> pattern = []>
: ABXI<0b1100, oops, iops, NoItinerary,
!strconcat(opc, "\t$cop, $opc1, $Rt, $Rt2, $CRm"), pattern>,
Requires<[PreV8]> {
let Inst{31-28} = 0b1111;
Expand All @@ -5166,13 +5166,18 @@ class MovRRCopro2<string opc, bit direction, list<dag> pattern = []>
let Inst{7-4} = opc1;
let Inst{3-0} = CRm;

let DecoderMethod = "DecodeMRRC2";
let DecoderMethod = "DecoderForMRRC2AndMCRR2";
}

def MCRR2 : MovRRCopro2<"mcrr2", 0 /* from ARM core register to coprocessor */,
(outs), (ins p_imm:$cop, imm0_15:$opc1, GPRnopc:$Rt,
GPRnopc:$Rt2, c_imm:$CRm),
[(int_arm_mcrr2 imm:$cop, imm:$opc1, GPRnopc:$Rt,
GPRnopc:$Rt2, imm:$CRm)]>;
def MRRC2 : MovRRCopro2<"mrrc2", 1 /* from coprocessor to ARM core register */>;

def MRRC2 : MovRRCopro2<"mrrc2", 1 /* from coprocessor to ARM core register */,
(outs GPRnopc:$Rt, GPRnopc:$Rt2),
(ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRm), []>;

//===----------------------------------------------------------------------===//
// Move between special register and ARM core register
Expand Down
34 changes: 26 additions & 8 deletions llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
Expand Up @@ -395,8 +395,8 @@ static DecodeStatus DecodeT2ShifterImmOperand(MCInst &Inst, unsigned Val,

static DecodeStatus DecodeLDR(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeMRRC2(llvm::MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder);
static DecodeStatus DecoderForMRRC2AndMCRR2(llvm::MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder);
#include "ARMGenDisassemblerTables.inc"

static MCDisassembler *createARMDisassembler(const Target &T,
Expand Down Expand Up @@ -5265,8 +5265,8 @@ static DecodeStatus DecodeLDR(MCInst &Inst, unsigned Val,
return S;
}

static DecodeStatus DecodeMRRC2(llvm::MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder) {
static DecodeStatus DecoderForMRRC2AndMCRR2(llvm::MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder) {

DecodeStatus S = MCDisassembler::Success;

Expand All @@ -5282,12 +5282,30 @@ static DecodeStatus DecodeMRRC2(llvm::MCInst &Inst, unsigned Val,
if (Rt == Rt2)
S = MCDisassembler::SoftFail;

// We have to check if the instruction is MRRC2
// or MCRR2 when constructing the operands for
// Inst. Reason is because MRRC2 stores to two
// registers so it's tablegen desc has has two
// outputs whereas MCRR doesn't store to any
// registers so all of it's operands are listed
// as inputs, therefore the operand order for
// MRRC2 needs to be [Rt, Rt2, cop, opc1, CRm]
// and MCRR2 operand order is [cop, opc1, Rt, Rt2, CRm]

if (Inst.getOpcode() == ARM::MRRC2) {
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt, Address, Decoder)))
return MCDisassembler::Fail;
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt2, Address, Decoder)))
return MCDisassembler::Fail;
}
Inst.addOperand(MCOperand::createImm(cop));
Inst.addOperand(MCOperand::createImm(opc1));
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt, Address, Decoder)))
return MCDisassembler::Fail;
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt2, Address, Decoder)))
return MCDisassembler::Fail;
if (Inst.getOpcode() == ARM::MCRR2) {
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt, Address, Decoder)))
return MCDisassembler::Fail;
if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rt2, Address, Decoder)))
return MCDisassembler::Fail;
}
Inst.addOperand(MCOperand::createImm(CRm));

return S;
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/CodeGen/ARM/intrinsics-coprocessor.ll
Expand Up @@ -35,6 +35,10 @@ entry:
tail call void @llvm.arm.stc2(i32 7, i32 3, i8* %i) nounwind
; CHECK: stc2l p7, c3, [r{{[0-9]+}}]
tail call void @llvm.arm.stc2l(i32 7, i32 3, i8* %i) nounwind
; CHECK: mrrc p1, #2, r{{[0-9]+}}, r{{[0-9]+}}, c3
%2 = tail call { i32, i32 } @llvm.arm.mrrc(i32 1, i32 2, i32 3) nounwind
; CHECK: mrrc2 p1, #2, r{{[0-9]+}}, r{{[0-9]+}}, c3
%3 = tail call { i32, i32 } @llvm.arm.mrrc2(i32 1, i32 2, i32 3) nounwind
ret void
}

Expand Down Expand Up @@ -69,3 +73,7 @@ declare i32 @llvm.arm.mrc2(i32, i32, i32, i32, i32) nounwind
declare void @llvm.arm.mcr(i32, i32, i32, i32, i32, i32) nounwind

declare i32 @llvm.arm.mrc(i32, i32, i32, i32, i32) nounwind

declare { i32, i32 } @llvm.arm.mrrc(i32, i32, i32) nounwind

declare { i32, i32 } @llvm.arm.mrrc2(i32, i32, i32) nounwind

0 comments on commit 39d2d09

Please sign in to comment.