|
| 1 | +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature |
| 2 | +// RUN: %riscv64_cheri_purecap_cc1 %s -emit-llvm -o - -O0 | FileCheck %s |
| 3 | +/// Test that we set the no_preserve_tags flag for coerced struct return values. |
| 4 | +/// Original test case found building XML_ExpatVersionInfo. |
| 5 | + |
| 6 | +typedef struct { |
| 7 | + int major; |
| 8 | + int minor; |
| 9 | + int micro; |
| 10 | +} XML_Expat_Version; |
| 11 | +// CHECK-LABEL: define {{[^@]+}}@XML_ExpatVersionInfo |
| 12 | +// CHECK-SAME: () addrspace(200) #[[ATTR0:[0-9]+]] { |
| 13 | +// CHECK-NEXT: entry: |
| 14 | +// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200) |
| 15 | +// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200) |
| 16 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)* |
| 17 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 4 bitcast ([[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* @__const.XML_ExpatVersionInfo.ret to i8 addrspace(200)*), i64 12, i1 false) #[[ATTR2:[0-9]+]] |
| 18 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [2 x i64] addrspace(200)* [[RETVAL_COERCE]] to i8 addrspace(200)* |
| 19 | +// CHECK-NEXT: [[TMP2:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)* |
| 20 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 8 [[TMP1]], i8 addrspace(200)* align 4 [[TMP2]], i64 12, i1 false) |
| 21 | +// CHECK-NEXT: [[TMP3:%.*]] = load [2 x i64], [2 x i64] addrspace(200)* [[RETVAL_COERCE]], align 8 |
| 22 | +// CHECK-NEXT: ret [2 x i64] [[TMP3]] |
| 23 | +// |
| 24 | +XML_Expat_Version XML_ExpatVersionInfo(void) { |
| 25 | + XML_Expat_Version ret = {1, 2, 3}; |
| 26 | + return ret; |
| 27 | +} |
| 28 | +// CHECK-LABEL: define {{[^@]+}}@take_XML_ExpatVersionInfo |
| 29 | +// CHECK-SAME: ([2 x i64] [[V_COERCE:%.*]]) addrspace(200) #[[ATTR0]] { |
| 30 | +// CHECK-NEXT: entry: |
| 31 | +// CHECK-NEXT: [[V:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200) |
| 32 | +// CHECK-NEXT: [[TMP_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200) |
| 33 | +// CHECK-NEXT: store [2 x i64] [[V_COERCE]], [2 x i64] addrspace(200)* [[TMP_COERCE]], align 8 |
| 34 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[V]] to i8 addrspace(200)* |
| 35 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [2 x i64] addrspace(200)* [[TMP_COERCE]] to i8 addrspace(200)* |
| 36 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 8 [[TMP1]], i64 12, i1 false) |
| 37 | +// CHECK-NEXT: [[MAJOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[V]], i32 0, i32 0 |
| 38 | +// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32 addrspace(200)* [[MAJOR]], align 4 |
| 39 | +// CHECK-NEXT: ret i32 [[TMP2]] |
| 40 | +// |
| 41 | +int take_XML_ExpatVersionInfo(XML_Expat_Version v) { |
| 42 | + return v.major; |
| 43 | +} |
| 44 | +// CHECK-LABEL: define {{[^@]+}}@pass_XML_ExpatVersionInfo |
| 45 | +// CHECK-SAME: () addrspace(200) #[[ATTR0]] { |
| 46 | +// CHECK-NEXT: entry: |
| 47 | +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200) |
| 48 | +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200) |
| 49 | +// CHECK-NEXT: [[MAJOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 |
| 50 | +// CHECK-NEXT: store i32 1, i32 addrspace(200)* [[MAJOR]], align 4 |
| 51 | +// CHECK-NEXT: [[MINOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1 |
| 52 | +// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[MINOR]], align 4 |
| 53 | +// CHECK-NEXT: [[MICRO:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 2 |
| 54 | +// CHECK-NEXT: store i32 3, i32 addrspace(200)* [[MICRO]], align 4 |
| 55 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [2 x i64] addrspace(200)* [[DOTCOMPOUNDLITERAL_COERCE]] to i8 addrspace(200)* |
| 56 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)* |
| 57 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 8 [[TMP0]], i8 addrspace(200)* align 4 [[TMP1]], i64 12, i1 false) |
| 58 | +// CHECK-NEXT: [[TMP2:%.*]] = load [2 x i64], [2 x i64] addrspace(200)* [[DOTCOMPOUNDLITERAL_COERCE]], align 8 |
| 59 | +// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @take_XML_ExpatVersionInfo([2 x i64] [[TMP2]]) |
| 60 | +// CHECK-NEXT: ret i32 [[CALL]] |
| 61 | +// |
| 62 | +int pass_XML_ExpatVersionInfo(void) { |
| 63 | + return take_XML_ExpatVersionInfo((XML_Expat_Version){1, 2, 3}); |
| 64 | +} |
| 65 | + |
| 66 | +typedef struct { |
| 67 | + int a; |
| 68 | + int b; |
| 69 | +} int_pair; |
| 70 | +// CHECK-LABEL: define {{[^@]+}}@ret_int_pair |
| 71 | +// CHECK-SAME: () addrspace(200) #[[ATTR0]] { |
| 72 | +// CHECK-NEXT: entry: |
| 73 | +// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200) |
| 74 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)* |
| 75 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 4 bitcast ([[STRUCT_INT_PAIR]] addrspace(200)* @__const.ret_int_pair.ret to i8 addrspace(200)*), i64 8, i1 false) #[[ATTR2]] |
| 76 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[RETVAL]] to i64 addrspace(200)* |
| 77 | +// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64 addrspace(200)* [[TMP1]], align 4 |
| 78 | +// CHECK-NEXT: ret i64 [[TMP2]] |
| 79 | +// |
| 80 | +int_pair ret_int_pair(void) { |
| 81 | + int_pair ret = {1, 2}; |
| 82 | + return ret; |
| 83 | +} |
| 84 | +// CHECK-LABEL: define {{[^@]+}}@take_int_pair |
| 85 | +// CHECK-SAME: (i64 [[P_COERCE:%.*]]) addrspace(200) #[[ATTR0]] { |
| 86 | +// CHECK-NEXT: entry: |
| 87 | +// CHECK-NEXT: [[P:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200) |
| 88 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[P]] to i64 addrspace(200)* |
| 89 | +// CHECK-NEXT: store i64 [[P_COERCE]], i64 addrspace(200)* [[TMP0]], align 4 |
| 90 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[P]], i32 0, i32 0 |
| 91 | +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32 addrspace(200)* [[A]], align 4 |
| 92 | +// CHECK-NEXT: ret i32 [[TMP1]] |
| 93 | +// |
| 94 | +int take_int_pair(int_pair p) { |
| 95 | + return p.a; |
| 96 | +} |
| 97 | +// CHECK-LABEL: define {{[^@]+}}@pass_int_pair |
| 98 | +// CHECK-SAME: () addrspace(200) #[[ATTR0]] { |
| 99 | +// CHECK-NEXT: entry: |
| 100 | +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200) |
| 101 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 |
| 102 | +// CHECK-NEXT: store i32 1, i32 addrspace(200)* [[A]], align 4 |
| 103 | +// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1 |
| 104 | +// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[B]], align 4 |
| 105 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i64 addrspace(200)* |
| 106 | +// CHECK-NEXT: [[TMP1:%.*]] = load i64, i64 addrspace(200)* [[TMP0]], align 4 |
| 107 | +// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @take_int_pair(i64 [[TMP1]]) |
| 108 | +// CHECK-NEXT: ret i32 [[CALL]] |
| 109 | +// |
| 110 | +int pass_int_pair(void) { |
| 111 | + return take_int_pair((int_pair){1, 2}); |
| 112 | +} |
| 113 | + |
| 114 | +typedef struct { |
| 115 | + __intcap a; |
| 116 | + int b; |
| 117 | +} cap_int_pair; |
| 118 | +// CHECK-LABEL: define {{[^@]+}}@ret_cap_int_pair |
| 119 | +// CHECK-SAME: ([[STRUCT_CAP_INT_PAIR:%.*]] addrspace(200)* noalias sret([[STRUCT_CAP_INT_PAIR]]) align 16 [[AGG_RESULT:%.*]]) addrspace(200) #[[ATTR0]] { |
| 120 | +// CHECK-NEXT: entry: |
| 121 | +// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8 addrspace(200)*, align 16, addrspace(200) |
| 122 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)* |
| 123 | +// CHECK-NEXT: store i8 addrspace(200)* [[TMP0]], i8 addrspace(200)* addrspace(200)* [[RESULT_PTR]], align 16 |
| 124 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)* |
| 125 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP1]], i8 addrspace(200)* align 16 bitcast ([[STRUCT_CAP_INT_PAIR]] addrspace(200)* @__const.ret_cap_int_pair.ret to i8 addrspace(200)*), i64 32, i1 false) #[[ATTR3:[0-9]+]] |
| 126 | +// CHECK-NEXT: ret void |
| 127 | +// |
| 128 | +cap_int_pair ret_cap_int_pair(void) { |
| 129 | + cap_int_pair ret = {1, 2}; |
| 130 | + return ret; |
| 131 | +} |
| 132 | +// CHECK-LABEL: define {{[^@]+}}@take_cap_int_pair |
| 133 | +// CHECK-SAME: ([[STRUCT_CAP_INT_PAIR:%.*]] addrspace(200)* [[P:%.*]]) addrspace(200) #[[ATTR0]] { |
| 134 | +// CHECK-NEXT: entry: |
| 135 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[P]], i32 0, i32 0 |
| 136 | +// CHECK-NEXT: [[TMP0:%.*]] = load i8 addrspace(200)*, i8 addrspace(200)* addrspace(200)* [[A]], align 16 |
| 137 | +// CHECK-NEXT: ret i8 addrspace(200)* [[TMP0]] |
| 138 | +// |
| 139 | +__intcap take_cap_int_pair(cap_int_pair p) { |
| 140 | + return p.a; |
| 141 | +} |
| 142 | +// CHECK-LABEL: define {{[^@]+}}@pass_cap_int_pair |
| 143 | +// CHECK-SAME: () addrspace(200) #[[ATTR0]] { |
| 144 | +// CHECK-NEXT: entry: |
| 145 | +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_CAP_INT_PAIR:%.*]], align 16, addrspace(200) |
| 146 | +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_CAP_INT_PAIR]], align 16, addrspace(200) |
| 147 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 |
| 148 | +// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1), i8 addrspace(200)* addrspace(200)* [[A]], align 16 |
| 149 | +// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1 |
| 150 | +// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[B]], align 16 |
| 151 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[BYVAL_TEMP]] to i8 addrspace(200)* |
| 152 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)* |
| 153 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP0]], i8 addrspace(200)* align 16 [[TMP1]], i64 32, i1 false) #[[ATTR3]] |
| 154 | +// CHECK-NEXT: [[CALL:%.*]] = call i8 addrspace(200)* @take_cap_int_pair([[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[BYVAL_TEMP]]) |
| 155 | +// CHECK-NEXT: ret i8 addrspace(200)* [[CALL]] |
| 156 | +// |
| 157 | +__intcap pass_cap_int_pair(void) { |
| 158 | + return take_cap_int_pair((cap_int_pair){1, 2}); |
| 159 | +} |
| 160 | + |
| 161 | +typedef struct { |
| 162 | + __intcap a; |
| 163 | + __intcap b; |
| 164 | +} cap_pair; |
| 165 | +// CHECK-LABEL: define {{[^@]+}}@ret_cap_pair |
| 166 | +// CHECK-SAME: ([[STRUCT_CAP_PAIR:%.*]] addrspace(200)* noalias sret([[STRUCT_CAP_PAIR]]) align 16 [[AGG_RESULT:%.*]]) addrspace(200) #[[ATTR0]] { |
| 167 | +// CHECK-NEXT: entry: |
| 168 | +// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8 addrspace(200)*, align 16, addrspace(200) |
| 169 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)* |
| 170 | +// CHECK-NEXT: store i8 addrspace(200)* [[TMP0]], i8 addrspace(200)* addrspace(200)* [[RESULT_PTR]], align 16 |
| 171 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)* |
| 172 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP1]], i8 addrspace(200)* align 16 bitcast ([[STRUCT_CAP_PAIR]] addrspace(200)* @__const.ret_cap_pair.ret to i8 addrspace(200)*), i64 32, i1 false) #[[ATTR3]] |
| 173 | +// CHECK-NEXT: ret void |
| 174 | +// |
| 175 | +cap_pair ret_cap_pair(void) { |
| 176 | + cap_pair ret = {1, 2}; |
| 177 | + return ret; |
| 178 | +} |
| 179 | +// CHECK-LABEL: define {{[^@]+}}@take_cap_pair |
| 180 | +// CHECK-SAME: ([[STRUCT_CAP_PAIR:%.*]] addrspace(200)* [[P:%.*]]) addrspace(200) #[[ATTR0]] { |
| 181 | +// CHECK-NEXT: entry: |
| 182 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[P]], i32 0, i32 0 |
| 183 | +// CHECK-NEXT: [[TMP0:%.*]] = load i8 addrspace(200)*, i8 addrspace(200)* addrspace(200)* [[A]], align 16 |
| 184 | +// CHECK-NEXT: ret i8 addrspace(200)* [[TMP0]] |
| 185 | +// |
| 186 | +__intcap take_cap_pair(cap_pair p) { |
| 187 | + return p.a; |
| 188 | +} |
| 189 | +// CHECK-LABEL: define {{[^@]+}}@pass_cap_pair |
| 190 | +// CHECK-SAME: () addrspace(200) #[[ATTR0]] { |
| 191 | +// CHECK-NEXT: entry: |
| 192 | +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_CAP_PAIR:%.*]], align 16, addrspace(200) |
| 193 | +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_CAP_PAIR]], align 16, addrspace(200) |
| 194 | +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 |
| 195 | +// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1), i8 addrspace(200)* addrspace(200)* [[A]], align 16 |
| 196 | +// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1 |
| 197 | +// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 2), i8 addrspace(200)* addrspace(200)* [[B]], align 16 |
| 198 | +// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[BYVAL_TEMP]] to i8 addrspace(200)* |
| 199 | +// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)* |
| 200 | +// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP0]], i8 addrspace(200)* align 16 [[TMP1]], i64 32, i1 false) #[[ATTR3]] |
| 201 | +// CHECK-NEXT: [[CALL:%.*]] = call i8 addrspace(200)* @take_cap_pair([[STRUCT_CAP_PAIR]] addrspace(200)* [[BYVAL_TEMP]]) |
| 202 | +// CHECK-NEXT: ret i8 addrspace(200)* [[CALL]] |
| 203 | +// |
| 204 | +__intcap pass_cap_pair(void) { |
| 205 | + return take_cap_pair((cap_pair){1, 2}); |
| 206 | +} |
| 207 | + |
| 208 | +// UTC_ARGS: --disable |
| 209 | +// CHECK: attributes #[[ATTR2]] = { no_preserve_cheri_tags } |
| 210 | +// CHECK: attributes #[[ATTR3]] = { must_preserve_cheri_tags } |
0 commit comments