Skip to content

Commit ce1dc9d

Browse files
Thomas Johnsonmarkschimmel
authored andcommitted
[ARC] Add codegen for the readcyclecounter intrinsic along with disassembly for associated instructions
Differential Revision: https://reviews.llvm.org/D108598
1 parent 1537563 commit ce1dc9d

File tree

7 files changed

+170
-4
lines changed

7 files changed

+170
-4
lines changed

llvm/lib/Target/ARC/ARCISelLowering.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,31 @@ static ARCCC::CondCode ISDCCtoARCCC(ISD::CondCode isdCC) {
6868
}
6969
}
7070

71+
void ARCTargetLowering::ReplaceNodeResults(SDNode *N,
72+
SmallVectorImpl<SDValue> &Results,
73+
SelectionDAG &DAG) const {
74+
LLVM_DEBUG(dbgs() << "[ARC-ISEL] ReplaceNodeResults ");
75+
LLVM_DEBUG(N->dump(&DAG));
76+
LLVM_DEBUG(dbgs() << "; use_count=" << N->use_size() << "\n");
77+
78+
switch (N->getOpcode()) {
79+
case ISD::READCYCLECOUNTER:
80+
if (N->getValueType(0) == MVT::i64) {
81+
// We read the TIMER0 and zero-extend it to 64-bits as the intrinsic
82+
// requires.
83+
SDValue V =
84+
DAG.getNode(ISD::READCYCLECOUNTER, SDLoc(N),
85+
DAG.getVTList(MVT::i32, MVT::Other), N->getOperand(0));
86+
SDValue Op = DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N), MVT::i64, V);
87+
Results.push_back(Op);
88+
Results.push_back(V.getValue(1));
89+
}
90+
break;
91+
default:
92+
break;
93+
}
94+
}
95+
7196
ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM,
7297
const ARCSubtarget &Subtarget)
7398
: TargetLowering(TM), Subtarget(Subtarget) {
@@ -140,6 +165,10 @@ ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM,
140165
// when the HasBitScan predicate is available.
141166
setOperationAction(ISD::CTLZ, MVT::i32, Legal);
142167
setOperationAction(ISD::CTTZ, MVT::i32, Legal);
168+
169+
setOperationAction(ISD::READCYCLECOUNTER, MVT::i32, Legal);
170+
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64,
171+
isTypeLegal(MVT::i64) ? Legal : Custom);
143172
}
144173

145174
const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const {
@@ -766,6 +795,13 @@ SDValue ARCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
766795
return LowerJumpTable(Op, DAG);
767796
case ISD::VASTART:
768797
return LowerVASTART(Op, DAG);
798+
case ISD::READCYCLECOUNTER:
799+
// As of LLVM 3.8, the lowering code insists that we customize it even
800+
// though we've declared the i32 version as legal. This is because it only
801+
// thinks i64 is the truly supported version. We've already converted the
802+
// i64 version to a widened i32.
803+
assert(Op.getSimpleValueType() == MVT::i32);
804+
return Op;
769805
default:
770806
llvm_unreachable("unimplemented operand");
771807
}

llvm/lib/Target/ARC/ARCISelLowering.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ class ARCTargetLowering : public TargetLowering {
7777
private:
7878
const ARCSubtarget &Subtarget;
7979

80+
void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
81+
SelectionDAG &DAG) const override;
82+
8083
// Lower Operand helpers
8184
SDValue LowerCallArguments(SDValue Chain, CallingConv::ID CallConv,
8285
bool isVarArg,

llvm/lib/Target/ARC/ARCInstrFormats.td

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,50 @@ class F32_DOP_RS12<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
395395
let Inst{5-0} = S12{11-6};
396396
}
397397

