249 lines · c
1// RUN: %clang_cc1 -fms-extensions -triple x86_64-windows-msvc %s -emit-llvm -o - | FileCheck %s --check-prefix=X642// RUN: %clang_cc1 -fms-extensions -triple thumbv7-windows-msvc %s -emit-llvm -o - | FileCheck %s --check-prefix=ARM3// RUN: %clang_cc1 -fms-extensions -triple aarch64-windows-msvc %s -emit-llvm -o - | FileCheck %s --check-prefix=ARM64 -check-prefix=ARM4 5volatile unsigned char sink = 0;6void test32(long *base, long idx) {7 sink = _bittest(base, idx);8 sink = _bittestandcomplement(base, idx);9 sink = _bittestandreset(base, idx);10 sink = _bittestandset(base, idx);11 sink = _interlockedbittestandreset(base, idx);12 sink = _interlockedbittestandset(base, idx);13}14 15void test64(__int64 *base, __int64 idx) {16 sink = _bittest64(base, idx);17 sink = _bittestandcomplement64(base, idx);18 sink = _bittestandreset64(base, idx);19 sink = _bittestandset64(base, idx);20 sink = _interlockedbittestandreset64(base, idx);21 sink = _interlockedbittestandset64(base, idx);22}23 24#if defined(_M_ARM) || defined(_M_ARM64)25void test_arm(long *base, long idx) {26 sink = _interlockedbittestandreset_acq(base, idx);27 sink = _interlockedbittestandreset_rel(base, idx);28 sink = _interlockedbittestandreset_nf(base, idx);29 sink = _interlockedbittestandset_acq(base, idx);30 sink = _interlockedbittestandset_rel(base, idx);31 sink = _interlockedbittestandset_nf(base, idx);32}33#endif34 35#if defined(_M_ARM64)36void test_arm64(__int64 *base, __int64 idx) {37 sink = _interlockedbittestandreset64_acq(base, idx);38 sink = _interlockedbittestandreset64_rel(base, idx);39 sink = _interlockedbittestandreset64_nf(base, idx);40 sink = _interlockedbittestandset64_acq(base, idx);41 sink = _interlockedbittestandset64_rel(base, idx);42 sink = _interlockedbittestandset64_nf(base, idx);43}44#endif45 46// X64-LABEL: define dso_local void @test32(ptr noundef %base, i32 noundef %idx)47// X64: call i8 asm sideeffect "btl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})48// X64: call i8 asm sideeffect "btcl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})49// X64: call i8 asm sideeffect "btrl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})50// X64: call i8 asm sideeffect "btsl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})51// X64: call i8 asm sideeffect "lock btrl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})52// X64: call i8 asm sideeffect "lock btsl $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i32 {{.*}})53 54// X64-LABEL: define dso_local void @test64(ptr noundef %base, i64 noundef %idx)55// X64: call i8 asm sideeffect "btq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})56// X64: call i8 asm sideeffect "btcq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})57// X64: call i8 asm sideeffect "btrq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})58// X64: call i8 asm sideeffect "btsq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})59// X64: call i8 asm sideeffect "lock btrq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})60// X64: call i8 asm sideeffect "lock btsq $2, ($1)", "={@ccc},r,r,~{cc},~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %{{.*}}, i64 {{.*}})61 62// ARM-LABEL: define dso_local {{.*}}void @test32(ptr noundef %base, i32 noundef %idx)63// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 364// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]65// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i866// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 767// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 168// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]69// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 170// ARM: store volatile i8 %[[RES]], ptr @sink, align 171 72// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 373// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]74// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i875// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 776// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]77// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 178// ARM: %[[NEWBYTE:[^ ]*]] = xor i8 %[[BYTE]], %[[MASK]]79// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 180// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]81// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 182// ARM: store volatile i8 %[[RES]], ptr @sink, align 183 84// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 385// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]86// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i887// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 788// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]89// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 190// ARM: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -191// ARM: %[[NEWBYTE:[^ ]*]] = and i8 %[[BYTE]], %[[NOTMASK]]92// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 193// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]94// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 195// ARM: store volatile i8 %[[RES]], ptr @sink, align 196 97// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 398// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]99// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i8100// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7101// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]102// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 1103// ARM: %[[NEWBYTE:[^ ]*]] = or i8 %[[BYTE]], %[[MASK]]104// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 1105// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]106// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1107// ARM: store volatile i8 %[[RES]], ptr @sink, align 1108 109// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 3110// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]111// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i8112// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7113// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]114// ARM: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -1115// ARM: %[[BYTE:[^ ]*]] = atomicrmw and ptr %[[BYTEADDR]], i8 %[[NOTMASK]] seq_cst, align 1116// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]117// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1118// ARM: store volatile i8 %[[RES]], ptr @sink, align 1119 120// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 3121// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]122// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i8123// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7124// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]125// ARM: %[[BYTE:[^ ]*]] = atomicrmw or ptr %[[BYTEADDR]], i8 %[[MASK]] seq_cst, align 1126// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]127// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1128// ARM: store volatile i8 %[[RES]], ptr @sink, align 1129 130// ARM-LABEL: define dso_local {{.*}}void @test64(ptr noundef %base, i64 noundef %idx)131// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3132// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]133// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8134// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7135// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 1136// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]137// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1138// ARM: store volatile i8 %[[RES]], ptr @sink, align 1139 140// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3141// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]142// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8143// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7144// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]145// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 1146// ARM: %[[NEWBYTE:[^ ]*]] = xor i8 %[[BYTE]], %[[MASK]]147// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 1148// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]149// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1150// ARM: store volatile i8 %[[RES]], ptr @sink, align 1151 152// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3153// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]154// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8155// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7156// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]157// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 1158// ARM: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -1159// ARM: %[[NEWBYTE:[^ ]*]] = and i8 %[[BYTE]], %[[NOTMASK]]160// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 1161// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]162// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1163// ARM: store volatile i8 %[[RES]], ptr @sink, align 1164 165// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3166// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]167// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8168// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7169// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]170// ARM: %[[BYTE:[^ ]*]] = load i8, ptr %[[BYTEADDR]], align 1171// ARM: %[[NEWBYTE:[^ ]*]] = or i8 %[[BYTE]], %[[MASK]]172// ARM: store i8 %[[NEWBYTE]], ptr %[[BYTEADDR]], align 1173// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]174// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1175// ARM: store volatile i8 %[[RES]], ptr @sink, align 1176 177// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3178// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]179// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8180// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7181// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]182// ARM: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -1183// ARM: %[[BYTE:[^ ]*]] = atomicrmw and ptr %[[BYTEADDR]], i8 %[[NOTMASK]] seq_cst, align 1184// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]185// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1186// ARM: store volatile i8 %[[RES]], ptr @sink, align 1187 188// ARM: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3189// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]190// ARM: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8191// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7192// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]193// ARM: %[[BYTE:[^ ]*]] = atomicrmw or ptr %[[BYTEADDR]], i8 %[[MASK]] seq_cst, align 1194// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]195// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1196// ARM: store volatile i8 %[[RES]], ptr @sink, align 1197 198// ARM-LABEL: define dso_local {{.*}}void @test_arm(ptr noundef %base, i32 noundef %idx)199// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 3200// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]201// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i8202// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7203// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]204// ARM: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -1205// ARM: %[[BYTE:[^ ]*]] = atomicrmw and ptr %[[BYTEADDR]], i8 %[[NOTMASK]] acquire, align 1206// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]207// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1208// ARM: store volatile i8 %[[RES]], ptr @sink, align 1209// Just look for the atomicrmw instructions.210// ARM: atomicrmw and ptr %{{.*}}, i8 {{.*}} release, align 1211// ARM: atomicrmw and ptr %{{.*}}, i8 {{.*}} monotonic, align 1212// ARM: %[[IDXHI:[^ ]*]] = ashr i32 %{{.*}}, 3213// ARM: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[IDXHI]]214// ARM: %[[IDX8:[^ ]*]] = trunc i32 %{{.*}} to i8215// ARM: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7216// ARM: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]217// ARM: %[[BYTE:[^ ]*]] = atomicrmw or ptr %[[BYTEADDR]], i8 %[[MASK]] acquire, align 1218// ARM: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]219// ARM: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1220// ARM: store volatile i8 %[[RES]], ptr @sink, align 1221// Just look for the atomicrmw instructions.222// ARM: atomicrmw or ptr %{{.*}}, i8 {{.*}} release, align 1223// ARM: atomicrmw or ptr %{{.*}}, i8 {{.*}} monotonic, align 1224 225// ARM64-LABEL: define dso_local void @test_arm64(ptr noundef %base, i64 noundef %idx)226// ARM64: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3227// ARM64: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]228// ARM64: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8229// ARM64: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7230// ARM64: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]231// ARM64: %[[NOTMASK:[^ ]*]] = xor i8 %[[MASK]], -1232// ARM64: %[[BYTE:[^ ]*]] = atomicrmw and ptr %[[BYTEADDR]], i8 %[[NOTMASK]] acquire, align 1233// ARM64: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]234// ARM64: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1235// ARM64: store volatile i8 %[[RES]], ptr @sink, align 1236// ARM64: atomicrmw and ptr %{{.*}}, i8 {{.*}} release, align 1237// ARM64: atomicrmw and ptr %{{.*}}, i8 {{.*}} monotonic, align 1238// ARM64: %[[IDXHI:[^ ]*]] = ashr i64 %{{.*}}, 3239// ARM64: %[[BYTEADDR:[^ ]*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 %[[IDXHI]]240// ARM64: %[[IDX8:[^ ]*]] = trunc i64 %{{.*}} to i8241// ARM64: %[[IDXLO:[^ ]*]] = and i8 %[[IDX8]], 7242// ARM64: %[[MASK:[^ ]*]] = shl i8 1, %[[IDXLO]]243// ARM64: %[[BYTE:[^ ]*]] = atomicrmw or ptr %[[BYTEADDR]], i8 %[[MASK]] acquire, align 1244// ARM64: %[[BYTESHR:[^ ]*]] = lshr i8 %[[BYTE]], %[[IDXLO]]245// ARM64: %[[RES:[^ ]*]] = and i8 %[[BYTESHR]], 1246// ARM64: store volatile i8 %[[RES]], ptr @sink, align 1247// ARM64: atomicrmw or ptr %{{.*}}, i8 {{.*}} release, align 1248// ARM64: atomicrmw or ptr %{{.*}}, i8 {{.*}} monotonic, align 1249