Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -426,7 +426,7 @@ InGroup>; def warn_drv_fine_grained_bitfield_accesses_ignored : Warning< - "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">, + "option '-ffine-grained-bitfield-accesses' cannot be enabled together with thread sanitizer; flag ignored">, InGroup; def note_drv_verify_prefix_spelling : Note< Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -3477,9 +3477,11 @@ if (T.isSPIR()) Res.getDiagnosticOpts().Warnings.push_back("spir-compat"); - // If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses. + // If thread sanitizer is enabled, disable + // OPT_ffine_grained_bitfield_accesses because it will cripple the ability + // of Tsan to find race conditions between accesses to consecutive bitfields. if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses && - !Res.getLangOpts()->Sanitize.empty()) { + LangOpts.Sanitize.has(SanitizerKind::Thread)) { Res.getCodeGenOpts().FineGrainedBitfieldAccesses = false; Diags.Report(diag::warn_drv_fine_grained_bitfield_accesses_ignored); } Index: test/CodeGenCXX/finegrain-bitfield-access.cpp =================================================================== --- test/CodeGenCXX/finegrain-bitfield-access.cpp +++ test/CodeGenCXX/finegrain-bitfield-access.cpp @@ -1,8 +1,13 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \ // RUN: -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \ -// RUN: -emit-llvm -fsanitize=address -o - %s | FileCheck %s --check-prefix=SANITIZE -// Check -fsplit-bitfields will be ignored since sanitizer is enabled. +// RUN: -emit-llvm -fsanitize=address -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \ +// RUN: -emit-llvm -fsanitize=thread -o - %s | FileCheck %s \ +// RUN: --check-prefix=SANITIZE-THREAD + +// Check -ffine-grained-bitfield-accesses will be ignored if thread sanitizer +// is enabled. struct S1 { unsigned f1:2; @@ -15,56 +20,56 @@ S1 a1; unsigned read8_1() { // CHECK-LABEL: @_Z7read8_1v - // CHECK: %bf.load = load i8, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1 - // CHECK-NEXT: %bf.cast = zext i8 %bf.load to i32 - // CHECK-NEXT: ret i32 %bf.cast - // SANITIZE-LABEL: @_Z7read8_1v - // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE: %bf.lshr = lshr i32 %bf.load, 8 - // SANITIZE: %bf.clear = and i32 %bf.lshr, 255 - // SANITIZE: ret i32 %bf.clear + // CHECK: %bf.load = load i8, i8* getelementptr inbounds {{.*}}, align 1 + // CHECK: %bf.cast = zext i8 %bf.load to i32 + // CHECK: ret i32 %bf.cast + // SANITIZE-THREAD-LABEL: @_Z7read8_1v + // SANITIZE-THREAD: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: %bf.lshr = lshr i32 %bf.load, 8 + // SANITIZE-THREAD: %bf.clear = and i32 %bf.lshr, 255 + // SANITIZE-THREAD: ret i32 %bf.clear return a1.f3; } void write8_1() { // CHECK-LABEL: @_Z8write8_1v - // CHECK: store i8 3, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1 - // CHECK-NEXT: ret void - // SANITIZE-LABEL: @_Z8write8_1v - // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -65281 - // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 768 - // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE-NEXT: ret void + // CHECK: store i8 3, i8* getelementptr inbounds {{.*}}, align 1 + // CHECK: ret void + // SANITIZE-THREAD-LABEL: @_Z8write8_1v + // SANITIZE-THREAD: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: %bf.clear = and i32 %bf.load, -65281 + // SANITIZE-THREAD: %bf.set = or i32 %bf.clear, 768 + // SANITIZE-THREAD: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: ret void a1.f3 = 3; } unsigned read8_2() { // CHECK-LABEL: @_Z7read8_2v - // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 - // CHECK-NEXT: %bf.lshr = lshr i16 %bf.load, 4 - // CHECK-NEXT: %bf.clear = and i16 %bf.lshr, 255 - // CHECK-NEXT: %bf.cast = zext i16 %bf.clear to i32 - // CHECK-NEXT: ret i32 %bf.cast - // SANITIZE-LABEL: @_Z7read8_2v - // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE-NEXT: %bf.lshr = lshr i32 %bf.load, 20 - // SANITIZE-NEXT: %bf.clear = and i32 %bf.lshr, 255 - // SANITIZE-NEXT: ret i32 %bf.clear + // CHECK: %bf.load = load i16, i16* getelementptr inbounds {{.*}}, align 2 + // CHECK: %bf.lshr = lshr i16 %bf.load, 4 + // CHECK: %bf.clear = and i16 %bf.lshr, 255 + // CHECK: %bf.cast = zext i16 %bf.clear to i32 + // CHECK: ret i32 %bf.cast + // SANITIZE-THREAD-LABEL: @_Z7read8_2v + // SANITIZE-THREAD: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: %bf.lshr = lshr i32 %bf.load, 20 + // SANITIZE-THREAD: %bf.clear = and i32 %bf.lshr, 255 + // SANITIZE-THREAD: ret i32 %bf.clear return a1.f5; } void write8_2() { // CHECK-LABEL: @_Z8write8_2v - // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 - // CHECK-NEXT: %bf.clear = and i16 %bf.load, -4081 - // CHECK-NEXT: %bf.set = or i16 %bf.clear, 48 - // CHECK-NEXT: store i16 %bf.set, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2 - // CHECK-NEXT: ret void - // SANITIZE-LABEL: @_Z8write8_2v - // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -267386881 - // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 3145728 - // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 - // SANITIZE-NEXT: ret void + // CHECK: %bf.load = load i16, i16* getelementptr inbounds {{.*}}, align 2 + // CHECK: %bf.clear = and i16 %bf.load, -4081 + // CHECK: %bf.set = or i16 %bf.clear, 48 + // CHECK: store i16 %bf.set, i16* getelementptr inbounds {{.*}}, align 2 + // CHECK: ret void + // SANITIZE-THREAD-LABEL: @_Z8write8_2v + // SANITIZE-THREAD: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: %bf.clear = and i32 %bf.load, -267386881 + // SANITIZE-THREAD: %bf.set = or i32 %bf.clear, 3145728 + // SANITIZE-THREAD: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4 + // SANITIZE-THREAD: ret void a1.f5 = 3; } @@ -77,54 +82,54 @@ S2 a2; unsigned read16_1() { // CHECK-LABEL: @_Z8read16_1v - // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8 - // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64 - // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 - // CHECK-NEXT: ret i32 %conv - // SANITIZE-LABEL: @_Z8read16_1v - // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 65535 - // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32 - // SANITIZE-NEXT: ret i32 %conv + // CHECK: %bf.load = load i16, i16* getelementptr inbounds {{.*}}, align 8 + // CHECK: %bf.cast = zext i16 %bf.load to i64 + // CHECK: %conv = trunc i64 %bf.cast to i32 + // CHECK: ret i32 %conv + // SANITIZE-THREAD-LABEL: @_Z8read16_1v + // SANITIZE-THREAD: %bf.load = load i64, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: %bf.clear = and i64 %bf.load, 65535 + // SANITIZE-THREAD: %conv = trunc i64 %bf.clear to i32 + // SANITIZE-THREAD: ret i32 %conv return a2.f1; } unsigned read16_2() { // CHECK-LABEL: @_Z8read16_2v - // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2 - // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64 - // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 - // CHECK-NEXT: ret i32 %conv - // SANITIZE-LABEL: @_Z8read16_2v - // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 16 - // SANITIZE-NEXT: %bf.clear = and i64 %bf.lshr, 65535 - // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32 - // SANITIZE-NEXT: ret i32 %conv + // CHECK: %bf.load = load i16, i16* getelementptr inbounds {{.*}}, align 2 + // CHECK: %bf.cast = zext i16 %bf.load to i64 + // CHECK: %conv = trunc i64 %bf.cast to i32 + // CHECK: ret i32 %conv + // SANITIZE-THREAD-LABEL: @_Z8read16_2v + // SANITIZE-THREAD: %bf.load = load i64, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: %bf.lshr = lshr i64 %bf.load, 16 + // SANITIZE-THREAD: %bf.clear = and i64 %bf.lshr, 65535 + // SANITIZE-THREAD: %conv = trunc i64 %bf.clear to i32 + // SANITIZE-THREAD: ret i32 %conv return a2.f2; } void write16_1() { // CHECK-LABEL: @_Z9write16_1v - // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8 - // CHECK-NEXT: ret void - // SANITIZE-LABEL: @_Z9write16_1v - // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -65536 - // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 5 - // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: ret void + // CHECK: store i16 5, i16* getelementptr inbounds {{.*}}, align 8 + // CHECK: ret void + // SANITIZE-THREAD-LABEL: @_Z9write16_1v + // SANITIZE-THREAD: %bf.load = load i64, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: %bf.clear = and i64 %bf.load, -65536 + // SANITIZE-THREAD: %bf.set = or i64 %bf.clear, 5 + // SANITIZE-THREAD: store i64 %bf.set, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: ret void a2.f1 = 5; } void write16_2() { // CHECK-LABEL: @_Z9write16_2v - // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2 - // CHECK-NEXT: ret void - // SANITIZE-LABEL: @_Z9write16_2v - // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -4294901761 - // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 327680 - // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8 - // SANITIZE-NEXT: ret void + // CHECK: store i16 5, i16* getelementptr inbounds {{.*}}, align 2 + // CHECK: ret void + // SANITIZE-THREAD-LABEL: @_Z9write16_2v + // SANITIZE-THREAD: %bf.load = load i64, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: %bf.clear = and i64 %bf.load, -4294901761 + // SANITIZE-THREAD: %bf.set = or i64 %bf.clear, 327680 + // SANITIZE-THREAD: store i64 %bf.set, i64* bitcast {{.*}}, align 8 + // SANITIZE-THREAD: ret void a2.f2 = 5; } @@ -137,26 +142,26 @@ S3 a3; unsigned read32_1() { // CHECK-LABEL: @_Z8read32_1v - // CHECK: %bf.load = load i32, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4 - // CHECK-NEXT: %bf.cast = zext i32 %bf.load to i64 - // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32 - // CHECK-NEXT: ret i32 %conv - // SANITIZE-LABEL: @_Z8read32_1v - // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 - // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 32 - // SANITIZE-NEXT: %conv = trunc i64 %bf.lshr to i32 - // SANITIZE-NEXT: ret i32 %conv + // CHECK: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4 + // CHECK: %bf.cast = zext i32 %bf.load to i64 + // CHECK: %conv = trunc i64 %bf.cast to i32 + // CHECK: ret i32 %conv + // SANITIZE-THREAD-LABEL: @_Z8read32_1v + // SANITIZE-THREAD: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 + // SANITIZE-THREAD: %bf.lshr = lshr i64 %bf.load, 32 + // SANITIZE-THREAD: %conv = trunc i64 %bf.lshr to i32 + // SANITIZE-THREAD: ret i32 %conv return a3.f3; } void write32_1() { // CHECK-LABEL: @_Z9write32_1v - // CHECK: store i32 5, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4 - // CHECK-NEXT: ret void - // SANITIZE-LABEL: @_Z9write32_1v - // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 - // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 4294967295 - // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 21474836480 - // SANITIZE-NEXT: store i64 %bf.set, i64* getelementptr inbounds {{.*}}, align 8 - // SANITIZE-NEXT: ret void + // CHECK: store i32 5, i32* getelementptr inbounds {{.*}}, align 4 + // CHECK: ret void + // SANITIZE-THREAD-LABEL: @_Z9write32_1v + // SANITIZE-THREAD: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8 + // SANITIZE-THREAD: %bf.clear = and i64 %bf.load, 4294967295 + // SANITIZE-THREAD: %bf.set = or i64 %bf.clear, 21474836480 + // SANITIZE-THREAD: store i64 %bf.set, i64* getelementptr inbounds {{.*}}, align 8 + // SANITIZE-THREAD: ret void a3.f3 = 5; }