-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CHERI-RISC-V] Restrict CFromPtr usage to ISAv8 compatibility
We emit `x == 0 ? null : CSetOffset(auth, x)` when we see the intrinsic in non-ISAv8 compilation mode instead. When expanding `inttoptr` in hybrid mode, we do not include the base of DDC as part of the expansion (since DDC relocation is no longer part of ISAv9). Adding the base would result in a capability that points to a different address when dereferenced. Therefore, inttoptr is expanded to `x == 0 ? null : CSetAddr(DDC, x)`. It would be nice if we could just use `CSetAddr(DDC, x)` unconditionally for non-constant arguments, but that could result in semantic differences (tagged vs untagged) for integers that happen to be zero at run time.
- Loading branch information
1 parent
2a20c31
commit 0c0ec2f
Showing
4 changed files
with
252 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | ||
;; The CFromPtr instruction is not part of ISAv9, check that we emit `x == 0 ? null : csetoffset(auth, x)` instead. | ||
; RUN: %riscv64_cheri_purecap_llc < %s | FileCheck %s --check-prefix=ISAV8 | ||
; RUN: %riscv64_cheri_purecap_llc -mattr=+xcheri-no-v8-compat < %s | FileCheck %s --check-prefix=ISAV9 | ||
;; Also emit a .o file since verifyInstructionPredicates() is only called for binary output. | ||
; RUN: %riscv64_cheri_purecap_llc -mattr=+xcheri-no-v8-compat -filetype=obj -o /dev/null < %s | ||
|
||
;; (int_cheri_cap_from_ptr auth, x) -> x == 0 ? null : csetoffset(auth, x) | ||
define internal i8 addrspace(200)* @cap_from_ptr(i8 addrspace(200)* addrspace(200)* %ptr, i8 addrspace(200)* %cap, i64 %offset) nounwind { | ||
; ISAV8-LABEL: cap_from_ptr: | ||
; ISAV8: # %bb.0: # %entry | ||
; ISAV8-NEXT: cfromptr ca1, ca1, a2 | ||
; ISAV8-NEXT: csc ca1, 0(ca0) | ||
; ISAV8-NEXT: cmove ca0, ca1 | ||
; ISAV8-NEXT: cret | ||
; | ||
; ISAV9-LABEL: cap_from_ptr: | ||
; ISAV9: # %bb.0: # %entry | ||
; ISAV9-NEXT: bnez a2, .LBB0_2 | ||
; ISAV9-NEXT: # %bb.1: # %entry | ||
; ISAV9-NEXT: cmove ca1, cnull | ||
; ISAV9-NEXT: j .LBB0_3 | ||
; ISAV9-NEXT: .LBB0_2: | ||
; ISAV9-NEXT: csetoffset ca1, ca1, a2 | ||
; ISAV9-NEXT: .LBB0_3: # %entry | ||
; ISAV9-NEXT: csc ca1, 0(ca0) | ||
; ISAV9-NEXT: cmove ca0, ca1 | ||
; ISAV9-NEXT: cret | ||
entry: | ||
%new = call i8 addrspace(200)* @llvm.cheri.cap.from.pointer.i64(i8 addrspace(200)* %cap, i64 %offset) | ||
store i8 addrspace(200)* %new, i8 addrspace(200)* addrspace(200)* %ptr, align 16 | ||
ret i8 addrspace(200)* %new | ||
} | ||
|
||
;; (int_cheri_cap_from_ptr ddc, y) -> x == 0 ? null : csetoffset(ddc, x) | ||
;; NB: This is not the same as (inttoptr x), since the explicit intrinsic retains the offsetting semantics. | ||
define internal i8 addrspace(200)* @cap_from_ptr_ddc(i8 addrspace(200)* addrspace(200)* %ptr, i64 %offset) nounwind { | ||
; ISAV8-LABEL: cap_from_ptr_ddc: | ||
; ISAV8: # %bb.0: # %entry | ||
; ISAV8-NEXT: cfromptr ca1, ddc, a1 | ||
; ISAV8-NEXT: csc ca1, 0(ca0) | ||
; ISAV8-NEXT: cmove ca0, ca1 | ||
; ISAV8-NEXT: cret | ||
; | ||
; ISAV9-LABEL: cap_from_ptr_ddc: | ||
; ISAV9: # %bb.0: # %entry | ||
; ISAV9-NEXT: cspecialr ca2, ddc | ||
; ISAV9-NEXT: bnez a1, .LBB1_2 | ||
; ISAV9-NEXT: # %bb.1: # %entry | ||
; ISAV9-NEXT: cmove ca1, cnull | ||
; ISAV9-NEXT: j .LBB1_3 | ||
; ISAV9-NEXT: .LBB1_2: | ||
; ISAV9-NEXT: csetoffset ca1, ca2, a1 | ||
; ISAV9-NEXT: .LBB1_3: # %entry | ||
; ISAV9-NEXT: csc ca1, 0(ca0) | ||
; ISAV9-NEXT: cmove ca0, ca1 | ||
; ISAV9-NEXT: cret | ||
entry: | ||
%ddc = call i8 addrspace(200)* @llvm.cheri.ddc.get() | ||
%new = call i8 addrspace(200)* @llvm.cheri.cap.from.pointer.i64(i8 addrspace(200)* %ddc, i64 %offset) | ||
store i8 addrspace(200)* %new, i8 addrspace(200)* addrspace(200)* %ptr, align 16 | ||
ret i8 addrspace(200)* %new | ||
} | ||
|
||
declare i8 addrspace(200)* @llvm.cheri.cap.from.pointer.i64(i8 addrspace(200)*, i64) | ||
declare i8 addrspace(200)* @llvm.cheri.ddc.get() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | ||
;; Check that we don't emit CFromPtr when lowering inttoptr for ISAv9. | ||
; RUN: %riscv64_cheri_purecap_llc -mattr=+xcheri-no-v8-compat < %s | FileCheck %s --check-prefix=PURECAP | ||
; RUN: %riscv64_cheri_llc -mattr=+xcheri-no-v8-compat < %s | FileCheck %s --check-prefix=HYBRID | ||
;; Also emit a .o file since verifyInstructionPredicates() is only called for binary output. | ||
; RUN: %riscv64_cheri_purecap_llc -mattr=+xcheri-no-v8-compat -filetype=obj -o /dev/null < %s | ||
; RUN: %riscv64_cheri_llc -mattr=+xcheri-no-v8-compat -filetype=obj -o /dev/null < %s | ||
|
||
define internal i8 addrspace(200)* @inttoptr(i64 %ptr) addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cincoffset ca0, cnull, a0 | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cspecialr ca1, ddc | ||
; HYBRID-NEXT: bnez a0, .LBB0_2 | ||
; HYBRID-NEXT: # %bb.1: | ||
; HYBRID-NEXT: cmove ca0, cnull | ||
; HYBRID-NEXT: ret | ||
; HYBRID-NEXT: .LBB0_2: | ||
; HYBRID-NEXT: csetaddr ca0, ca1, a0 | ||
; HYBRID-NEXT: ret | ||
%ret = inttoptr i64 %ptr to i8 addrspace(200)* | ||
ret i8 addrspace(200)* %ret | ||
} | ||
|
||
define internal i8 addrspace(200)* @inttoptr_plus_const(i64 %ptr) addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr_plus_const: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cincoffset ca0, cnull, a0 | ||
; PURECAP-NEXT: cincoffset ca0, ca0, 2 | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr_plus_const: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cspecialr ca1, ddc | ||
; HYBRID-NEXT: bnez a0, .LBB1_2 | ||
; HYBRID-NEXT: # %bb.1: | ||
; HYBRID-NEXT: cincoffset ca0, cnull, 2 | ||
; HYBRID-NEXT: ret | ||
; HYBRID-NEXT: .LBB1_2: | ||
; HYBRID-NEXT: csetaddr ca0, ca1, a0 | ||
; HYBRID-NEXT: cincoffset ca0, ca0, 2 | ||
; HYBRID-NEXT: ret | ||
%cap = inttoptr i64 %ptr to i8 addrspace(200)* | ||
%ret = getelementptr i8, i8 addrspace(200)* %cap, i64 2 | ||
ret i8 addrspace(200)* %ret | ||
} | ||
|
||
;; CFromPtr has been removed from CHERI ISAv9, but we want to retain the | ||
;; semantics that inttoptr of a variable that happens to be zero will result in | ||
;; an untagged value. This means we can't just expand inttoptr to CSetAddr on | ||
;; DDC since using that with address zero could result in a valid capability. | ||
;; Therefore we have to insert a conditional branch and emit | ||
;; `x.addr == 0 ? null : CSetAddr DDC, x` instead. This is a rather long code | ||
;; sequence due to lack of conditional moves, but it should happen rarely. | ||
|
||
define internal i8 addrspace(200)* @inttoptr_plus_var(i64 %ptr, i64 %add) addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr_plus_var: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cincoffset ca0, cnull, a0 | ||
; PURECAP-NEXT: cincoffset ca0, ca0, a1 | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr_plus_var: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cspecialr ca2, ddc | ||
; HYBRID-NEXT: bnez a0, .LBB2_2 | ||
; HYBRID-NEXT: # %bb.1: | ||
; HYBRID-NEXT: cincoffset ca0, cnull, a1 | ||
; HYBRID-NEXT: ret | ||
; HYBRID-NEXT: .LBB2_2: | ||
; HYBRID-NEXT: csetaddr ca0, ca2, a0 | ||
; HYBRID-NEXT: cincoffset ca0, ca0, a1 | ||
; HYBRID-NEXT: ret | ||
%cap = inttoptr i64 %ptr to i8 addrspace(200)* | ||
%ret = getelementptr i8, i8 addrspace(200)* %cap, i64 %add | ||
ret i8 addrspace(200)* %ret | ||
} | ||
|
||
define internal i8 addrspace(200)* @inttoptr_null() addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr_null: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cmove ca0, cnull | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr_null: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cmove ca0, cnull | ||
; HYBRID-NEXT: ret | ||
%ret = inttoptr i64 0 to i8 addrspace(200)* | ||
ret i8 addrspace(200)* %ret | ||
} | ||
|
||
define internal i8 addrspace(200)* @inttoptr_null_plus_const() addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr_null_plus_const: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cincoffset ca0, cnull, 2 | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr_null_plus_const: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cincoffset ca0, cnull, 2 | ||
; HYBRID-NEXT: ret | ||
%null = inttoptr i64 0 to i8 addrspace(200)* | ||
%ret = getelementptr i8, i8 addrspace(200)* %null, i64 2 | ||
ret i8 addrspace(200)* %ret | ||
} | ||
|
||
define internal i8 addrspace(200)* @inttoptr_null_plus_var(i64 %add) addrspace(200) nounwind { | ||
; PURECAP-LABEL: inttoptr_null_plus_var: | ||
; PURECAP: # %bb.0: | ||
; PURECAP-NEXT: cincoffset ca0, cnull, a0 | ||
; PURECAP-NEXT: cret | ||
; | ||
; HYBRID-LABEL: inttoptr_null_plus_var: | ||
; HYBRID: # %bb.0: | ||
; HYBRID-NEXT: cincoffset ca0, cnull, a0 | ||
; HYBRID-NEXT: ret | ||
%null = inttoptr i64 0 to i8 addrspace(200)* | ||
%ret = getelementptr i8, i8 addrspace(200)* %null, i64 %add | ||
ret i8 addrspace(200)* %ret | ||
} |