From 2a90cde4fd97c131a9756d672582e58313b74864 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 30 Mar 2015 22:40:40 +0000 Subject: [PATCH] [bpf] add support for bswap instructions BPF has cpu_to_be and cpu_to_le instructions. For now assume little endian and generate cpu_to_be for ISD::BSWAP. llvm-svn: 233620 --- llvm/lib/Target/BPF/BPFISelLowering.cpp | 1 - llvm/lib/Target/BPF/BPFInstrInfo.td | 27 +++++++++++++++++++++++++ llvm/test/CodeGen/BPF/intrinsics.ll | 25 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp index 8b7a061e8218..cdcf0936a3de 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -137,7 +137,6 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); - setOperationAction(ISD::BSWAP, MVT::i64, Expand); setOperationAction(ISD::CTTZ, MVT::i64, Custom); setOperationAction(ISD::CTLZ, MVT::i64, Custom); setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Custom); diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td index 1ab7a7754cd3..346c7f9b787c 100644 --- a/llvm/lib/Target/BPF/BPFInstrInfo.td +++ b/llvm/lib/Target/BPF/BPFInstrInfo.td @@ -484,6 +484,33 @@ def XADD64 : XADD<3, "xadd64", atomic_load_add_64>; // undefined def XADD8 : XADD<2, "xadd8", atomic_load_add_8>; } +// bswap16, bswap32, bswap64 +class BSWAP SizeOp, string OpcodeStr, list Pattern> + : InstBPF<(outs GPR:$dst), (ins GPR:$src), + !strconcat(OpcodeStr, "\t$dst"), + Pattern> { + bits<4> op; + bits<1> BPFSrc; + bits<4> dst; + bits<32> imm; + + let Inst{63-60} = op; + let Inst{59} = BPFSrc; + let Inst{51-48} = dst; + let Inst{31-0} = imm; + + let op = 0xd; // BPF_END + let BPFSrc = 1; // BPF_TO_BE (TODO: use BPF_TO_LE for big-endian target) + let BPFClass = 4; // BPF_ALU + let imm = SizeOp; +} + +let Constraints = "$dst = $src" in { +def BSWAP16 : BSWAP<16, "bswap16", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>; +def BSWAP32 : BSWAP<32, "bswap32", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>; +def BSWAP64 : BSWAP<64, "bswap64", [(set GPR:$dst, (bswap GPR:$src))]>; +} + let Defs = [R0, R1, R2, R3, R4, R5], Uses = [R6], hasSideEffects = 1, hasExtraDefRegAllocReq = 1, hasExtraSrcRegAllocReq = 1, mayLoad = 1 in { class LOAD_ABS SizeOp, string OpcodeStr, Intrinsic OpNode> diff --git a/llvm/test/CodeGen/BPF/intrinsics.ll b/llvm/test/CodeGen/BPF/intrinsics.ll index 01ba4c770daf..98b57deb7c8d 100644 --- a/llvm/test/CodeGen/BPF/intrinsics.ll +++ b/llvm/test/CodeGen/BPF/intrinsics.ll @@ -61,3 +61,28 @@ entry: declare void @bar(i64, i32) #1 declare i64 @llvm.bpf.pseudo(i64, i64) #2 + +define i32 @bswap(i64 %a, i64 %b, i64 %c) #0 { +entry: + %0 = tail call i64 @llvm.bswap.i64(i64 %a) + %conv = trunc i64 %b to i32 + %1 = tail call i32 @llvm.bswap.i32(i32 %conv) + %conv1 = zext i32 %1 to i64 + %add = add i64 %conv1, %0 + %conv2 = trunc i64 %c to i16 + %2 = tail call i16 @llvm.bswap.i16(i16 %conv2) + %conv3 = zext i16 %2 to i64 + %add4 = add i64 %add, %conv3 + %conv5 = trunc i64 %add4 to i32 + ret i32 %conv5 +; CHECK-LABEL: bswap: +; CHECK: bswap64 r1 # encoding: [0xdc,0x01,0x00,0x00,0x40,0x00,0x00,0x00] +; CHECK: bswap32 r2 # encoding: [0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00] +; CHECK: add r2, r1 # encoding: [0x0f,0x12,0x00,0x00,0x00,0x00,0x00,0x00] +; CHECK: bswap16 r3 # encoding: [0xdc,0x03,0x00,0x00,0x10,0x00,0x00,0x00] +; CHECK: add r2, r3 # encoding: [0x0f,0x32,0x00,0x00,0x00,0x00,0x00,0x00] +} + +declare i64 @llvm.bswap.i64(i64) #1 +declare i32 @llvm.bswap.i32(i32) #1 +declare i16 @llvm.bswap.i16(i16) #1