398+
// 1-register, signed 12-bit immediate Dual Operand instruction.
399+
// This instruction uses B as the first operand (i.e., lr B, [%count0]).
400+
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
401+
// |B[2-0] | 1| 0| subop| F|B[5-3] |S12[5-0] |S12[11-6] |
402+
class F32_SOP_RS12<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
403+
string asmstr, list<dag> pattern> :
404+
InstARC<4, outs, ins, asmstr, pattern> {
405+
bits<6> B;
406+
bits<12> S12;
407+
408+
let Inst{31-27} = major;
409+
let Inst{26-24} = B{2-0};
410+
let Inst{23-22} = 0b10;
411+
let Inst{21-16} = subop;
412+
let Inst{15} = F;
413+
let Inst{14-12} = B{5-3};
414+
let Inst{11-6} = S12{5-0};
415+
let Inst{5-0} = S12{11-6};
416+
417+
let DecoderMethod = "DecodeSOPwithRS12";
418+
}
419+
420+
// 1-register, unsigned 6-bit immediate Dual Operand instruction.
421+
// This instruction uses B as the first operand.
422+
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
423+
// |B[2-0] | 0| 1| subop| F|B[5-3] |U6 |0|0|0|0|0|0|
424+
class F32_SOP_RU6<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
425+
string asmstr, list<dag> pattern> :
426+
InstARC<4, outs, ins, asmstr, pattern> {
427+
bits<6> B;
428+
bits<6> U6;
429+
430+
let Inst{31-27} = major;
431+
let Inst{26-24} = B{2-0};
432+
let Inst{23-22} = 0b01;
433+
let Inst{21-16} = subop;
434+
let Inst{15} = F;
435+
let Inst{14-12} = B{5-3};
436+
let Inst{11-6} = U6;
437+
let Inst{5-0} = 0;
438+
439+
let DecoderMethod = "DecodeSOPwithRU6";
440+
}
441+
398442
// 2-register, 32-bit immediate (LImm) Dual Operand instruction.
399443
// This instruction has the 32-bit immediate in bits 32-63, and
400444
// 62 in the C register operand slot, but is otherwise F32_DOP_RR.

llvm/lib/Target/ARC/ARCInstrInfo.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,19 @@ multiclass MultiPat<SDPatternOperator InFrag,
270270
def _rrlimm : Pat<(InFrag i32:$B, imm32:$LImm), (RRLImm i32:$B, imm32:$LImm)>;
271271
}
272272

273+
// NOTE: This could be specialized later with a custom `PrintMethod` for
274+
// displaying the aux register name. E.g. `[%count0]` instead of [33].
275+
def AuxReg : Operand<i32>;
276+
277+
def LR_rs12 : F32_SOP_RS12<0b00100, 0b101010, 0,
278+
(outs GPR32:$B), (ins AuxReg:$C),
279+
"lr\t$B, [$C]", []>;
280+
def LR_ru6 : F32_SOP_RU6<0b00100, 0b101010, 0,
281+
(outs GPR32:$B), (ins AuxReg:$C),
282+
"lr\t$B, [$C]", []>;
283+
284+
def: Pat<(i32 readcyclecounter), (LR_rs12 0x21) >; // read timer
285+
273286
// ---------------------------------------------------------------------------
274287
// Instruction definitions and patterns for 3 operand binary instructions.
275288
// ---------------------------------------------------------------------------

llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ static DecodeStatus DecodeStLImmInstruction(MCInst &, uint64_t, uint64_t,
107107
static DecodeStatus DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t,
108108
const void *);
109109

110+
static DecodeStatus DecodeSOPwithRS12(MCInst &, uint64_t, uint64_t,
111+
const void *);
112+
113+
static DecodeStatus DecodeSOPwithRU6(MCInst &, uint64_t, uint64_t,
114+
const void *);
115+
110116
static DecodeStatus DecodeCCRU6Instruction(MCInst &, uint64_t, uint64_t,
111117
const void *);
112118

@@ -311,6 +317,29 @@ static DecodeStatus DecodeCCRU6Instruction(MCInst &Inst, uint64_t Insn,
311317
return MCDisassembler::Success;
312318
}
313319

