diff --git a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp index e9920e1b41cb7..0ea54272d9b15 100644 --- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @@ -810,8 +810,6 @@ TEST(SourceCodeTests, isKeywords) { EXPECT_TRUE(isKeyword("return", LangOpts)); // CHERI-TODO: COROUTINES_KEYWORD is not included in CXX20_KEYWORD until // https://github.com/CTSRD-CHERI/llvm-project/issues/717 has been fixed. - EXPECT_FALSE(isKeyword("co_await", LangOpts)); - LangOpts.Coroutines = true; EXPECT_TRUE(isKeyword("co_await", LangOpts)); // these are identifiers (not keywords!) with special meaning in some diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8002e6d46d140..5aba083e19fac 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12457,6 +12457,8 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { return LongTy; case BuiltinType::ULongLong: return LongLongTy; + case BuiltinType::UIntCap: + return IntCapTy; case BuiltinType::UInt128: return Int128Ty; // wchar_t is special. It is either unsigned or not, but when it's unsigned, diff --git a/clang/test/SemaCXX/cheri/intcap-make-signed-unsigned.cpp b/clang/test/SemaCXX/cheri/intcap-make-signed-unsigned.cpp new file mode 100644 index 0000000000000..35ed550b8ae46 --- /dev/null +++ b/clang/test/SemaCXX/cheri/intcap-make-signed-unsigned.cpp @@ -0,0 +1,11 @@ +// RUN: %cheri_cc1 -fsyntax-only -verify %s + +// expected-no-diagnostics + +_Static_assert(__is_same(__make_signed(__intcap), __intcap), ""); +_Static_assert(__is_same(__make_signed(signed __intcap), __intcap), ""); +_Static_assert(__is_same(__make_signed(unsigned __intcap), __intcap), ""); + +_Static_assert(__is_same(__make_unsigned(__intcap), unsigned __intcap), ""); +_Static_assert(__is_same(__make_unsigned(signed __intcap), unsigned __intcap), ""); +_Static_assert(__is_same(__make_unsigned(unsigned __intcap), unsigned __intcap), ""); diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index db5ebca75fa5b..0bd7a6748dd8d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -2789,8 +2789,9 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) { // * x is a null pointer; or // * the add can be constant-folded; or // * the add can be combined and z is not a constant; or - // * y is a constant and z has one use; or - // * y is a constant and (ptradd x, y) has one use; or + // * y is a constant and z has one use and z is not a constant; or + // * y is a constant and (ptradd x, y) has one use and z is not a + // constant; or // * (ptradd x, y) and z have one use and z is not a constant. // // Some of these overly-restrictive conditions are to not obfuscate CAndAddr @@ -2799,12 +2800,15 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) { // and canonicalise it to a PTRMASK. // // Commute: (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if: - // * y and z have the same sign and y is a constant. + // * y and z have the same sign and only y is a constant. // // This allows immediate addressing modes to be used. Note that we need to be // careful to ensure we don't transiently become unrepresentable if the // original DAG does not already do so, and this is the case if both PTRADDs // have the same sign. + // + // Note we must be careful to handle the case that both are + // constants, as opaque constants will not be constant-folded. if (N0.getOpcode() == ISD::PTRADD && !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) { SDValue X = N0.getOperand(0); @@ -2827,15 +2831,18 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) { } LLVM_DEBUG(dbgs() << "visitPTRADD() add operand:"; Add.dump(&DAG)); assert(Add->getOpcode() != ISD::DELETED_NODE && "Deleted Node used"); - if (isNullConstant(X) || - DAG.isConstantIntBuildVectorOrConstantInt(Add) || - (VisitedAdd && !DAG.isConstantIntBuildVectorOrConstantInt(Z)) || - (DAG.isConstantIntBuildVectorOrConstantInt(Y) && Z.hasOneUse()) || - (DAG.isConstantIntBuildVectorOrConstantInt(Y) && N0.hasOneUse()) || - (N0.hasOneUse() && Z.hasOneUse() && - !DAG.isConstantIntBuildVectorOrConstantInt(Z))) + bool IsZConst = DAG.isConstantIntBuildVectorOrConstantInt(Z); + if (isNullConstant(X) || DAG.isConstantIntBuildVectorOrConstantInt(Add) || + (VisitedAdd && !IsZConst) || + (DAG.isConstantIntBuildVectorOrConstantInt(Y) && Z.hasOneUse() && + !IsZConst) || + (DAG.isConstantIntBuildVectorOrConstantInt(Y) && N0.hasOneUse() && + !IsZConst) || + (N0.hasOneUse() && Z.hasOneUse() && !IsZConst)) return DAG.getMemBasePlusOffset(X, Add, DL); - if (DAG.SignBitIsSame(Y, Z) && DAG.isConstantIntBuildVectorOrConstantInt(Y)) + if (DAG.SignBitIsSame(Y, Z) && + DAG.isConstantIntBuildVectorOrConstantInt(Y) && + !DAG.isConstantIntBuildVectorOrConstantInt(Z)) return GetPTRADD2(X, Z, Y); } @@ -2843,7 +2850,8 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) { // * both y and z have the same sign and z is a constant. // // Transform: (ptradd x, (add y, z)) -> (ptradd (ptradd x, z), y) if: - // * both y and z have the same sign and y is a constant. + // * both y and z have the same sign and y is a constant (and + // implicitly not z due to the previous transform). // // As above, this allows for immediate addressing modes. if (N1.getOpcode() == ISD::ADD) { @@ -2851,10 +2859,10 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) { SDValue Y = N1.getOperand(0); SDValue Z = N1.getOperand(1); if (DAG.SignBitIsSame(Y, Z)) { - if (DAG.isConstantIntBuildVectorOrConstantInt(Y)) - return GetPTRADD2(X, Z, Y); if (DAG.isConstantIntBuildVectorOrConstantInt(Z)) return GetPTRADD2(X, Y, Z); + if (DAG.isConstantIntBuildVectorOrConstantInt(Y)) + return GetPTRADD2(X, Z, Y); } } diff --git a/llvm/test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll b/llvm/test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll new file mode 100644 index 0000000000000..55901761b20e6 --- /dev/null +++ b/llvm/test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll @@ -0,0 +1,14 @@ +; RUN: llc @PURECAP_HARDFLOAT_ARGS@ -O0 < %s | FileCheck %s + +;; Test that, when DAGCombiner folds a load-insert-store to just storing the +;; element, it uses the index rather than pointer type for the offset. Without +;; this it would crash with: +;; +;; Assertion `Int.isZero() && "Should not create non-zero capability " "constants with SelectionDAG::getConstant()"' failed. +define void @foo(ptr addrspace(200) %p) addrspace(200) { +entry: + %0 = load <4 x i8>, ptr addrspace(200) %p, align 4 + %1 = insertelement <4 x i8> %0, i8 0, i64 0 + store <4 x i8> %1, ptr addrspace(200) %p, align 4 + ret void +} diff --git a/llvm/test/CodeGen/CHERI-Generic/MIPS/store-insert-load-index-type.ll b/llvm/test/CodeGen/CHERI-Generic/MIPS/store-insert-load-index-type.ll new file mode 100644 index 0000000000000..036cc3429e2e1 --- /dev/null +++ b/llvm/test/CodeGen/CHERI-Generic/MIPS/store-insert-load-index-type.ll @@ -0,0 +1,22 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2 +; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll +; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap -O0 < %s | FileCheck %s + +;; Test that, when DAGCombiner folds a load-insert-store to just storing the +;; element, it uses the index rather than pointer type for the offset. Without +;; this it would crash with: +;; +;; Assertion `Int.isZero() && "Should not create non-zero capability " "constants with SelectionDAG::getConstant()"' failed. +define void @foo(ptr addrspace(200) %p) addrspace(200) { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: daddiu $1, $zero, 0 +; CHECK-NEXT: csb $zero, $zero, 0($c3) +; CHECK-NEXT: cjr $c17 +; CHECK-NEXT: nop +entry: + %0 = load <4 x i8>, ptr addrspace(200) %p, align 4 + %1 = insertelement <4 x i8> %0, i8 0, i64 0 + store <4 x i8> %1, ptr addrspace(200) %p, align 4 + ret void +} diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV32/store-insert-load-index-type.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV32/store-insert-load-index-type.ll new file mode 100644 index 0000000000000..6a6a34ba35077 --- /dev/null +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV32/store-insert-load-index-type.ll @@ -0,0 +1,22 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll +; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+xcheripurecap,+f -O0 < %s | FileCheck %s + +;; Test that, when DAGCombiner folds a load-insert-store to just storing the +;; element, it uses the index rather than pointer type for the offset. Without +;; this it would crash with: +;; +;; Assertion `Int.isZero() && "Should not create non-zero capability " "constants with SelectionDAG::getConstant()"' failed. +define void @foo(ptr addrspace(200) %p) addrspace(200) { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: cmove a1, a0 +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: csb a0, 0(a1) +; CHECK-NEXT: cret +entry: + %0 = load <4 x i8>, ptr addrspace(200) %p, align 4 + %1 = insertelement <4 x i8> %0, i8 0, i64 0 + store <4 x i8> %1, ptr addrspace(200) %p, align 4 + ret void +} diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV64/store-insert-load-index-type.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV64/store-insert-load-index-type.ll new file mode 100644 index 0000000000000..4280485d08956 --- /dev/null +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV64/store-insert-load-index-type.ll @@ -0,0 +1,22 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/store-insert-load-index-type.ll +; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+xcheripurecap,+f,+d -O0 < %s | FileCheck %s + +;; Test that, when DAGCombiner folds a load-insert-store to just storing the +;; element, it uses the index rather than pointer type for the offset. Without +;; this it would crash with: +;; +;; Assertion `Int.isZero() && "Should not create non-zero capability " "constants with SelectionDAG::getConstant()"' failed. +define void @foo(ptr addrspace(200) %p) addrspace(200) { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: cmove a1, a0 +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: csb a0, 0(a1) +; CHECK-NEXT: cret +entry: + %0 = load <4 x i8>, ptr addrspace(200) %p, align 4 + %1 = insertelement <4 x i8> %0, i8 0, i64 0 + store <4 x i8> %1, ptr addrspace(200) %p, align 4 + ret void +} diff --git a/llvm/test/CodeGen/RISCV/cheri/ptradd-infinite-combine.ll b/llvm/test/CodeGen/RISCV/cheri/ptradd-infinite-combine.ll new file mode 100644 index 0000000000000..468475b6a2ffa --- /dev/null +++ b/llvm/test/CodeGen/RISCV/cheri/ptradd-infinite-combine.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: %riscv64_cheri_purecap_llc -start-before=riscv-isel < %s | FileCheck %s +;; This is a reduced testcase for an infinite combine that was fixed by +;; "[CodeGen] Don't create combine loops for PTRADD with opaque constants" +;; (commit 511c1e0089b4112d4dfbc8b3b093c588aeedb8e9) + +define ptr addrspace(200) @wwv_rf(ptr addrspace(200) %arg) addrspace(200) { +; CHECK-LABEL: wwv_rf: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lui a1, 1 +; CHECK-NEXT: addi a1, a1, -656 +; CHECK-NEXT: addi a1, a1, 112 +; CHECK-NEXT: cincoffset a0, a0, a1 +; CHECK-NEXT: cret +entry: + ; We need an opaque constant here to trigger the infinite loop that keeps + ; changing between (ptradd arg, (add 122, opaque 3440)) and + ; (ptradd (ptradd arg, 122), opaque 3440). Without the opaque constant, + ; the addition would just be folded to 3522. + %const5 = bitcast i64 3440 to i64 + %const_mat = add i64 %const5, 112 + %scevgep2 = getelementptr i8, ptr addrspace(200) %arg, i64 %const_mat + ret ptr addrspace(200) %scevgep2 +}