Skip to content

Commit

Permalink
[AArch64][FastISel] Handle CRC32 intrinsics
Browse files Browse the repository at this point in the history
With a similar reason as D148023; some applications make heavy use of
the CRC32 intrinsic (e.g., as part of a hash function) and therefore
benefit from avoiding frequent SelectionDAG fallbacks. In our
application, we get a 2% compile-time improvement.

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D148917
  • Loading branch information
aengelke committed Apr 28, 2023
1 parent 8ead003 commit ab21bea
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
52 changes: 52 additions & 0 deletions llvm/lib/Target/AArch64/AArch64FastISel.cpp
Expand Up @@ -53,6 +53,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
Expand Down Expand Up @@ -3776,6 +3777,57 @@ bool AArch64FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
updateValueMap(II, ResultReg1, 2);
return true;
}
case Intrinsic::aarch64_crc32b:
case Intrinsic::aarch64_crc32h:
case Intrinsic::aarch64_crc32w:
case Intrinsic::aarch64_crc32x:
case Intrinsic::aarch64_crc32cb:
case Intrinsic::aarch64_crc32ch:
case Intrinsic::aarch64_crc32cw:
case Intrinsic::aarch64_crc32cx: {
if (!Subtarget->hasCRC())
return false;

unsigned Opc;
switch (II->getIntrinsicID()) {
default:
llvm_unreachable("Unexpected intrinsic!");
case Intrinsic::aarch64_crc32b:
Opc = AArch64::CRC32Brr;
break;
case Intrinsic::aarch64_crc32h:
Opc = AArch64::CRC32Hrr;
break;
case Intrinsic::aarch64_crc32w:
Opc = AArch64::CRC32Wrr;
break;
case Intrinsic::aarch64_crc32x:
Opc = AArch64::CRC32Xrr;
break;
case Intrinsic::aarch64_crc32cb:
Opc = AArch64::CRC32CBrr;
break;
case Intrinsic::aarch64_crc32ch:
Opc = AArch64::CRC32CHrr;
break;
case Intrinsic::aarch64_crc32cw:
Opc = AArch64::CRC32CWrr;
break;
case Intrinsic::aarch64_crc32cx:
Opc = AArch64::CRC32CXrr;
break;
}

Register LHSReg = getRegForValue(II->getArgOperand(0));
Register RHSReg = getRegForValue(II->getArgOperand(1));
if (!LHSReg || !RHSReg)
return false;

Register ResultReg =
fastEmitInst_rr(Opc, &AArch64::GPR32RegClass, LHSReg, RHSReg);
updateValueMap(II, ResultReg);
return true;
}
}
return false;
}
Expand Down
71 changes: 71 additions & 0 deletions llvm/test/CodeGen/AArch64/arm64-fast-isel-crc32.ll
@@ -0,0 +1,71 @@
; RUN: llc -mtriple=arm64-eabi -fast-isel -fast-isel-abort=3 -mattr=+crc -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-eabi -fast-isel -fast-isel-abort=3 -mattr=+v8r -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-eabi -fast-isel -fast-isel-abort=3 -mcpu=cortex-a53 -mattr=+crc -o - %s | FileCheck %s

; Note: tests are a copy of arm64-crc32.ll

define i32 @test_crc32b(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32b:
; CHECK: crc32b w0, w0, w1
%val = call i32 @llvm.aarch64.crc32b(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32h(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32h:
; CHECK: crc32h w0, w0, w1
%val = call i32 @llvm.aarch64.crc32h(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32w(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32w:
; CHECK: crc32w w0, w0, w1
%val = call i32 @llvm.aarch64.crc32w(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32x(i32 %cur, i64 %next) {
; CHECK-LABEL: test_crc32x:
; CHECK: crc32x w0, w0, x1
%val = call i32 @llvm.aarch64.crc32x(i32 %cur, i64 %next)
ret i32 %val
}

define i32 @test_crc32cb(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32cb:
; CHECK: crc32cb w0, w0, w1
%val = call i32 @llvm.aarch64.crc32cb(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32ch(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32ch:
; CHECK: crc32ch w0, w0, w1
%val = call i32 @llvm.aarch64.crc32ch(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32cw(i32 %cur, i32 %next) {
; CHECK-LABEL: test_crc32cw:
; CHECK: crc32cw w0, w0, w1
%val = call i32 @llvm.aarch64.crc32cw(i32 %cur, i32 %next)
ret i32 %val
}

define i32 @test_crc32cx(i32 %cur, i64 %next) {
; CHECK-LABEL: test_crc32cx:
; CHECK: crc32cx w0, w0, x1
%val = call i32 @llvm.aarch64.crc32cx(i32 %cur, i64 %next)
ret i32 %val
}

declare i32 @llvm.aarch64.crc32b(i32, i32)
declare i32 @llvm.aarch64.crc32h(i32, i32)
declare i32 @llvm.aarch64.crc32w(i32, i32)
declare i32 @llvm.aarch64.crc32x(i32, i64)

declare i32 @llvm.aarch64.crc32cb(i32, i32)
declare i32 @llvm.aarch64.crc32ch(i32, i32)
declare i32 @llvm.aarch64.crc32cw(i32, i32)
declare i32 @llvm.aarch64.crc32cx(i32, i64)

0 comments on commit ab21bea

Please sign in to comment.