320+
static DecodeStatus DecodeSOPwithRU6(MCInst &Inst, uint64_t Insn,
321+
uint64_t Address, const void *Decoder) {
322+
unsigned DstB = decodeBField(Insn);
323+
DecodeGPR32RegisterClass(Inst, DstB, Address, Decoder);
324+
using Field = decltype(Insn);
325+
Field U6 = fieldFromInstruction(Insn, 6, 6);
326+
Inst.addOperand(MCOperand::createImm(U6));
327+
return MCDisassembler::Success;
328+
}
329+
330+
static DecodeStatus DecodeSOPwithRS12(MCInst &Inst, uint64_t Insn,
331+
uint64_t Address, const void *Decoder) {
332+
unsigned DstB = decodeBField(Insn);
333+
DecodeGPR32RegisterClass(Inst, DstB, Address, Decoder);
334+
using Field = decltype(Insn);
335+
Field Lower = fieldFromInstruction(Insn, 6, 6);
336+
Field Upper = fieldFromInstruction(Insn, 0, 5);
337+
Field Sign = fieldFromInstruction(Insn, 5, 1) ? -1 : 1;
338+
Field Result = Sign * ((Upper << 6) + Lower);
339+
Inst.addOperand(MCOperand::createImm(Result));
340+
return MCDisassembler::Success;
341+
}
342+
314343
DecodeStatus ARCDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
315344
ArrayRef<uint8_t> Bytes,
316345
uint64_t Address,

llvm/test/CodeGen/ARC/intrinsics.ll

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,29 @@ target triple = "arc"
44

55
declare i32 @llvm.ctlz.i32(i32, i1)
66
declare i32 @llvm.cttz.i32(i32, i1)
7+
declare i64 @llvm.readcyclecounter()
78

8-
; CHECK-LABEL: clz32:
9+
; CHECK-LABEL: test_ctlz_i32:
910
; CHECK: fls.f %r0, %r0
1011
; CHECK-NEXT: mov.eq %r0, 32
1112
; CHECK-NEXT: rsub.ne %r0, %r0, 31
12-
define i32 @clz32(i32 %x) {
13+
define i32 @test_ctlz_i32(i32 %x) {
1314
%a = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
1415
ret i32 %a
1516
}
1617

17-
; CHECK-LABEL: ctz32:
18+
; CHECK-LABEL: test_cttz_i32:
1819
; CHECK: ffs.f %r0, %r0
1920
; CHECK-NEXT: mov.eq %r0, 32
20-
define i32 @ctz32(i32 %x) {
21+
define i32 @test_cttz_i32(i32 %x) {
2122
%a = call i32 @llvm.cttz.i32(i32 %x, i1 false)
2223
ret i32 %a
2324
}
25+
26+
; CHECK-LABEL: test_readcyclecounter:
27+
; CHECK: lr %r0, [33]
28+
; CHECK-NEXT: mov %r1, 0
29+
define i64 @test_readcyclecounter() nounwind {
30+
%a = call i64 @llvm.readcyclecounter()
31+
ret i64 %a
32+
}

llvm/test/MC/Disassembler/ARC/ldst.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,35 @@
9292

9393
# CHECK: stb.di.ab %r0, [%r9,64]
9494
0x40 0x19 0x32 0x10
95+
96+
# LR instructions with a U6 immediate bit pattern
97+
# ([33] maps to the [%count0] auxilary register)
98+
99+
# CHECK: lr %r0, [33]
100+
0x6a 0x20 0x40 0x08
101+
102+
# CHECK: lr %r7, [33]
103+
0x6a 0x27 0x40 0x08
104+
105+
# CHECK: lr %r15, [33]
106+
0x6a 0x27 0x40 0x18
107+
108+
# CHECK: lr %r22, [33]
109+
0x6a 0x26 0x40 0x28
110+
111+
# LR instructions with an S12 immediate bit pattern
112+
113+
# CHECK: lr %r0, [33]
114+
0xaa 0x20 0x40 0x08
115+
116+
# The following don't necessarily map to real auxilary registers, but
117+
# the different range of numbers helps exercise the S12 decoder.
118+
119+
# CHECK: lr %r0, [-33]
120+
0xaa 0x20 0x60 0x08
121+
122+
# CHECK: lr %r0, [97]
123+
0xaa 0x20 0x41 0x08
124+
125+
# CHECK: lr %r0, [-97]
126+
0xaa 0x20 0x61 0x08

0 commit comments

Comments
 (0)