Skip to content

Commit

Permalink
Merge branch 'CTSRD-CHERI:master' into petr/break-mips-riscv-dependancy
Browse files Browse the repository at this point in the history
  • Loading branch information
veselypeta committed May 20, 2024
2 parents fd7059e + 578ea4f commit 2975066
Show file tree
Hide file tree
Showing 7 changed files with 593 additions and 3 deletions.
3 changes: 2 additions & 1 deletion clang/lib/Headers/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ struct _Unwind_Context;
#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || \
defined(__ARM_DWARF_EH__) || defined(__SEH__))
struct _Unwind_Control_Block;
typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
typedef struct _Unwind_Control_Block _Unwind_Control_Block;
#define _Unwind_Exception _Unwind_Control_Block /* Alias */
#else
struct _Unwind_Exception;
typedef struct _Unwind_Exception _Unwind_Exception;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6768,7 +6768,7 @@ static bool isMemSrcFromConstant(SDValue Src, ConstantDataArraySlice &Slice) {
GlobalAddressSDNode *G = nullptr;
if (Src.getOpcode() == ISD::GlobalAddress)
G = cast<GlobalAddressSDNode>(Src);
else if (Src.getOpcode() == ISD::ADD &&
else if ((Src.getOpcode() == ISD::ADD || Src.getOpcode() == ISD::PTRADD) &&
Src.getOperand(0).getOpcode() == ISD::GlobalAddress &&
Src.getOperand(1).getOpcode() == ISD::Constant) {
G = cast<GlobalAddressSDNode>(Src.getOperand(0));
Expand Down Expand Up @@ -6887,7 +6887,7 @@ static SDValue getMemcpyLoadsAndStores(
// TODO: the frontend/optimization passes probably shouldn't emit
// must-preserve-tags for such small memcpys
auto CapTy = TLI.cheriCapabilityType();
if (CapTy.isValid()) {
if (CapTy.isValid() && !Op.isMemset()) {
const uint64_t CapSize = CapTy.getStoreSize();
if (PreserveTags == PreserveCheriTags::Required && !ReachedLimit &&
Size >= CapSize && (!FoundLowering || !MemOps[0].isFatPointer())) {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ bool TargetLowering::findOptimalMemOpLowering(

// XXXAR: (ab)use MVT::isVoid to indicate that a memcpy call must be made
if (VT == MVT::isVoid) {
assert(!Op.isMemset() && "MVT::isVoid should only be used for copies");
return false; // cannot lower as memops
}
// If the type is a fat pointer, then forcibly disable overlap.
Expand Down
93 changes: 93 additions & 0 deletions llvm/test/CodeGen/CHERI-Generic/Inputs/memcpy-from-constant.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
;; Copying from a zero constant can be converted to a memset (even with the tag preservation flags)
; RUN: llc @PURECAP_HARDFLOAT_ARGS@ < %s -o - | FileCheck %s

@a = internal addrspace(200) constant ptr addrspace(200) null
@b = internal addrspace(200) constant ptr addrspace(200) null
@zero_constant = internal addrspace(200) constant [5 x ptr addrspace(200)] zeroinitializer
@constant_ptrs = internal addrspace(200) constant [2 x ptr addrspace(200)] [ptr addrspace(200) @a, ptr addrspace(200) @b]

declare void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) noalias nocapture writeonly, ptr addrspace(200) noalias nocapture readonly, i64, i1 immarg) addrspace(200) #0

define linkonce_odr void @copy_from_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @zero_constant, i64 @CAP_BYTES@, i1 false)
ret void
}

define linkonce_odr void @copy_from_zero_constant_with_offset(ptr addrspace(200) %dst) addrspace(200) {
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @zero_constant, i64 @CAP_BYTES@
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ %src, i64 @CAP_BYTES@, i1 false)
ret void
}

define linkonce_odr void @copy_from_large_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @zero_constant, i64 @CAP_RANGE_BYTES@, i1 false)
ret void
}

define linkonce_odr void @copy_from_ptr_constant(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @constant_ptrs, i64 @CAP_BYTES@, i1 false)
ret void
}

