diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index 835a7b6cc81d987186486590e7e31cc6476766f4..98c4f1ada15b2191e214d3c253930a53a4b4c2bd 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -8141,6 +8141,14 @@ AArch64InstrInfo::getTailDuplicateSize(CodeGenOpt::Level OptLevel) const { return OptLevel >= CodeGenOpt::Aggressive ? 6 : 2; } +// OHOS_LOCAL begin +bool AArch64InstrInfo::preservesZeroValueInReg( + const MachineInstr *MI, const Register NullValueReg, + const TargetRegisterInfo *TRI) const { + return !MI->modifiesRegister(NullValueReg, TRI); +} +// OHOS_LOCAL end + unsigned llvm::getBLRCallOpcode(const MachineFunction &MF) { if (MF.getSubtarget().hardenSlsBlr()) return AArch64::BLRNoIP; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h index b7a6ac301cdc17c708dd056d69333e30067aa23f..7059de6b272c340e93041b09f40208104682fe6b 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h @@ -194,6 +194,12 @@ public: // with subreg operands to foldMemoryOperandImpl. bool isSubregFoldable() const override { return true; } + // OHOS_LOCAL begin + bool preservesZeroValueInReg(const MachineInstr *MI, + const Register NullValueReg, + const TargetRegisterInfo *TRI) const override; + // OHOS_LOCAL end + using TargetInstrInfo::foldMemoryOperandImpl; MachineInstr * foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, diff --git a/llvm/test/CodeGen/AArch64/implicit-null-check.ll b/llvm/test/CodeGen/AArch64/implicit-null-check.ll index ed236e0010fb4b7ed95d5b8614c55beb94dce25f..59bbfda757c8d8038de7dc7b8c09184cb57b5b91 100644 --- a/llvm/test/CodeGen/AArch64/implicit-null-check.ll +++ b/llvm/test/CodeGen/AArch64/implicit-null-check.ll @@ -224,11 +224,13 @@ define i32 @imp_null_check_add_result(i32* %x, i32 %p) { define i32 @imp_null_check_hoist_over_udiv(i32* %x, i32 %a, i32 %b) { ; CHECK-LABEL: imp_null_check_hoist_over_udiv: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: cbz x0, .LBB9_2 +;; OHOS_LOCAL begin +; CHECK-NEXT: .Ltmp6: +; CHECK-NEXT: ldr w9, [x0] // on-fault: .LBB9_2 ; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: udiv w8, w1, w2 -; CHECK-NEXT: ldr w9, [x0] ; CHECK-NEXT: add w0, w9, w8 +;; OHOS_LOCAL end ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB9_2: ; CHECK-NEXT: mov w0, #42 @@ -247,21 +249,20 @@ define i32 @imp_null_check_hoist_over_udiv(i32* %x, i32 %a, i32 %b) { ret i32 %res } - -; TODO: We should be able to hoist this - we can on x86, why isn't this -; working for aarch64? Aliasing? define i32 @imp_null_check_hoist_over_unrelated_load(i32* %x, i32* %y, i32* %z) { +;; OHOS_LOCAL begin ; CHECK-LABEL: imp_null_check_hoist_over_unrelated_load: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: cbz x0, .LBB10_2 +; CHECK-NEXT: .Ltmp7: +; CHECK-NEXT: ldr w0, [x0] // on-fault: .LBB10_2 ; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: ldr w8, [x1] -; CHECK-NEXT: ldr w0, [x0] ; CHECK-NEXT: str w8, [x2] ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB10_2: ; CHECK-NEXT: mov w0, #42 ; CHECK-NEXT: ret +;; OHOS_LOCAL end entry: %c = icmp eq i32* %x, null br i1 %c, label %is_null, label %not_null, !make.implicit !0 @@ -279,7 +280,9 @@ define i32 @imp_null_check_hoist_over_unrelated_load(i32* %x, i32* %y, i32* %z) define i32 @imp_null_check_gep_load_with_use_dep(i32* %x, i32 %a) { ; CHECK-LABEL: imp_null_check_gep_load_with_use_dep: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: .Ltmp6: +;; OHOS_LOCAL begin +; CHECK-NEXT: .Ltmp8: +;; OHOS_LOCAL end ; CHECK-NEXT: ldr w8, [x0] // on-fault: .LBB11_2 ; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: add w9, w0, w1 @@ -357,14 +360,15 @@ not_null: ret i32 %t } -; TODO: We can fold to implicit null here, not sure why this isn't working define void @imp_null_check_store(i32* %x) { +;; OHOS_LOCAL begin ; CHECK-LABEL: imp_null_check_store: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: cbz x0, .LBB14_2 -; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: mov w8, #1 -; CHECK-NEXT: str w8, [x0] +; CHECK-NEXT: .Ltmp9: +; CHECK-NEXT: str w8, [x0] // on-fault: .LBB14_2 +; CHECK-NEXT: // %bb.1: // %not_null +;; OHOS_LOCAL end ; CHECK-NEXT: .LBB14_2: // %common.ret ; CHECK-NEXT: ret entry: @@ -379,14 +383,15 @@ define void @imp_null_check_store(i32* %x) { ret void } -;; TODO: can be implicit define void @imp_null_check_unordered_store(i32* %x) { +;; OHOS_LOCAL begin ; CHECK-LABEL: imp_null_check_unordered_store: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: cbz x0, .LBB15_2 -; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: mov w8, #1 -; CHECK-NEXT: str w8, [x0] +; CHECK-NEXT: .Ltmp10: +; CHECK-NEXT: str w8, [x0] // on-fault: .LBB15_2 +; CHECK-NEXT: // %bb.1: // %not_null +;; OHOS_LOCAL end ; CHECK-NEXT: .LBB15_2: // %common.ret ; CHECK-NEXT: ret entry: @@ -404,7 +409,9 @@ define void @imp_null_check_unordered_store(i32* %x) { define i32 @imp_null_check_neg_gep_load(i32* %x) { ; CHECK-LABEL: imp_null_check_neg_gep_load: ; CHECK: // %bb.0: // %entry -; CHECK-NEXT: .Ltmp7: +;; OHOS_LOCAL begin +; CHECK-NEXT: .Ltmp11: +;; OHOS_LOCAL end ; CHECK-NEXT: ldur w0, [x0, #-128] // on-fault: .LBB16_2 ; CHECK-NEXT: // %bb.1: // %not_null ; CHECK-NEXT: ret @@ -424,4 +431,33 @@ define i32 @imp_null_check_neg_gep_load(i32* %x) { ret i32 %t } +;; OHOS_LOCAL begin +;; LLVM does not support implicit null checks for ldp and stp +;; The test must be fixed, when such is introduced +define i64 @imp_null_check_load_pair(i64* %array) { +; CHECK-LABEL: imp_null_check_load_pair: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: cbz x0, .LBB17_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldp x8, x9, [x0] +; CHECK-NEXT: add x0, x9, x8 +; CHECK-NEXT: .LBB17_2: // %return +; CHECK-NEXT: ret +entry: + %cmp = icmp eq i64* %array, null + br i1 %cmp, label %return, label %if.end, !make.implicit !0 + +if.end: ; preds = %entry + %0 = load i64, i64* %array, align 8 + %arrayidx1 = getelementptr inbounds i64, i64* %array, i64 1 + %1 = load i64, i64* %arrayidx1, align 8 + %add = add nsw i64 %1, %0 + br label %return + +return: ; preds = %entry, %if.end + %retval.0 = phi i64 [ %add, %if.end ], [ 0, %entry ] + ret i64 %retval.0 +} +;; OHOS_LOCAL end + !0 = !{} diff --git a/llvm/test/CodeGen/AArch64/ptr32-implicit-null-checks.ll b/llvm/test/CodeGen/AArch64/ptr32-implicit-null-checks.ll new file mode 100644 index 0000000000000000000000000000000000000000..dcecc92d5b7085fd27adf7840b2ecbe2adae84b1 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptr32-implicit-null-checks.ll @@ -0,0 +1,276 @@ +; RUN: llc --enable-implicit-null-checks --aarch64-enable-ptr32 -verify-machineinstrs -O2 < %s | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +; CHECK-LABEL: LoadI32FromPtr32: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: ldr w0, [x0, #16] +; CHECK-NEXT: // %bb.1: +; CHECK-NEXT: ldr x30, [sp], #16 +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: bl ThrowNullPointerException +define i32 @LoadI32FromPtr32(ptr addrspace(271) %object) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: + tail call void @ThrowNullPointerException() + unreachable + +if.end: + %add.ptr = getelementptr inbounds i32, ptr addrspace(271) %object, i32 4 + %1 = load i32, ptr addrspace(271) %add.ptr, align 4 + ret i32 %1 +} + +; CHECK-LABEL: LoadFloatFromPtr32: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: ldr s0, [x0, #16] +; CHECK-NEXT: // %bb.1: +; CHECK-NEXT: ldr x30, [sp], #16 +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB1_2: +; CHECK-NEXT: bl ThrowNullPointerException +define float @LoadFloatFromPtr32(ptr addrspace(271) %object) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() #2 + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds float, ptr addrspace(271) %object, i32 4 + %1 = load float, ptr addrspace(271) %add.ptr, align 4 + ret float %1 +} + +; CHECK-LABEL: LoadDoubleFromPtr32: +; CHECK: .cfi_startproc +; CHECK: // %bb.0: // %entry +; CHECK: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK: .cfi_def_cfa_offset 16 +; CHECK: .cfi_offset w30, -16 +; CHECK: .Ltmp2: +; CHECK: ldr d0, [x0, #64] // on-fault: .LBB2_2 +; CHECK: // %bb.1: // %if.end +; CHECK: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK: ret +; CHECK: .LBB2_2: // %if.then +; CHECK: bl ThrowNullPointerException +define double @LoadDoubleFromPtr32(ptr addrspace(271) %object) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: + tail call void @ThrowNullPointerException() + unreachable + +if.end: + %add.ptr = getelementptr inbounds double, ptr addrspace(271) %object, i32 8 + %1 = load double, ptr addrspace(271) %add.ptr, align 8 + ret double %1 +} + +; CHECK-LABEL: LoadPtr32FromPtr32: // @LoadPtr32FromPtr32 +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp3: +; CHECK-NEXT: ldr w0, [x0, #16] // on-fault: .LBB3_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB3_2: // %if.then +; CHECK-NEXT: bl ThrowNullPointerException +define ptr addrspace(271) @LoadPtr32FromPtr32(ptr addrspace(271) %object) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 4 + %1 = load ptr addrspace(271), ptr addrspace(271) %add.ptr, align 4 + ret ptr addrspace(271) %1 +} + +; CHECK-LABEL: StoreI32ToPtr32: // @StoreI32ToPtr32 +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp4: +; CHECK-NEXT: str w1, [x0, #32] // on-fault: .LBB4_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB4_2: // %if.then +; CHECK-NEXT: bl ThrowNullPointerException +define void @StoreI32ToPtr32(ptr addrspace(271) %object, i32 %value) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 8 + store i32 %value, ptr addrspace(271) %add.ptr, align 4 + ret void +} + +; CHECK-LABEL: StoreFloatToPtr32: // @StoreFloatToPtr32 +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp5: +; CHECK-NEXT: str s0, [x0, #32] // on-fault: .LBB5_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB5_2: // %if.then +; CHECK-NEXT: bl ThrowNullPointerException +define void @StoreFloatToPtr32(ptr addrspace(271) %object, float %value) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 8 + store float %value, ptr addrspace(271) %add.ptr, align 4 + ret void +} + +; CHECK-LABEL: StoreDoubleToPtr32: // @StoreDoubleToPtr32 +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp6: +; CHECK-NEXT: str d0, [x0, #32] // on-fault: .LBB6_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB6_2: // %if.then +; CHECK-NEXT: bl ThrowNullPointerException +define void @StoreDoubleToPtr32(ptr addrspace(271) %object, double %value) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 8 + store double %value, ptr addrspace(271) %add.ptr, align 8 + ret void +} + +; Note LLVM does not support this case because ImplicitNullChecks does not hoist +; str x8, [x0, #32] above the moves to x8 because of the dependency on x8 +; The test should be enabled when such support is introduced +; StoreConstantDoubleToPtr32: // @StoreConstantDoubleToPtr32 +; // %bb.0: // %entry +; str x30, [sp, #-16]! // 8-byte Folded Spill +; cbz x0, .LBB7_2 +; // %bb.1: // %if.end +; mov x8, #55370 +; movk x8, #19730, lsl #16 +; movk x8, #8699, lsl #32 +; movk x8, #16393, lsl #48 +; str x8, [x0, #32] +; ldr x30, [sp], #16 // 8-byte Folded Reload +; ret +; .LBB7_2: // %if.then +; bl ThrowNullPointerException + +; COM: CHECK-LABEL: StoreConstantDoubleToPtr32: // @StoreConstantDoubleToPtr32 +; COM: CHECK-NOT: cbz x0, {{.*}} +; COM: CHECK: ret +define void @StoreConstantDoubleToPtr32(ptr addrspace(271) %object) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 8 + store double 0x400921FB4D12D84A, ptr addrspace(271) %add.ptr, align 8 + ret void +} + +; CHECK-LABEL: StorePtr32ToPtr32: // @StorePtr32ToPtr32 +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp7: +; CHECK-NEXT: str w1, [x0, #32] // on-fault: .LBB8_2 +; CHECK-NEXT: // %bb.1: // %if.end +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB8_2: // %if.then +; CHECK-NEXT: bl ThrowNullPointerException +define void @StorePtr32ToPtr32(ptr addrspace(271) %object, ptr addrspace(271) %value) { +entry: + %0 = addrspacecast ptr addrspace(271) %object to ptr + %cmp = icmp eq ptr %0, null + br i1 %cmp, label %if.then, label %if.end, !make.implicit !0 + +if.then: ; preds = %entry + tail call void @ThrowNullPointerException() + unreachable + +if.end: ; preds = %entry + %add.ptr = getelementptr inbounds ptr addrspace(271), ptr addrspace(271) %object, i32 8 + store ptr addrspace(271) %value, ptr addrspace(271) %add.ptr, align 4 + ret void +} + +declare void @ThrowNullPointerException() + +!0 = !{}