diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -12,6 +12,7 @@ stdarg.h stdatomic.h stdbool.h + stdckdint.h stddef.h __stddef_max_align_t.h stdint.h diff --git a/clang/lib/Headers/stdckdint.h b/clang/lib/Headers/stdckdint.h new file mode 100644 --- /dev/null +++ b/clang/lib/Headers/stdckdint.h @@ -0,0 +1,22 @@ +/*===---- stdckdint.h - Standard header for checking integer + *-------------------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __STDCKDINT_H +#define __STDCKDINT_H + +#if defined(__GNUC__) +#define ckd_add(R, A, B) __builtin_add_overflow((A), (B), (R)) +#define ckd_sub(R, A, B) __builtin_sub_overflow((A), (B), (R)) +#define ckd_mul(R, A, B) __builtin_mul_overflow((A), (B), (R)) +#else +#error "we need a compiler extension for this" +#endif + +#endif /* __STDCKDINT_H */ \ No newline at end of file diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -384,6 +384,7 @@ .Case("stdarg.h", true) .Case("stdatomic.h", true) .Case("stdbool.h", true) + .Case("stdckdint.h", true) .Case("stddef.h", true) .Case("stdint.h", true) .Case("tgmath.h", true) diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -207,7 +207,7 @@ .Cases("assert.h", "complex.h", "ctype.h", "errno.h", "fenv.h", true) .Cases("float.h", "inttypes.h", "iso646.h", "limits.h", "locale.h", true) .Cases("math.h", "setjmp.h", "signal.h", "stdalign.h", "stdarg.h", true) - .Cases("stdatomic.h", "stdbool.h", "stddef.h", "stdint.h", "stdio.h", true) + .Cases("stdatomic.h", "stdbool.h", "stdckdint.h", "stddef.h", "stdint.h", "stdio.h", true) .Cases("stdlib.h", "stdnoreturn.h", "string.h", "tgmath.h", "threads.h", true) .Cases("time.h", "uchar.h", "wchar.h", "wctype.h", true) diff --git a/clang/test/Headers/stdckdint.cpp b/clang/test/Headers/stdckdint.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Headers/stdckdint.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -emit-llvm -fgnuc-version=4.2.1 -std=gnu++11 %s -o - | FileCheck --check-prefix=CHECK-NEXT %s + + +#include +// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_add() #0 { +// CHECK-NEXT: entry: +// CHECK-NEXT: %0 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 -1073741826, i32 -1073741826) +// CHECK-NEXT: %1 = extractvalue { i32, i1 } %0, 1 +// CHECK-NEXT: store i32 %2, ptr %result, align 4 +// CHECK-NEXT: ret i1 %1 +// CHECK-NEXT: } +// CHECK-NEXT: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +// CHECK-NEXT: declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1 +bool test_ckd_add() { + int result; + return ckd_add(&result, -1073741826, -1073741826); +} + +// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_sub() #0 { +// CHECK-NEXT: entry: +// CHECK-NEXT: %0 = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 -1073741826, i32 1073741826) +// CHECK-NEXT: %1 = extractvalue { i32, i1 } %0, 1 +// CHECK-NEXT: store i32 %2, ptr %result, align 4 +// CHECK-NEXT: ret i1 %1 +// CHECK-NEXT: } +// CHECK-NEXT: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +// CHECK-NEXT: declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) #1 +bool test_ckd_sub() { + int result; + return ckd_sub(&result, -1073741826, 1073741826); +} + +// CHECK-LABEL: define dso_local zeroext i1 @test_ckd_mul() #0 { +// CHECK-NEXT: entry: +// CHECK-NEXT: %0 = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 -1073741826, i32 2) +// CHECK-NEXT: %1 = extractvalue { i32, i1 } %0, 1 +// CHECK-NEXT: store i32 %2, ptr %result, align 4 +// CHECK-NEXT: ret i1 %1 +// CHECK-NEXT: } +// CHECK-NEXT: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +// CHECK-NEXT: declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) #1 +bool test_ckd_mul() { + int result; + return ckd_mul(&result, -1073741826, 2); +} diff --git a/clang/test/Modules/Inputs/System/usr/include/module.map b/clang/test/Modules/Inputs/System/usr/include/module.map --- a/clang/test/Modules/Inputs/System/usr/include/module.map +++ b/clang/test/Modules/Inputs/System/usr/include/module.map @@ -14,6 +14,11 @@ header "stdbool.h" } + // In both directories (compiler support version wins, does not forward) + module stdckdint { + header "stdckdint.h" + } + // In both directories (compiler support version wins, forwards) module stdint { header "stdint.h"