define linkonce_odr void @copy_from_ptr_constant_with_offset(ptr addrspace(200) %dst) addrspace(200) {
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @constant_ptrs, i64 @CAP_BYTES@
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ %src, i64 @CAP_BYTES@, i1 false)
ret void
}

;; Run the same tests again this time with must_preserve_tags to check that we don't call memcpy().

define linkonce_odr void @copy_from_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @zero_constant, i64 @CAP_BYTES@, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_zero_constant_with_offset_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @zero_constant, i64 @CAP_BYTES@
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ %src, i64 @CAP_BYTES@, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_large_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @zero_constant, i64 @CAP_RANGE_BYTES@, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_ptr_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ @constant_ptrs, i64 @CAP_BYTES@, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_ptr_constant_with_offset_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @constant_ptrs, i64 @CAP_BYTES@
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_BYTES@ %dst, ptr addrspace(200) align @CAP_BYTES@ %src, i64 @CAP_BYTES@, i1 false) #1
ret void
}

;; Finally, check copying from a zero constant with insufficient known alignment.
;; We should be able to emit this inline since a zero constant source never has tags.

define linkonce_odr void @copy_from_underaligned_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_RANGE_BYTES@ %dst, ptr addrspace(200) align @CAP_RANGE_BYTES@ @zero_constant, i64 @CAP_BYTES@, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_underaligned_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align @CAP_RANGE_BYTES@ %dst, ptr addrspace(200) align @CAP_RANGE_BYTES@ @zero_constant, i64 @CAP_BYTES@, i1 false) #1
ret void
}

attributes #0 = { argmemonly nocallback nofree nounwind willreturn }
attributes #1 = { must_preserve_cheri_tags "frontend-memtransfer-type"="'const UChar * __capability' (aka 'const char16_t * __capability')" }
165 changes: 165 additions & 0 deletions llvm/test/CodeGen/CHERI-Generic/MIPS/memcpy-from-constant.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes --force-update
; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/memcpy-from-constant.ll
;; Copying from a zero constant can be converted to a memset (even with the tag preservation flags)
; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap < %s -o - | FileCheck %s

@a = internal addrspace(200) constant ptr addrspace(200) null
@b = internal addrspace(200) constant ptr addrspace(200) null
@zero_constant = internal addrspace(200) constant [5 x ptr addrspace(200)] zeroinitializer
@constant_ptrs = internal addrspace(200) constant [2 x ptr addrspace(200)] [ptr addrspace(200) @a, ptr addrspace(200) @b]

declare void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) noalias nocapture writeonly, ptr addrspace(200) noalias nocapture readonly, i64, i1 immarg) addrspace(200) #0

define linkonce_odr void @copy_from_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_zero_constant:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $cnull, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @zero_constant, i64 16, i1 false)
ret void
}

define linkonce_odr void @copy_from_zero_constant_with_offset(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_zero_constant_with_offset:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $cnull, $zero, 0($c3)
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @zero_constant, i64 16
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 %src, i64 16, i1 false)
ret void
}

define linkonce_odr void @copy_from_large_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_large_zero_constant:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csd $zero, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @zero_constant, i64 8, i1 false)
ret void
}

define linkonce_odr void @copy_from_ptr_constant(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_ptr_constant:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: lui $1, %pcrel_hi(_CHERI_CAPABILITY_TABLE_-8)
; CHECK-NEXT: daddiu $1, $1, %pcrel_lo(_CHERI_CAPABILITY_TABLE_-4)
; CHECK-NEXT: cgetpccincoffset $c1, $1
; CHECK-NEXT: clcbi $c1, %captab20(constant_ptrs)($c1)
; CHECK-NEXT: clc $c1, $zero, 0($c1)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $c1, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @constant_ptrs, i64 16, i1 false)
ret void
}

define linkonce_odr void @copy_from_ptr_constant_with_offset(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_ptr_constant_with_offset:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: lui $1, %pcrel_hi(_CHERI_CAPABILITY_TABLE_-8)
; CHECK-NEXT: daddiu $1, $1, %pcrel_lo(_CHERI_CAPABILITY_TABLE_-4)
; CHECK-NEXT: cgetpccincoffset $c1, $1
; CHECK-NEXT: clcbi $c1, %captab20(constant_ptrs)($c1)
; CHECK-NEXT: clc $c1, $zero, 16($c1)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $c1, $zero, 0($c3)
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @constant_ptrs, i64 16
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 %src, i64 16, i1 false)
ret void
}

;; Run the same tests again this time with must_preserve_tags to check that we don't call memcpy().

define linkonce_odr void @copy_from_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_zero_constant_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $cnull, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @zero_constant, i64 16, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_zero_constant_with_offset_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_zero_constant_with_offset_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $cnull, $zero, 0($c3)
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @zero_constant, i64 16
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 %src, i64 16, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_large_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_large_zero_constant_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csd $zero, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @zero_constant, i64 8, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_ptr_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_ptr_constant_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: lui $1, %pcrel_hi(_CHERI_CAPABILITY_TABLE_-8)
; CHECK-NEXT: daddiu $1, $1, %pcrel_lo(_CHERI_CAPABILITY_TABLE_-4)
; CHECK-NEXT: cgetpccincoffset $c1, $1
; CHECK-NEXT: clcbi $c1, %captab20(constant_ptrs)($c1)
; CHECK-NEXT: clc $c1, $zero, 0($c1)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $c1, $zero, 0($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 @constant_ptrs, i64 16, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_ptr_constant_with_offset_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_ptr_constant_with_offset_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: lui $1, %pcrel_hi(_CHERI_CAPABILITY_TABLE_-8)
; CHECK-NEXT: daddiu $1, $1, %pcrel_lo(_CHERI_CAPABILITY_TABLE_-4)
; CHECK-NEXT: cgetpccincoffset $c1, $1
; CHECK-NEXT: clcbi $c1, %captab20(constant_ptrs)($c1)
; CHECK-NEXT: clc $c1, $zero, 16($c1)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csc $c1, $zero, 0($c3)
do.body:
%src = getelementptr inbounds i8, ptr addrspace(200) @constant_ptrs, i64 16
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 16 %dst, ptr addrspace(200) align 16 %src, i64 16, i1 false) #1
ret void
}

;; Finally, check copying from a zero constant with insufficient known alignment.
;; We should be able to emit this inline since a zero constant source never has tags.

define linkonce_odr void @copy_from_underaligned_zero_constant(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_underaligned_zero_constant:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: csd $zero, $zero, 0($c3)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csd $zero, $zero, 8($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 8 %dst, ptr addrspace(200) align 8 @zero_constant, i64 16, i1 false) #1
ret void
}

define linkonce_odr void @copy_from_underaligned_zero_constant_preserve(ptr addrspace(200) %dst) addrspace(200) {
; CHECK-LABEL: copy_from_underaligned_zero_constant_preserve:
; CHECK: # %bb.0: # %do.body
; CHECK-NEXT: csd $zero, $zero, 0($c3)
; CHECK-NEXT: cjr $c17
; CHECK-NEXT: csd $zero, $zero, 8($c3)
do.body:
call void @llvm.memcpy.p200.p200.i64(ptr addrspace(200) align 8 %dst, ptr addrspace(200) align 8 @zero_constant, i64 16, i1 false) #1
ret void
}

attributes #0 = { argmemonly nocallback nofree nounwind willreturn }
attributes #1 = { must_preserve_cheri_tags "frontend-memtransfer-type"="'const UChar * __capability' (aka 'const char16_t * __capability')" }
Loading

0 comments on commit 2975066

Please sign in to comment.